$!.............................................................................
$! VAX/VMS archive file created by VMS_SHARE V06.00 26-May-1988.
$!
$! VMS_SHARE was written by James Gray (Gray:OSBUSouth@Xerox.COM) from
$! VMS_SHAR by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au).
$!
$! To unpack, simply save, concatinate all parts into one file and
$! execute (@) that file.
$!
$! This archive was created by user KVC
$! on 14-OCT-1864 22:00:33.11.
$!
$! ATTENTION: To keep each article below 62 blocks (31744 bytes), this
$!            program has been transmitted in 5 parts.  You should
$!            concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 9 files:
$!        000_README.TXT
$!        BUILD.COM
$!        DRIVER.OPT
$!        NOTES.TXT
$!        PTY.PAS
$!        PTY_DOC.TXT
$!        PTY_EXAMPLE.C
$!        PYDRIVER.MAR
$!        TWDRIVER.MAR
$!
$!==============================================================================
$ SET SYMBOL/SCOPE=( NOLOCAL, NOGLOBAL )
$ VERSION = F$GETSYI( "VERSION" )
$ IF VERSION .GES "V4.4" THEN GOTO VERSION_OK
$ WRITE SYS$OUTPUT "You are running VMS ''VERSION'; ", -
    "VMS_SHARE V06.00 26-May-1988 requires VMS V4.4 or higher."
$ EXIT 44 
$VERSION_OK:
$ GOTO START
$
$UNPACK_FILE:
$ WRITE SYS$OUTPUT "Creating ''FILE_IS'"
$ DEFINE/USER_MODE SYS$OUTPUT NL:
$ EDIT/TPU/COMMAND=SYS$INPUT/NODISPLAY/OUTPUT='FILE_IS'/NOSECTION -
    VMS_SHARE_DUMMY.DUMMY
b_part := CREATE_BUFFER( "{Part}", GET_INFO( COMMAND_LINE, "file_name" ) )
; s_file_spec := GET_INFO( COMMAND_LINE, "output_file" ); SET( OUTPUT_FILE
, b_part, s_file_spec ); b_errors := CREATE_BUFFER( "{Errors}" ); i_errors := 0
; pat_beg_1 := ANCHOR & "-+-+-+ Beginning"; pat_beg_2 := LINE_BEGIN 
& "+-+-+-+ Beginning"; pat_end := ANCHOR & "+-+-+-+-+ End"; POSITION
( BEGINNING_OF( b_part ) ); i_append_line := 0; LOOP EXITIF MARK( NONE 
) = END_OF( b_part ); s_x := ERASE_CHARACTER( 1 ); IF s_x = "+" THEN r_skip 
:= SEARCH( pat_beg_1, FORWARD, EXACT ); IF r_skip <> 0 THEN s_x := ""
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ERASE_LINE; ENDIF; ENDIF
; IF s_x = "-" THEN r_skip := SEARCH( pat_end, FORWARD, EXACT ); IF r_skip <
> 0 THEN s_x := ""; MOVE_HORIZONTAL( -CURRENT_OFFSET ); m_skip := MARK( NONE )
; r_skip := SEARCH( pat_beg_2, FORWARD, EXACT ); IF r_skip <> 0 THEN POSITION
( END_OF( r_skip ) ); MOVE_HORIZONTAL( -CURRENT_OFFSET ); MOVE_VERTICAL( 1 )
; MOVE_HORIZONTAL( -1 ); ELSE POSITION( END_OF( b_part ) ); ENDIF; ERASE
( CREATE_RANGE( m_skip, MARK( NONE ), NONE ) ); ENDIF; ENDIF
; IF s_x = "V" THEN s_x := ""; IF i_append_line <> 0 THEN APPEND_LINE
; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line := 1; MOVE_VERTICAL
( 1 ); ENDIF; IF s_x = "X" THEN s_x := ""; IF i_append_line <
> 0 THEN APPEND_LINE; MOVE_HORIZONTAL( -CURRENT_OFFSET ); ENDIF; i_append_line 
:= 0; MOVE_VERTICAL( 1 ); ENDIF; IF s_x <> "" THEN i_errors := i_errors + 1
; s_text := CURRENT_LINE; POSITION( b_errors ); COPY_TEXT
( "The following line could not be unpacked properly:" ); SPLIT_LINE; COPY_TEXT
( s_x ); COPY_TEXT( s_text ); POSITION( b_part ); MOVE_VERTICAL( 1 ); ENDIF
; ENDLOOP; POSITION( BEGINNING_OF( b_part ) ); LOOP r_x := SEARCH( "`", FORWARD
, EXACT ); EXITIF r_x = 0; POSITION( r_x ); ERASE_CHARACTER( 1 )
; IF CURRENT_CHARACTER = "`" THEN MOVE_HORIZONTAL( 1 ); ELSE COPY_TEXT( ASCII
( INT( ERASE_CHARACTER( 3 ) ) ) ); ENDIF; ENDLOOP; IF i_errors = 0 THEN SET
( NO_WRITE, b_errors, ON ); ELSE POSITION( BEGINNING_OF( b_errors ) )
; COPY_TEXT( FAO( "The following !UL errors were detected while unpacking !AS"
, i_errors, s_file_spec ) ); SPLIT_LINE; SET( OUTPUT_FILE, b_errors
, "SYS$COMMAND" ); ENDIF; EXIT; 
$ DELETE VMS_SHARE_DUMMY.DUMMY;*
$ CHECKSUM 'FILE_IS
$ WRITE SYS$OUTPUT " CHECKSUM ", -
  F$ELEMENT( CHECKSUM_IS .EQ. CHECKSUM$CHECKSUM, ",", "failed!,passed." )
$ RETURN
$
$START:
$ FILE_IS = "000_README.TXT"
$ CHECKSUM_IS = 1903303373
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
XThese files make up a pseudo terminal driver for VAX/VMS. This driver was
Xoriginally developed at Carnegie-Mellon University and has made the
Xrounds before as the CMU PTY driver.  I picked up the driver just after
Xit had been migrated from V3 to V4, made a lot of improvements, and have
Xbeen redistributing it ever since.
X
XThis driver runs under VMS V4 and V5.  It will not work under any VMS
Xprior to V4.  It has been minimally tested by me on V4.7 and V5.0.  It
Xshould work on earlier V4 point releases as well, but I haven't tried it.
X
XNote that during assembly the driver will detect the version of VMS and
Xbuild the proper variant.  You do not need to modify the sources for V4
Xof V5.
X
XSee PTY_DOC.TXT for documentation and NOTES.TXT for my additional comments
Xand observations.
X
XChanges for version 05-006A (PYDRIVER) and 05-004A (TWDRIVER) include:
X
X  o  Support for VMS V5 including Symmetric Multiprocessing environments.
X     Conditional assembly of the drivers will produce V4 or V5
X     compatible drivers.  This also includes changes to the PY$FDTWRITE
X     routine to be smarter about grabbing and releasing the device
X     (device IPL in V5, device lock in V5).  It used to raise and
X     lower IPL quite a lot, but this is expensive when converted to
X     lock/unlock for SMP.
X
X  o  The port control MULTISESSION bit is now set by the driver, causing
X     terminal sessions on TW devices to NOT count against your license
X     limit.  This is good for programs like PHOTO, but not so good
X     for network logins.  This really should be made settable by the
X     application controlling the PY device.
X
X  o  Writes to the PY device will now return SS$_DATAOVERUN if the TW
X     signals XOFF.  In the case of DATA OVER-RUN the bytecount field in
X     the IOSB is the number of characters actually delivered. Note that
X     if the last character causes XOFF you will receive SS$_DATAOVERUN
X     instead of SS$_NORMAL.  Applications should check for SS$_DATAOVERUN
X     in the IOSB after a write to the PY device and keep track of how
X     many characters remain to be delivered later.  You probably want to
X     use the new flow-control AST mechanism, described below, in
X     conjunction with this so you know when to continue delivering data
X     to the PY device.
X
X  o  There is now a SETMODE and SETCHAR function that allows you to
X     enable three new ASTs.  It does not take any function modifiers and
X     only sets the specified ASTs.  The QIO parameters are:
X
X`009`009P1 - ASTADDR
X`009`009P2 - ASTPARAM (16 bits only on TW$XON or TW$XOFF)
X`009`009P3 - ACCESS MODE to deliver AST in -- usual rules
X`009`009P4 - AST to deliver -- legal values are
X`009`009`0091 - Deliver AST when TW$XON is called.  When the
X`009`009`009    AST is delivered the low order word of
X`009`009`009    ASTPARAM will be the character supplied to
X`009`009`009    TW$XON to send.  The high order word will
X`009`009`009    be your ASTPARAM.
X`009`009`0092 - Deliver AST when TW$XOFF is called.  When the
X`009`009`009    AST is delivered the low order word of
X`009`009`009    ASTPARAM will be the character supplied to
X`009`009`009    TW$XOFF to send.  The high order word will
X`009`009`009    be your ASTPARAM.
X`009`009`0093 - Deliver AST when TW$SET_LINE is called.
X
X  o  The TW device now defaults to HOSTSYNC.  This may be disabled
X     with a SET TERM DCL command or the proper SETMODE or SETCHAR
X     QIO to the TW device.  The TW device is always set NOMODEM and
X     will not allow MODEM to be set.
X
X  o  The PY device now accepts a SENSEMODE and SENSECHAR QIO function
X     to read the device characteristics of the TW terminal device.
X     These work exactly the same as they would to a terminal device.
X     The IOSB and return data buffer have the same format.  This allows
X     the controlling application to track the state of the associated TW
X     device.
X
X     NOTE:  Because SENSEMODE now returns TW terminal characteristics,
X            you can no longer use it to return the PY device dependent
X            longword which contains the unit number for the associated
X            TW device.  You must use $GETDVI instead.  You should already
X            have been using $GETDVI.
X
X  o  Modification to slave terminal device ownership to function
X     correctly after "Security Upgrade V2" has been applied to a
X     VMS V4 system.  The security upgrade is incorporated into V5.
X
X  o  The PY device now supports writes of buffers greater than 64K.
X     Note that use of such large buffers probably requires that you monitor
X     the flow control ASTs.
X
X     The security upgrade fixed a bug whereby cloned terminal devices
X     were not protected in accordance with the system-wide terminal
X     protection mask, but were left wide open.  Cloned terminals are
X     no longer G,W:RWLP.  This caused some PTY applications to break,
X     since they needed access to the created terminal device without
X     privileges.  This version of the PTY drivers sets the device owner
X     of the cloned terminal device to that of the creator.  This should
X     allow applications that were sensitive to the device protection to
X     continue to function.  Additionally, the device remains inaccessible
X     to GROUP and WORLD, in keeping with system security requirements.
X
X     Other solutions to this problem have been proposed which merely force
X     the terminal protections wide open.  This is not a good idea as it
X     circumvents system security requirements.
X
X  o  The terminal device name has been changed from TPAn: to TWAn: because
X     the VAX PSI product now uses TP.  PY and TW are the names of choice
X     now since they have been registered within Digital by a development
X     group.  Some applications which are hard-coded for TPAn: or some
X     other name are going to break.  Perhaps they should have used a
X     logical name to refer to the device in the first place.  Oh well.
X
X     Source code is available for such applications (the two types of
X     PHOTO utility come to mind) and will have to be changed.  Alternately,
X     it is a simple patch to the executable if source code is not
X     available.  Finally, you may be able to get by with defining TPA0
X     to be TWA0 if you cannot fix or patch but this is may cause problems
X     if you use VAX PSI.  I urge anyone distributing an application which
X     will break due to this change to fix their application and make it
X     available again.
X
X     Please note that not all applications of PTY need to know the
X     terminal device name.  The TEK-CMU IP/TCP package, at least in
X     V6.0 with which I am familiar, uses PTYs but does not care what
X     the terminal device name is.
X
X     On a final note, if the results of the Digital development effort which
X     is using PY and TW should find their way onto your system, you
X     should be able to continue to use your applications with the Digital
X     supplied devices.  I will do my best to keep abreast of developments
X     in that arena and make public any caveats I find with the Digital
X     supplied devices.  At the worst, the DEC devices may be completely
X     changed, and we will change the names of PY and TW again.  Note that
X     this may be the time for you application writers to use (properly
X     prefixed -- naturally) logical names for your pseudo-terminal
X     device specifications.
X
X`009/Kevin Carosso                     kvc@nrc.com
X`009 Network Research Co.              kvc@ymir.bitnet
X
X`009June 9, 1988
X
XPS:
X
XIn case anyone has a REALLY old version, here's the notes from my
Xprevious distribution (note the date at the bottom).  These changes,
Xwhere applicable, are all incorporated into the current distribution.
X
X---------------------------------------------------------------------
X
XThe distribution version 04-006 fixes the following problems:
X
X  o  ^S^Y system crasher
X  o  randomly munged <LF> and <ESC> characters
X  o  SHOW DEVICE stack dumps
X  o  system crashes due to attempted use of the TPA0: device
X  o  terminal device name changed from PTAn: to TPAn: because
X     VMS uses PTA for MSCP tapes.
X
X`009/Kevin Carosso              kvc@engvax.scg.hac.com
X`009 Hughes Aircraft Co.`009or  kvc%engvax@oberon.usc.edu
X
X`009 December 9, 1986
$ GOSUB UNPACK_FILE
$ FILE_IS = "BUILD.COM"
$ CHECKSUM_IS = 2087006555
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X$ macro twdriver
X$ macro pydriver
X$ link twdriver,driver/opt
X$ link pydriver,driver/opt
X$ exit
$ GOSUB UNPACK_FILE
$ FILE_IS = "DRIVER.OPT"
$ CHECKSUM_IS = 623735376
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
Xsys$system:sys.stb/select
Xbase=0
$ GOSUB UNPACK_FILE
$ FILE_IS = "NOTES.TXT"
$ CHECKSUM_IS = 1258759985
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
XThese notes document some caveats I have found.  This information
Xcomplements the documentation in PTY_DOC.TXT with some additional
Xobservations I've made.
X
XFirst of all, I want to grant credit to the original authors of the
Xdriver, they are listed at the beginning of the two source files.  In
Xprivate correspondence with Dale Moore at CMU, he has chosen to release the
Xdriver to the public domain.  There have been various incarnations of this
Xdriver in the past.  I started with a version that was modified to run
Xunder VMS V4 and cleaned it up and made CONNECT/DISCONNECT and HANGUP work
Xconsistently.  I also changed the device name of the terminal device from
XPTAn: to TPAn: because VMS now uses PTA0: for MSCP tapes.  This version
Xhas been modified further for VMS V5 and the terminal device name has been
Xchanged, once again, to TWAn: because VAX PSI has usurped TPAn:.
X
XThe previous distribution of the drivers had been tested on VMS V4.0 through
XV4.7.  This distribution has been tested under V4.7, V5 FT2, and V5.0.
X
XThe driver detects during assembly whether it is being built under VMS V4
Xor V5 and conditionally builds the proper variant.  A message will be
Xissued indicating the version being built.  You cannot build the driver
Xon one major version of VMS to execute on another.
X
XAlso note that the LINK warning message
X
X  %LINK-W-USRTFR, image has no user transfer address
X
Xis normal for device drivers and should be ignored.
X
XLoad the two drivers as PYA0: and TWA0: using a SYSGEN command such
Xas:
X
X`009$ MCR SYSGEN
X`009SYSGEN> LOAD DISK:[DIRECTORY]TWDRIVER
X`009SYSGEN> LOAD DISK:[DIRECTORY]PYDRIVER
X`009SYSGEN> CONNECT TWA0/NOADAPTER/DRIVER=TWDRIVER
X`009SYSGEN> CONNECT PYA0/NOADAPTER/DRIVER=PYDRIVER
X
XAssigning a channel to PYA0: will create a PYAn: and a TWAn:
Xpseudo-terminal pair (the unit numbers just go up).  Anything you write to
Xthat channel appears on the TW as if typed at a terminal.  Any output to
Xthe terminal TWAn: is available to be read from PYAn:.  On output, the
Xdevices do flow control between one another and all buffering.  You can
Xjust read, for example, with a 100 char buffer from PY and the read will
Xcomplete with whatever number of characters the QIO to the TW terminal
Xhad, anywhere from 1 to MAXBUF. If the QIO to the TW had more chars than
Xyour read buffer, it'll just fill the read buffer and return, and you can
Xget the rest on the next read.  On input, it is possible to overrun the TW
Xdevice's terminal type-ahead buffer, as it is with a real terminal.
X
XIf you assign a mailbox with the PYAn: device (use LIB$ASN_WTH_MBX
Xwhen assigning the channel to PYA0:) you will get an MSG$_TRMHANGUP
Xmessage in the mailbox whenever the terminal is hung-up.  This occurs
Xwhen a process deassigns the last channel to the device, just as a HANGUP
Xwill on terminals with modem signals.  You may ignore the hangup message if
Xyou choose and continue to use the device after the message.
X
XShould you deassign all channels to the PYAn: device, a hangup will be
Xforced on any process using the TWAn: device.  Just like dropping carrier on
Xa modem line.  If the pseudo-terminal is in use by an interactive process
Xand has an associated virtual terminal, the process will be disconnected,
Xotherwise the interactive process will be logged out.
X
XTo enable virtual terminals on pseudo-terminals, you must have the
XTT2$M_DISCONNECT bit set in the system default terminal characteristics
X(TTY_DEFCHAR2 in SYSGEN).
X
XNote that, just as with normal VMS terminals, you will only get a
XVTAn: if the line has the DISCONNECT terminal characteristic before
Xyou log into it, and only if you use LOGINOUT to start a process on
Xthe terminal.  Sending a <CR> into the pseudo-terminal device will
Xstart up LOGINOUT as it would on a real terminal.
X
XThere is currently one minor known bug in the drivers, a side-effect of
Xthe driver being cautious in order to prevent possible problems.  If you
Xhave a virtual terminal associated with the pseudo-terminal, and you
Xdeassign the last channel to the control device (the PY device) then a
XDISCONNECT is forced on any process on the TW and both devices should be
Xdeleted.  Currently, the TW will not disappear, though the PY will and
Xthe TW will be marked as OFFLINE.  This is because I rely on VMS to do
Xthe actual delete of the device and it appears that virtual terminals
Xscrew up the way device reference counts work, so VMS never gets around to
Xdeleting the device.  It is marked for delete, so anything you do (I like
XSHOW TERM TWA53:, for example) will cause it to disappear.  I could fix this
Xby zapping the device explicitly after forcing the DISCONNECT, however I
Xam not convinced that someone, somewhere, won't try to reference the UCB and
Xthus cause bad things to occur.  Note that it DOES get deleted correctly if
Xyou do not have a virtual terminal associated with the TW or if you have no
Xprocesses active on the TW when the PY and TW are to be deleted.  These two
Xcases are generally the norm.
X
XIt should be possible to set the TW terminal characteristics through
Xthe PY device, so the controlling program can set them.
XThere may be ramifications of changing device characteristics on
XTTDRIVER unexpectedly, however, that have to be figured out first.
X
XIf you need to set characteristics of the terminal device right now,
Xyou must assign a channel to the TW device and use a SETCHAR QIO
Xthen deassign the channel before giving the TW to another process. You
Xwill get a HANGUP message in the associated mailbox when you
Xdeassign if the HANGUP attribute was set on the device.  You can
Xignore this message, however, and go ahead and use the device.
X
XThis is sufficient for most applications that need to set characteristics
Xonly before starting up another process to use the device.
X
XIf you need to set the characteristics after your other process has
Xassigned a channel to the terminal device, you will need the SHARE
Xprivilege to assign your own channel to it and do the SETMODE.  Note that
Xthe SETMODE QIO you do should be asynchronous as your QIO may get queued
Xbehind other QIO's and your application probably does not want to wait for
Xcompletion.
X
X`009/Kevin Carosso               kvc@nrc.com
X`009 Network Research Co.        kvc@ymir.bitnet
X
X`009 June 17, 1988  (supersedes NOTES.TXT dated December 9, 1986)
$ GOSUB UNPACK_FILE
$ FILE_IS = "PTY.PAS"
$ CHECKSUM_IS = 1629888086
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X(* Simple program to converse with the pseudo-terminal control device. *)
X
X[inherit ('SYS$LIBRARY:STARLET')]
Xprogram PTY;
X
Xconst
X  buffer_size = 256;
X  CTRL_BACKSLASH = chr (28);
X
Xtype
X  string = varying [256] of char;
X  unsigned_byte = [byte] 0..255;
X  unsigned_word = [word] 0..65535;
X  characteristic_buffer = packed record
X`009`009`009    dev_class, dev_type : unsigned_byte;
X`009`009`009    width : unsigned_word;
X`009`009`009    charbits, extended_bits : unsigned;
X`009`009`009  end;
X  status_block = packed record
X`009`009   status, count, terminator, terminator_size : unsigned_word;
X`009`009 end;
X
Xvar
X  stat : integer;
X  mbx_chan, tt_chan, pty_chan : [static, volatile] unsigned_word;
X  input_char : [static, volatile] char;
X  buffer : packed array [1..buffer_size] of char;
X  mbx_buffer : [static, volatile] packed array [1..40] of char;
X  term_chars, old_term_chars : [static, volatile] characteristic_buffer;
X  in_iosb, out_iosb, mbx_iosb : [static, volatile] status_block;
X  exit_descriptor : [static] packed record
X`009`009      flink : unsigned;
X`009`009      handler : unsigned;
X`009`009      argnum : integer;
X`009`009      reason : ^integer;
X`009`009    end := (0, 0, 1, nil);
X  message : [static, volatile] string :=
X`009`009`009`009''(13, 10, 7)'Got a mailbox message'(13, 10);
X
X{-----------------------------------------------------------------------------}
X
X  [external]
X  function LIB$ASN_WTH_MBX
X`009`009(DEVNAM : [class_s] packed array [l1..u1:integer] of char;
X`009`009 MAXMSG, BUFQUO : integer;
X`009`009 var DEVCHAN, MBXCHAN : [volatile] unsigned_word
X`009`009) : integer; extern;
X
X(*
X * CLEANUP is our exit handler.  It resets the terminal characteristics.
X *)
X
X  [unbound]
X  function Cleanup (reason : integer) : integer;
X
X  var
X    stat : integer;
X    iosb : status_block;
X
X  begin (* Cleanup *)
X    Cleanup := reason;
X    stat := $QIOW (CHAN := tt_chan,
X`009`009     FUNC := IO$_SETMODE,
X`009`009     P1 := old_term_chars,
X`009`009     P2 := size (old_term_chars));
X    if not odd (stat) then Cleanup := stat;
X  end; (* Cleanup *)
X
X  [asynchronous, unbound]
X  procedure Set_asynch_mbx_input; forward;
X
X(*
X * MBX_INPUT_AST is the AST handler invoked whenever we get something in
X * the associated mailbox.
X *)
X  [asynchronous, unbound]
X  procedure Mbx_input_AST;
X
X  var
X    stat : integer;
X    iosb : status_block;
X
X  begin (* Mbx_input_AST *)
X    if not odd (mbx_iosb.status) then $EXIT (mbx_iosb.status);
X
X    stat := $QIOW (CHAN := tt_chan,
X`009`009   FUNC := IO$_WRITEVBLK,
X`009`009   IOSB := iosb,
X`009`009   P1 := message.body,
X`009`009   P2 := message.length);
X    if not odd (stat) then $EXIT (stat);
X    if not odd (iosb.status) then $EXIT (iosb.status);
X
X    Set_asynch_mbx_input;
X  end; (* mbx_input_AST *)
X
X(*
X * SET_ASYNCH_MBX_INPUT issues an asynchronous read on the terminal.
X *)
X  procedure Set_asynch_mbx_input;
X
X  var
X    stat : integer;
X
X  begin (* Set_asynch_mbx_input *)
X    stat := $QIO (CHAN := mbx_chan,
X`009`009  FUNC := IO$_READVBLK,
X`009`009  IOSB := mbx_iosb,
X`009`009  ASTADR := mbx_input_AST,
X`009`009  P1 := mbx_buffer,
X`009`009  P2 := size (mbx_buffer));
X    if not odd (stat) then $EXIT (stat);
X  end; (* Set_asynch_mbx_input *)
X
X  [asynchronous, unbound]
X  procedure Set_asynch_input; forward;
X
X(*
X * INPUT_AST is the AST handler invoked whenever we get something in
X * from the terminal.  Just ship it to the PTY.
X *
X * One thing to note:  We are ignoring the fact that the PTY may return
X * SS$_DATAOVERUN if we fill up it's input buffer and it wants to XOFF us.
X * This should not really be a problem, since we tend to write one-char-at-
X * a-time.  We could also disable the HOSTSYNC characteristic on the pseudo
X * terminal, which causes it to never return the SS$_DATAOVERUN.  Either
X * way, data that doesn't fit into the typeahead buffer is lost.
X *
X * If the application wants input flow control, it should register for
X * the XON AST using an IO$_SETMODE QIO.  It should then check for
X * SS$_DATAOVERUN on writes, keep track of characters actually delivered,
X * as specified in the "count" field of the IOSB, and deliver the rest of
X * the characters when we get XON'ed again.  It should also not attempt
X * to deliver any additional data to the PTY until the XON AST happens.
X *)
X  [asynchronous, unbound]
X  procedure Input_AST;
X
X  var
X    stat : integer;
X
X  begin (* Input_AST *)
X    if not odd (in_iosb.status) then $EXIT (in_iosb.status);
X    if input_char = CTRL_BACKSLASH then $EXIT (SS$_NORMAL);
X
X    stat := $QIOW (CHAN := pty_chan,
X`009`009   FUNC := IO$_WRITEVBLK,
X`009`009   IOSB := in_iosb,
X`009`009   P1 := input_char,
X`009`009   P2 := 1);
X    if not odd (stat) then $EXIT (stat);
X    if (not odd (in_iosb.status) and (in_iosb.status <> SS$_DATAOVERUN)) then
X      $EXIT (in_iosb.status);
X
X    Set_asynch_input;
X  end; (* Input_AST *)
X
X(*
X * SET_ASYNCH_INPUT issues an asynchronous read on the terminal.
X *)
X  procedure Set_asynch_input;
X
X  var
X    stat : integer;
X
X  begin (* Set_asynch_input *)
X    stat := $QIO (CHAN := tt_chan,
X`009`009  FUNC := IO$_READVBLK,
X`009`009  IOSB := in_iosb,
X`009`009  ASTADR := Input_AST,
X`009`009  P1 := input_char,
X`009`009  P2 := 1);
X    if not odd (stat) then $EXIT (stat);
X  end; (* Set_asynch_input *)
X
Xbegin (* PTY *)
X  stat := LIB$ASN_WTH_MBX (DEVNAM := 'PYA0:',
X`009`009`009    MAXMSG := size (mbx_buffer),
X`009`009`009    BUFQUO := 2 * size (mbx_buffer),
X`009`009`009    DEVCHAN := pty_chan,
X`009`009`009    MBXCHAN := mbx_chan);
X  if not odd (stat) then $EXIT (stat);
X
X  Set_asynch_mbx_input;
X
X  stat := $ASSIGN (CHAN := tt_chan, DEVNAM := 'TT');
X  if not odd (stat) then $EXIT (stat);
X
X(* Get terminal characteristics. *)
X
X  stat := $QIOW (CHAN := tt_chan,
X`009`009 FUNC := IO$_SENSEMODE,
X`009`009 P1 := term_chars,
X`009`009 P2 := size (term_chars));
X  if not odd (stat) then $EXIT (stat);
X
X  if term_chars.dev_class <> DC$_TERM then
X    $EXIT (SS$_IVDEVNAM);
X
X  old_term_chars := term_chars;
X
X(* declare exit handler so that terminal chars are restored *)
X
X  exit_descriptor.handler := iaddress (Cleanup);
X  new (exit_descriptor.reason);
X
X  stat := $DCLEXH (DESBLK := exit_descriptor);
X  if not odd (stat) then $EXIT (stat);
X
X(*
X * Set terminal characteristics we need:
X *    PASSTHRU, NOECHO, NOTTSYNC, NOHOSTSYNC
X *)
X
X  with term_chars do
X  begin
X    extended_bits := UOR (extended_bits, TT2$M_PASTHRU);
X    charbits := UOR (charbits, TT$M_NOECHO);
X    charbits := UAND (charbits, UNOT (TT$M_TTSYNC));
X    charbits := UAND (charbits, UNOT (TT$M_HOSTSYNC));
X  end;
X
X  stat := $QIOW (CHAN := tt_chan,
X`009`009 FUNC := IO$_SETMODE,
X`009`009 P1 := term_chars,
X`009`009 P2 := size (term_chars));
X  if not odd (stat) then $EXIT (stat);
X
X  Set_asynch_input;
X
X  repeat
X    stat := $QIOW (CHAN := pty_chan,
X`009`009   FUNC := IO$_READVBLK,
X`009`009   IOSB := out_iosb,
X`009`009   P1 := buffer,
X`009`009   P2 := size (buffer));
X    if not odd (stat) then $EXIT (stat);
X    if not odd (out_iosb.status) then $EXIT (out_iosb.status);
X
X    stat := $QIOW (CHAN := tt_chan,
X`009`009   FUNC := IO$_WRITEVBLK,
X`009`009   IOSB := out_iosb,
X`009`009   P1 := buffer,
X`009`009   P2 := out_iosb.count);
X    if not odd (stat) then $EXIT (stat);
X    if not odd (out_iosb.status) then $EXIT (out_iosb.status);
X  until false;
Xend. (* PTY *)
$ GOSUB UNPACK_FILE
$ FILE_IS = "PTY_DOC.TXT"
$ CHECKSUM_IS = 202457527
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X             Pseudo Terminal release notes
X
X
X
X
X
X             This document briefly describes a VAX/VMS Pseudo Terminal. It
X             contains information about the device, a programming chapter, user
X             interface section, and instructions on compiling and installing
X             the drivers.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X`012
X
X
X
X
X
X
X
X
X
X          Contents
X
X
X          CHAPTER 1  INTRODUCTION                                           1-1
X
X               1.1  USES OF PTYS                                            1-1
X
X               1.2  CONCEPT OF CONTROL AND TERMINAL DEVICE                  1-2
X
X               1.3  SIMILARITIES BETWEEN PTYS AND TERMINALS                 1-2
X
X               1.4  DIFFERENCES BETWEEN PTYS AND TERMINALS                  1-3
V                     1.4.1  Device Characteristics                           1-
X3
V                     1.4.2  Device Type                                      1-
X4
V                     1.4.3  Device Class                                     1-
X4
V                     1.4.4  TW Unit Number                                   1-
X4
X
X          CHAPTER 2  USING THE PTY                                          2-1
X
X               2.1  CREATING A PTY                                          2-1
X
X               2.2  READING DATA                                            2-2
X
X               2.3  WRITING DATA                                            2-3
X
X               2.4  SPECIAL SIGNALS                                         2-4
X
X               2.5  PROBLEMS                                                2-4
X
X          CHAPTER 3  PTY FUNCTION CODES                                     3-1
X
X               3.1  READ                                                    3-1
X
X               3.2  WRITE                                                   3-2
X
X               3.3  SET MODE AND SET CHARACTERISTICS                        3-3
X
X               3.4  SENSE MODE AND SENSE CHARACTERISTICS                    3-4
X
X               3.5  I/O STATUS BLOCK                                        3-5
X
X
X
X
X
X
X
X                                                                            iii
X`012
X
X
X
X          Contents
X
X
X
X
X          CHAPTER 4  BUILDING AND INSTALLING THE PTY                        4-1
X
X               4.1  COMPILING SOURCES                                       4-1
X
X               4.2  INSTALLING THE DEVICES                                  4-2
X
X
X          FIGURES
X               3-1  Sense Mode and Characteristics Buffer                   3-5
X               3-2  IOSB Contents - Read and Write Function                 3-5
X               3-3  IOSB Contents - Set Mode and Characteristics
V                     Functions                                               3-
X6
X               3-4  IOSB Contents - Sense Mode and Characteristics
V                     Functions                                               3-
X6
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          iv
X`012
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          Chapter 1
X
X
X          Introduction
X
X
X
X
X             This chapter describes the use of the VAX/VMS Pseudo Terminal
X             Driver as implemented at Carnegie-Mellon University Computer
X             Science Department. Additional information about VMS device
X             drivers and the VMS operating system interface can be found in
X             VAX/VMS I/O User's Guide, and in VAX/VMS System Service Reference
X             Manual.
X
X
X          1.1  Uses of PTYs
X
X             There is no device from DEC which suffices for remote logins when
X             using non-DECnet protocols. The remote terminal driver expects the
X             remote node to do the local line editing. This includes delete,
X             control-o, control-s, control-q, and many other capabilities. PTYs
X             handle the local line editing locally. When the line editing is
X             done locally, the remote machine has to know much less about VMS
X             and its terminal handling conventions.
X
X
X
X
X
X
X
X
X
X
X                                                              Introduction  1-1
X`012
X
X
X
X
X
X
X
X
X          1.2  Concept of Control and Terminal Device
X
X             A single PTY consists of two devices, a control and a terminal de-
X             vice. The terminal device is the device that acts like a terminal.
X
X             The control device on VMS is named ````PYAx:''. For example, a
X             PTY control device could be named ````PYA1:''. The terminal de-
X             vice portion of the PTY is name ````TWAx:''. The terminal device
V             ````TWA1:'' is the mate to the control device ````PYA1:''. Similar
Xly,
X             the control device ````PYA5:'' is the mate to the terminal device
X             ````TWA5:''.
X
X
X          1.3  Similarities Between PTYs and Terminals
X
X             The terminal portion of a PTY behaves very much like a regular
X             VAX/VMS terminal. The terminal portion of a PTY has:
X
X              o  Type-ahead
X
X              o  Specifiable or default line terminators
X
X              o  Special operating modes, such as NOECHO and PASSALL
X
X              o  American National Standard escape sequence detection
X
X              o  Terminal/mailbox interaction
X
X              o  Terminal control characters such as Sontrol-S and control-q
X                for starting and stopping output, Control-O for discarding
X                output, and all other special characters that are handled by
X                the VAX/VMS terminal driver.
X
X              o  Limited full-duplex operation (simultaneously active read and
X                write requests)
X
X              o  The device characteristics are inherited from the system de-
X                fault parameters with the following exceptions:
X
X                 -  The device is always forced to HOSTSYNC.
X
X
X
X
X
X          1-2  Introduction
X`012
X
X
X
X
X
X
X
X
X                 -  The device is set to NOMODEM and cannot ever be set to
X                   MODEM.
X
X
X
X          1.4  Differences Between PTYs and Terminals
X
X             The difference between a VAX/VMS terminal and the terminal portion
X             of a PTY is where the input comes from and where the output goes
X             to. On a VAX/VMS terminal, the input comes from an actual terminal
X             and the output goes to an actual terminal. On a PTY the input
X             comes from the control device and the output goes to the control
X             device. In order to simulate someone typing at the terminal device
V             ````TWA5:'' we must write to the control device ````PYA5:''. In or
Xder
X             to read what has been typed out to the terminal device ````TWA5:''
X             we must read from the control device ````PYA5:''. PTYs are like
X             terminals that only software can access.
X
X             PTYs are virtual devices. When allocating a PTY, they behave much
X             like mailboxes or network devices. To allocate a PTY, simply
X             allocate the first one ('PYA0:'). The allocating routine will
X             create a new PTY and assign it to you. The PTY will be deallocated
X             when no process is referencing the device.
X
X
X          1.4.1  Device Characteristics
X
X             A PTY control device has the following characteristics.
X
X              o  DEV$M_AVL - On line and available
X
X              o  DEV$M_IDV - Capable of input
X
X              o  DEV$M_ODV - Capable of output
X
X              o  DEV$M_REC - Record oriented
X
X             A PTY control device does not have the following characteristics.
X
X              o  DEV$M_CCL - Carriage Control
X
X
X
X
X                                                              Introduction  1-3
X`012
X
X
X
X
X
X
X
X
X              o  DEV$M_TRM - Terminal Device
X
X
X          1.4.2  Device Type
X
X             The device type is DT$_PY. Since a PTY is a nonstandard device,
X             you will probably not find the correct macros, literals or con-
X             stants for this device type. This field should have a value of
X             0.
X
X
X          1.4.3  Device Class
X
X             The device class is DC$_PY. Since a PTY seems to be such an odd
X             creature, this field should be FF in hex, or 177 in octal.
X
X
X          1.4.4  TW Unit Number
X
X             The unit number of the TW device is the same as the unit number of
X             the associated PT device.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          1-4  Introduction
X`012
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          Chapter 2
X
X
X          Using the PTY
X
X
X
X
X             This chapter will present information on using the PTY. It covers
X             creating the device, reading, writing data, and using additional
X             signaling information. Finally it covers a minor deficiency of the
X             existing implementation.
X
X
X          2.1  Creating a PTY
X
X             Make sure the two drivers are loaded as PYA0: and TWA0:. Then,
X             just assign a channel to PYA0:, this will create a PYAn: and a
X             TWAn: (the unit numbers just go up). Anything you write to that
X             channel appears on the TWAx: as if typed at a terminal. Any output
X             to the terminal TWAn: is available to be read from PYAn:. The
X             devices do flow control between one another and all buffering. So,
X             you can just read, for example, with a 100 char buffer from PY and
X             the read will complete with whatever number of characters the QIO
X             to the PTY terminal had, anywhere from 1 to MAXBUF. If the QIO to
X             the PTY had more chars than your read buffer, it'll just fill the
X             read buffer and return, and you can get the rest on the next read.
X             It is very simple to use.
X
X             Also, if you assign a mailbox with the PYAn: device (use LIB$ASN_
X             WTH_MBX when assigning channel to PYA0:) you will get a MSG$_
X             TRMHANGUP see the VMS I/O User's Reference Manual: Part I for
X             the format of the message in the mailbox whenever the terminal
X
X
X
X                                                             Using the PTY  2-1
X`012
X
X
X
X
X
X
X
X
X             is hung-up. A hang-up occurs when a process logouts out or it or
X             deassigns the last channel to the device. It works just like the
X             HANGUP on terminals with modem signals. You can even ignore the
X             hangup message if you want, it only generates the message in the
X             mailbox, you can continue to use the device if you choose after
X             getting the message.
X
X             Should you deassign the PYAn: device, a DISCONNECT will be forced
X             on any process using the TWAn: device, just like dropping carrier
X             on a modem line. If you have the TT2$M_DISCONNECT bit set in the
X             default terminal characteristics (TTY_DEFCHAR2 in SYSGEN), then
X             you will get a virtual terminal upon logging into a TWAn: device.
X             Then you get CONNECT/DISCONNECT to work. Really nice on network
X             connections.
X
X             Note that, just as with normal VMS terminals, you will only get
X             a VTAn: if the line has the DISCONNECT terminal characteristic
X             before you log into it, and only if you use LOGINOUT to start a
X             process on the terminal. Just sending a <CR> into the device as
X             the first character will start up LOGINOUT like a normal terminal.
X
X
X          2.2  Reading data
X
X             A read from the the PY device is used to accept data from the
X             TW device. The largest read operation possible is limited by the
X             value of SYSGEN parameter MAXBUF. The read request will complete
X             with a minimum of 1 character and maximum of the number characters
X             the buffer can hold. The read operation will only complete when
X             the TW driver has one or more characters to output. If at the time
X             you issue a read request no data is available this request will
X             be queued and completed at a later time. The PY device accepts
X             all three read function codes, but unlike the TW device treats all
X             three exactly the same. Note, that the system will still require
X             that you have the correct privileges to use them.
X
X
X
X
X
X
X          2-2  Using the PTY
X`012
X
X
X
X
X
X
X
X
X             When writing a control program for the PTY, care should be taken
X             to insure that a read request is always queued to the PY device.
X             Failure to do so can cause excessive delays in processing on the
X             TW device.
X
X
X          2.3  Writing data
X
X             A write to the PY device is used to input data to the TW device.
X             The largest write operation possible is limited by the value of
X             the SYSGEN parameter MAXBUF. It is not recommended that vary large
X             write requests be issued. It is possible by using very large I/O
X             requests to flood the TW devices input buffer. When this occurs
X             data will be lost without an error being reported. Note the driver
X             has been optimized for write requests of 1 to 32 bytes. Larger
X             requests will work but require more work on the part of the driver
X             to setup and process.
X
X             The current version of the driver has taken steps to help pre-
X             vent the data over-run condition described above. It does this
X             by setting the TW device to send and XOFF message if its type-
X             ahead buffer it getting full. Once this occurs, the PY device
X             will return a status of SS$_DATAOVERUN with the actual number of
X             characters input. This is sufficient to prevent a single request
X             from flooding the type-ahead buffer. If a program makes repeated
X             attempts to insert data after receiving this message it can flood
X             the terminal type-ahead buffer. This occurs because the driver
X             always inserts one character before checking to see if TW driver
X             is accepting data. Because the class driver does not tell the in-
X             put routine that it rejected the character, it is not possible to
X             report this real loss of data. One final note: if for some reason
X             the TW device clears the HOSTSYNC characteristic the driver will
X             no longer report the impending data overrun condition.
X
X
X
X
X
X
X
X
X                                                             Using the PTY  2-3
X`012
X
X
X
X
X
X
X
X
X          2.4  Special signals
X
X             Certain class driver events such as stopping and resuming input,
X             stopping and resuming output, and altering the device characteris-
X             tics, are of interest to the control program. This version of the
X             PTY SUPPLIES a notification mechanism for three of these events.
X             It provides notification for stopping and starting input; and for
X             notification when the device characteristics change. The control
X             program will have the supplied AST routine called when one these
X             events occur.
X
X             By making use of the start and stop input ASTs, and the SS$_
X             DATAOVERUN return stauts the control program can avoid flooding
X             the TW devices type-ahead buffer. Note, that these signals will
X             be returned even if HOSTSYNC is cleared. These AST can be enabled
X             by using the IO$_SETMODE, or the IO$_SETCHAR function on the PY
X             DEVICE. The ASTs will not accept an AST parameter, instead they
X             return the class driver signal character as the AST parameter.
X
X             Finally, the control, program by using the AST delivered the the
X             TW device, changes characteristics along with the IO$_SENSExxxx
X             function to track the TW device characteristics.
X
X
X          2.5  Problems
X
X             A minor problem exists and is actually a side-effect of the driver
X             being cautious in order to prevent possible problems. If you have
X             a virtual terminal associated with the pseudo-terminal, and you
X             deassign the last channel to the control device (the PY device)
X             a DISCONNECT is forced on any process on the terminal (the TW
X             device) and the PY and TW are both deleted. In this case, the TW
X             will not be deleted, although the PY will and the TW be marked
X             as OFFLINE. This is because the driver relies on VMS to do the
X             actual delete of the device. VT's alter the way device reference
X             counts work, and VMS never gets around to deleting the device.
X             It is marked for delete, so anything you do (like SHOW TERM) will
X             cause it to be deleted. This could be fixed by deleting the device
X
X
X
X          2-4  Using the PTY
X`012
X
X
X
X
X
X
X
X
X             explicitly after forcing the DISCONNECT, however it is very hard
X             to prevent the use of the UCB and thus cause a system crash. Note
X             that it doesget deleted correctly if you do not have a virtual
X             terminal associated with the PTY, or if you have no processes
X             active on the PTY when the PY and TW are to be deleted.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X                                                             Using the PTY  2-5
X`012
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          Chapter 3
X
X
X          PTY Function Codes
X
X
X
X
X             The function codes for the terminal device portion of a PTY are
X             exactly the same as those for regular VAX/VMS terminals. For more
X             information on VAX/VMS terminal I/O see VAX/VMS I/O User's Guide.
X
X             The basic function of the control portion of a PTY are read, write
X             and set mode or characteristics.
X
X             A user does not need to have assigned the PTY terminal device
X             in order to do I/O operations on the PTY control device. If the
X             terminal device has type ahead enabled, sending the right charac-
X             ters to the control device will send a message to OPCOM to start
X             running SYS$SYSTEM:LOGINOUT.EXE on the terminal device.
X
X
X          3.1  Read
X
X             The basic purpose of a PTY control device read is to transfer
X             data from the output buffer of the PTY terminal device to a user
X             specified buffer. There are three read functions which a user can
X             apply to a PTY control device.
X
X              o  IO$_READVBLK - Read virtual block
X
X              o  IO$_READLBLK - Read logical block
X
X              o  IO$_READPBLK - Read physical block
X
X
X
X
X                                                        PTY Function Codes  3-1
X`012
X
X
X
X
X
X
X
X
X             A read is complete if either of the below conditions occur:
X
X              o  The user specified buffer is full
X
X              o  At least one character is available from the PTY terminal
X                device
X
X             The read function codes can take the following device/function
X             dependent arguments:
X
X              o  P1 = The starting virtual address of the buffer that is to
X                receive the data read
X
X              o  P2 = The size of the buffer in bytes that is to receive the
X                data read
X
X              o  P3, P4, P5, P6 = ignored
X
X
X
X          3.2  Write
X
X             The basic purpose of a PTY control device write is to transfer
X             data from the user specified buffer to the type-ahead buffer of
X             the PTY terminal device. There are three write functions which a
X             user can apply to a PTY control device.
X
X              o  IO$_WRITEVBLK - write virtual block
X
X              o  IO$_WRITELBLK - write logical block
X
X              o  IO$_WRITEPBLK - write physical block
X
X             The write function codes can take the following device/function
X             dependent arguments:
X
X              o  P1 = The starting virtual address of the buffer that is to be
X                written to the PTY terminal device
X
X              o  P2 = The number of bytes that are to be sent
X
X              o  P3, P4, P5, P6 = Ignored
X
X
X
X
X          3-2  PTY Function Codes
X`012
X
X
X
X
X
X
X
X
X          3.3  Set Mode and Set Characteristics
X
X             The SETMODE and SETCHAR functions allow the programmer to enable
X             three special event notification ASTs. These special events have
X             been discussed in detail in the previous chapter. The driver
X             treats both of these funtion code identically but the VMS QIO(W)
X             dispatcher will require the PHY_IO privilege if you use choose to
X             use the IO$_SETCHAR function.
X
X              o  IO$_SETMODE
X
X              o  IO$_SETCHAR
X
X             These functions take the following device/function dependent
X             arguments.
X
X              o  P1 = address of characteristics buffer
X
V              o  P2 = For XON and XOFF ASTs the program can provide a 16 bit AS
XT
X                parameter. When the AST is delivered the high order 16 bits of
X                the AST parameter will be XON, XOFF, or bell character. For the
X                notification of TW characterisitcs changing the AST parameter
X                can be a full long word (32-bits).
X
X              o  P3 = access mode to deliver AST (maximized with the caller's
X                access mode)
X
X              o  P4 = type of AST to be queued. (1 = XON AST notification,
X                2 = XOFF AST notification, and 3 = terminal characteristics
X                changed)
X
X              o  P5, P6 = ignored
X
X
X
X
X
X
X
X
X
X
X
X                                                        PTY Function Codes  3-3
X`012
X
X
X
X
X
X
X
X
X          3.4  Sense Mode and Sense Characteristics
X
X             The two function codes to sense the mode of the PTY control device
X             are:
X
X              o  IO$ SENSEMODE
X
X              o  IO$ SENSECHAR
X
X             The IO$ SENSEMODE function returns the process-associated, that
X             is temporary, characteristics of the terminal device. The IO$
X             SENSECHAR function returns the permanent characteristics of the
X             terminal device. The IO$_SENSEMODE function is a logical func-
X             tion and requires no privilege. The IO$_SENSECHAR function is a
X             physical function and requires the PHY_IO privilege use it.
X
X             These function codes take the following device/function dependent
X             arguments.
X
X              o  P1 = address of an 8 or 12 byte characteristics buffer
X
X              o  P2 = size of characteristics buffer (eight is the default)
X
X              o  P3, P4, P5, P6 = ignored
X
X             The P1 argument points to a quadword block which is the same for-
X             mat as the Set Mode Characteristics Buffer, shown in Figure 3-1.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          3-4  PTY Function Codes
X`012
X
X
X
X
X
X
X
X
X             Figure 3-1: Sense Mode and Characteristics Buffer
X             __________________________________________________________________
X                           31        24 23        16 15         8 7          0
X                          -----------------------------------------------------
X                          |        Page Width       |    Type    |   Class    |
X                          -----------------------------------------------------
X                          | Page Length|       Basic Characteristics          |
X                          -----------------------------------------------------
X                          |             Extended Characteristics              |
X             _____________-----------------------------------------------------
X
X
X             Figure 3-2: IOSB Contents - Read and Write Function
X             __________________________________________________________________
X
X                           31        24 23        16 15         8 7          0
X                          -----------------------------------------------------
X                          |       Byte Count        |         Status          |
X                          -----------------------------------------------------
X                          |                      Unused                       |
X                          -----------------------------------------------------
X
X             __________________________________________________________________
X
X          3.5  I/O Status Block
X
X             The I/O status block formats for read, write, set mode and sense
X             mode I/O functions are shown in Figure 3-2, 3-3 and 3-4.
X
X             The status indicates the success or failure of the specified
X             operation. Below are possible values for the status field:
X
X              o  SS$_ABORT - The operation was canceled by the Cancel I/O on
X                Channel ($CANCEL) system service. Applicable only if the drive
X                was actively involved in an operation.
X
X
X
X
X
X
X
X                                                        PTY Function Codes  3-5
X`012
X
X
X
X
X
X
X
X
X             Figure 3-3: IOSB Contents - Set Mode and Characteristics
X                          Functions
X             __________________________________________________________________
X
X                           31        24 23        16 15         8 7          0
X                          -----------------------------------------------------
X                          |         Unused          |         Status          |
X                          -----------------------------------------------------
X                          |                      Unused                       |
X             _____________-----------------------------------------------------
X
X
X             Figure 3-4: IOSB Contents - Sense Mode and Characteristics
X                          Functions
X             __________________________________________________________________
X
X                           31        24 23        16 15         8 7          0
X                          -----------------------------------------------------
X                          | Rcv Speed  | Xmit speed |         Status          |
X                          -----------------------------------------------------
X                          |   Unused   |parity flags|  LF fill   |  CR fill   |
X                          -----------------------------------------------------
X             __________________________________________________________________
X
X              o  SS$_ACCVIO - The specified buffer is not accessible to the
X                specified process
X
X              o  SS$_BADPARAM - An illegal value was supplied in P4 for a set
X                request.
X
X              o  SS$_DATAOVERUN - The TW device has stopped accepting data. The
X                byte count indicates the number of characters accepted by the
X                terminal.
X
X              o  SS$_NORMAL - Successful Completion.
X
X              o  SS$_NOSUCHDEV - The TW device no longer exists.
X
X
X
X
X
X
X          3-6  PTY Function Codes
X`012
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          Chapter 4
X
X
X          Building and Installing the PTY
X
X
X
X
X             In VAX/VMS V5.0, several pieces of software support the terminal
V             interface. The hardware independent portion is SYS$SYSTEM:TTDRIVER
X.EXE.
X             This version of the PTY does not require any changes or patches to
X             this code. PTY drivers consist of two device drivers, TWDRIVER.EXE
X             for the terminal portion of the PTY's, and PYDRIVER.EXE for the
X             control portion. In order to have a working PTY you must build and
X             install both pieces.
X
X
X          4.1  Compiling Sources
X
X             There are several pieces of source code that make up PTY drivers.
X             PYDRIVER.MAR is the source for the control portion. TWDRIVER.MAR
X             is the source for the terminal portion.
X
X             The commands for compiling and linking the devices are:
X
X
X
X
X
X
X
X
X
X
X
X
X                                           Building and Installing the PTY  4-1
X`012
X
X
X
X
X
X
X
X
X               $ ! Compile the drivers
X               $ MACRO /LIST /OBJECT TWDRIVER.MAR
X               $ MACRO /LIST /OBJECT PYDRIVER.MAR
X               $ ! Link the drivers
X               $ LINK /MAP /FULL /CROSS -
X                       TWDRIVER,SYS$SYSTEM:SYS.STB/SELECTIVE,SYS$INPUT:/OPTION
X               BASE=0
X               $ LINK /MAP /FULL /CROSS -
X                       PYDRIVER,SYS$SYSTEM:SYS.STB/SELECTIVE,SYS$INPUT:/OPTION
X               BASE=0
X
X
X          4.2  Installing the Devices
X
X             To load a PTY, login to a privileged account and issue the follow-
X             ing commands.
X
X               $ RUN SYS$SYSTEM:SYSGEN
X               LOAD device:[directory]TWDRIVER
X               LOAD device:[directory]PYDRIVER
X               CONNECT TWA0/NOADAPTER/DRIVER=TWDRIVER
X               CONNECT PYA0/NOADAPTER/DRIVER=PYDRIVER
X
X             Don't try to use PTB0 or PYB0. The code is not built to handle
X             these. It is only built to handle the PYA and TWA control and
X             terminal devices.
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X          4-2  Building and Installing the PTY
$ GOSUB UNPACK_FILE
$ FILE_IS = "PTY_EXAMPLE.C"
$ CHECKSUM_IS = 38063334
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X/*
X* ++
X* FACILITY:
X*
X*`009TW/PY driver test program
X*
X* ABSTRACT:
X*`009`009Program to take data from a users terminal input it to a PY
X*`009device and display output.  The program contains the ability to also
X*`009report interesting events on a control connection.
X*
X*`009NOTE:
X*`009`009The program requires the following privileges
X*
X*`009`009`0091) SHARE
X*`009`009`0092) PHY_IO
X*`009`009`0093) SYSPRV
X*
X* 1) The program will ask for a terminal to output diagnostic information.  If
X*    you just hit <cr> it will skip outputying this info.
X*
X* 2) The diagnostic information is notification of XON & XOFF, and device
X*    characteristics changing on the TW device.  If you use this you have
X*    to have PHY_IO or else the program bombs.
X*
X* 3) The program will stop accepting input if the TW device is not accepting
X*    input.  When this happens all you can do is wait, I did this on purpose
X*    to make sure that the XOFF logic is working.  Some day maybe I will go
X*    back and make it smarter.
X* --
X*/
X`012
X/* Include file definitions and template structure definitions */
X
X#include`009descrip
X#include`009iodef
X#include`009ssdef
X#include`009stdio
X#include`009ttdef
X#include`009tt2def
X
Xstruct`009devchar
X{
Xchar`009`009class;
Xchar`009`009type;
Xshort int`009buffer_size;
Xint`009`009basic_char;
Xint`009`009extended_char;
X};
X
Xstruct`009iosb
X{
Xshort int`009status;
Xshort int`009byte_cnt;
Xshort int `009terminator;
Xshort int`009terminator_size;
X};
X
X
X`012
X/* Global data definitions */
X
Xchar`009`009mbx_buff[40];
Xchar  `009`009py_r_buff[255];
X
Xshort int`009info_chan;
Xshort int`009kbd_chan;
Xshort int`009mbx_chan;
Xshort int`009py_chan;
X
Xshort int`009kbd_s_efn;
Xshort int`009kbd_r_efn;
Xshort int`009py_s_efn;
Xshort int`009py_w_efn;
Xshort int`009wait_efn;
Xshort int`009xoff_efn;
X
Xint`009`009exit_handler();
Xint`009`009exit_status;
Xint`009`009info_flag = 0;
Xint`009`009term_mask[8] = {0, 0, 0, 0, 0, 0, 0, 0};
X
Xstruct`009devchar saved_char;
Xstruct`009exit_block
X{
Xint`009`009flink;
Xint`009`009*hanlder_addr;
Xchar`009`009arg_count;
Xchar`009`009unused[3];
Xint`009`009reason;
X}`009`009exit_block_descrip  = {0, exit_handler, 1, 0, 0, 0, &exit_status};
Xstruct`009iosb`009info_w_iosb;
Xstruct`009iosb`009kbd_w_iosb;
Xstruct`009iosb`009mbx_iosb;
Xstruct`009iosb`009py_r_iosb;
Xstruct`009iosb`009py_s_iosb;
Xstruct`009term_descrip
X{
Xshort int`009size;
Xshort int`009unused;
Xint`009`009*ptr;
X} term_block = {32, 0, &term_mask[0]};
X
X`012
Xmain()
X{
X
Xchar`009`009devnam[80];
Xchar`009`009kbd_r_buff[255];
X
X
X$DESCRIPTOR(dummy,"");
X$DESCRIPTOR(kbd_devnam,"tt:");
X$DESCRIPTOR(null_char,"\000");
X$DESCRIPTOR(py_devnam,"PYA0:");
X
Xint`009`009bintim[2] = {-5*10*100*100,-1};
Xint`009`009length;
Xint`009`009read_mbx_ast();
Xint`009`009py_read_ast();
Xint`009`009set_line_ast();
Xint`009`009xon_ast();
Xint`009`009xoff_ast();
Xint`009`009status;
X
Xstruct`009devchar`009changed_char;
Xstruct`009iosb`009kbd_r_iosb;
Xstruct`009iosb`009py_w_iosb;
X
X
X/* Get information channel name and assign a channel to it   */
X
Xprintf("Enter device to output diagnostic information on: ");
Xgets(devnam);
X
Xif (length=strlen(devnam))
X{
X   dummy.dsc$a_pointer = &devnam[0];
X   dummy.dsc$w_length = length;
X   status = SYS$ASSIGN(&dummy, &info_chan, 0, 0);
X   if (status & SS$_NORMAL)
X   {
X      info_flag = 1;
X   }
X   else
X   {
X      printf("Unable to assign infomation channel error number %9X", status);
X   }
X}
X
X
V/* Create a mailbox, get a channel to the PY device and the terminal exit any o
Xf these steps fail */
X
Xstatus = SYS$CREMBX(0, &mbx_chan, 0, 0, 0, 0, 0);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
Xstatus = SYS$ASSIGN(&py_devnam, &py_chan, 0, 0);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
Xstatus = SYS$ASSIGN(&kbd_devnam, &kbd_chan, 0, 0);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
X/* Get a bunch of efn that we will need exit if cannot get them */
Xstatus = LIB$GET_EF(&kbd_s_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xstatus = LIB$GET_EF(&kbd_r_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xstatus = LIB$GET_EF(&py_s_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xstatus = LIB$GET_EF(&py_w_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xstatus = LIB$GET_EF(&wait_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xstatus = LIB$GET_EF(&xoff_efn);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
X
X/* Now read the terminal characteristics so we can alter them */
X
Vstatus = SYS$QIOW(kbd_s_efn, kbd_chan, IO$_SENSEMODE, &kbd_r_iosb, 0, 0, &saved
X_char, 12, 0, 0, 0, 0);
X
Xif (status & SS$_NORMAL)
X{
X  if (kbd_r_iosb.status & SS$_NORMAL)
X  {
X    changed_char = saved_char;
V    changed_char.basic_char = TT$M_NOECHO | changed_char.basic_char & ~(TT$M_HO
XSTSYNC | TT$M_TTSYNC);
X    changed_char.extended_char = TT2$M_PASTHRU | changed_char.extended_char;
X  }
X  else
X  {
X    LIB$SIGNAL(kbd_r_iosb.status);
X  }
X}
Xelse
X{
X  LIB$SIGNAL(status);
X}
X
X
X/* Now establish the exit handler and change the terminal characteristics */
X
Xstatus = SYS$DCLEXH (&exit_block_descrip);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
Vstatus = SYS$QIOW(kbd_s_efn, kbd_chan, IO$_SETMODE, &kbd_r_iosb, 0, 0, &changed
X_char, 12, 0, 0, 0, 0);
Xif (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
Xif (!(kbd_r_iosb.status & SS$_NORMAL)) LIB$SIGNAL(kbd_r_iosb.status);
X
X
X/* All set up now so start read to mailbox, and PYDEVICE */
X
Vstatus = SYS$QIO (0, mbx_chan, IO$_READVBLK, &mbx_iosb, &read_mbx_ast, 0, &mbx_
Xbuff[0],
X`009`009  sizeof(mbx_buff), 0, 0, 0, 0);
X
Vstatus = SYS$QIO (0, py_chan, IO$_READVBLK, &py_r_iosb, &py_read_ast, 0, &py_r_
Xbuff[0],
X`009`009  sizeof(py_r_buff), 0, 0, 0, 0);
X
X
X/* Set up XON, XOFF, and set line ASTs */
X
Vstatus = SYS$QIOW(py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, xon_ast, 0,
X 0, 1, 0, 0);
Vstatus = SYS$QIOW(py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, xoff_ast, 0
X, 0, 2, 0, 0);
Vstatus = SYS$QIOW(py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, set_line_as
Xt, 0, 0, 3, 0, 0);
X
X
V/* Now the real magic begins we get a read going to the terminal in an infinite
X loop */
X
X
Xprintf("\n\nTo exit use CTRL-@\n\n");
Xdummy.dsc$a_pointer = &kbd_r_buff[0];
X
Xwhile (1)
X{
X
V  status = SYS$QIOW (kbd_r_efn, kbd_chan, IO$_READVBLK, &kbd_r_iosb, 0, 0, &kbd
X_r_buff[0], 1,
X`009`009     0, &term_block, 0, 0);
X  if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
X  /* Stall for 50 milli-seconds waiting for more data */
X
X  status = SYS$SETIMR (wait_efn, &bintim, 0, 0);
X  if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X  status = SYS$WAITFR(wait_efn);
X  if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X
X
X  /* Now pick up any more user data */
X
V  status = SYS$QIOW (kbd_r_efn, kbd_chan, IO$_READVBLK | IO$M_TIMED, &kbd_r_ios
Xb, 0, 0, &kbd_r_buff[1],
X`009`009     (sizeof(kbd_r_buff)-1), 0, &term_block, 0, 0);
X  if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X  dummy.dsc$w_length = 1 + kbd_r_iosb.byte_cnt;
X
X
X  /* Go ahead and try and input a character */
X
X
X  length = dummy.dsc$w_length;
X  do
X  {
X    status = SYS$QIOW(py_w_efn, py_chan, IO$_WRITEVBLK, &py_w_iosb, 0, 0,
X`009`009      &kbd_r_buff[0], length, 0, 0, 0, 0);
X    if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X    if ((py_w_iosb.status == SS$_DATAOVERUN) && (py_w_iosb.byte_cnt < length))
X    {
X      if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X      status = SYS$WAITFR(xoff_efn);
X      if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X      status = SYS$SETAST(0);
X      if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X      status = SYS$CLREF(xoff_efn);
X      if (!(status & SS$_NORMAL)) LIB$SIGNAL(status);
X      status = SYS$SETAST(1);
X      length = length - py_w_iosb.byte_cnt;
X    }
V    else if ((py_w_iosb.status == SS$_NORMAL) || (py_w_iosb.status == SS$_DATAO
XVERUN))
X    {
X      break;
X    }
X    else
X    {
X      LIB$SIGNAL(py_w_iosb.status);
X    }
X
X  } while (py_w_iosb.status != SS$_NORMAL);
X
X  status = LIB$MATCHC(&null_char, &dummy);
X  if (status) LIB$SIGNAL(SS$_HANGUP);
X}
X
X}
X`012
X/* Simple exit handler routine to reset terminal characteristics */
X
X
Xexit_handler()
X{
Xint`009`009status;
X
Xstruct`009iosb`009exit_iosb;
X
X
Vstatus = SYS$QIOW(kbd_s_efn, kbd_chan, IO$_SETMODE, &exit_iosb, 0, 0, &saved_ch
Xar, 12,
X`009`009  0, 0, 0, 0);
Xif (!(status & SS$_NORMAL)) printf("Error resetting terminal reason is %9X");
X
X}
X`012
X/* This routine will read the termination mailbox and report it to user */
Xread_mbx_ast()
X{
Xint`009`009status;
X
X
X/* Indicate if read mailbox & if successful */
Xif (mbx_iosb.status & SS$_NORMAL)
X{
X  printf("\n\nTermination mailbox message received form TW device!!\n\n");
X}
Xelse
X{
X  printf("\n\nTermination maibox read with error %9X\n\n", mbx_iosb.status);
X}
X
X
X/* Reset read to termination mailbox */
X
Vstatus = SYS$QIOW(0, mbx_chan, IO$_READVBLK, &mbx_iosb, &read_mbx_ast, 0, &mbx_
Xbuff[0],
X`009`009  sizeof(mbx_buff), 0, 0, 0, 0);
Vif (!(status & SS$_NORMAL)) printf("\n\nError setting up MBX read reason is %9X
X\n\n");
X
X}
X
X
X`012
X/* This routine will write to the terminal data read from the PY device */
Xpy_read_ast()
X{
Xint`009`009kbd_write_ast();
Xint`009`009status;
X
Xif (!(py_r_iosb.status & SS$_NORMAL))
X{
X  printf("\n\nError reading from PY device program exiting!!!\n\n");
X  LIB$SIGNAL(py_r_iosb.status);
X}
X
Vstatus = SYS$QIO(0, kbd_chan, IO$_WRITEVBLK, &kbd_w_iosb, &kbd_write_ast, 0, &p
Xy_r_buff[0], py_r_iosb.byte_cnt, 0, 0, 0, 0);
X
Xif (!(status & SS$_NORMAL))
X{
X  printf("\n\nError writing PY data to terminal program exiting!!!\n\n");
X  LIB$SIGNAL(status);
X}
X
X}
X
X
X`012
V/* This rouinte gets called when the write to the terminal finishes. It restart
Xs the read on the PYDEVICE. */
Xkbd_write_ast()
X{
Xint`009`009status;
X
Vstatus = SYS$QIO (0, py_chan, IO$_READVBLK, &py_r_iosb, &py_read_ast, 0, &py_r_
Xbuff[0], sizeof(py_r_buff), 0, 0, 0, 0);
X
Xif (!(status & SS$_NORMAL))
X{
X  printf("\n\nError reading from PY program exiting!!!\n\n");
X  LIB$SIGNAL(status);
X}
X
X}
X`012
V/* This routine will signal when an XOFF AST is delivered it resets AST and rep
Xorts character that is delivered */
Xxoff_ast(param)
Xint`009`009param;
X{
Xchar`009`009buffer[40];
X
Xshort int`009signal_char;
X
Xint`009`009len;
Xint`009`009status;
X
X
Vstatus = SYS$QIOW (py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, &xoff_ast,
X 0, 0, 2, 0, 0);
Xif (!(status & SS$_NORMAL))
X{
X  printf("Error enabling XOFF ast on PYDEVICE");
X  LIB$SIGNAL(status);
X}
Xif (!(py_s_iosb.status & SS$_NORMAL))
X{
X  printf("Error enabling XOFF ast on PYDEVICE");
X  LIB$SIGNAL(py_s_iosb.status);
X}
X
Xif (info_flag)
X{
X  signal_char = (short int) (param >> 16);
V  len =  sprintf(buffer, "\015\012Received XOFF character: %2X\015\012", signal
X_char);
V  status = SYS$QIO(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0],
X len, 0, 0, 0, 0);
X}
X
X}
X`012
V/* This routine will signal when an XON AST is delivered it resets AST and repo
Xrts character that is delivered */
Xxon_ast(param)
Xint`009`009param;
X{
Xchar`009`009buffer[40];
X
Xshort int`009signal_char;
X
Xint`009`009len;
Xint`009`009status;
X
Xstatus = SYS$SETEF(xoff_efn);
X
Vstatus = SYS$QIOW (py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, &xon_ast, 
X0, 0, 1, 0, 0);
Xif (!(status & SS$_NORMAL))
X{
X  printf("Error enabling XON ast on PYDEVICE");
X  LIB$SIGNAL(status);
X}
Xif (!(py_s_iosb.status & SS$_NORMAL))
X{
X  printf("Error enabling XON ast on PYDEVICE");
X  LIB$SIGNAL(py_s_iosb.status);
X}
X
Xif (info_flag)
X{
X  signal_char = (short int) (param >> 16);
V  len =  sprintf(buffer, "\015\012Received XON character: %2X\015\012", signal_
Xchar);
V  status = SYS$QIO(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0],
X len, 0, 0, 0, 0);
X}
X
X}
X`012
X/* This routine will signal when an XON AST is delivered it resets AST */
Xset_line_ast()
X{
Xchar`009`009buffer[80];
X
Xint`009`009len;
Xint`009`009status;
X
Xstruct`009devchar`009current_char;
Xstruct`009devchar`009perm_char;
X
Vstatus = SYS$QIOW (py_s_efn, py_chan, IO$_SETMODE, &py_s_iosb, 0, 0, &set_line_
Xast, 0, 0, 3, 0, 0);
Xif (!(status & SS$_NORMAL))
X{
X  printf("Error enabling set line ast on PYDEVICE");
X  LIB$SIGNAL(status);
X}
Xif (!(py_s_iosb.status & SS$_NORMAL))
X{
X  printf("Error enabling set line ast on PYDEVICE");
X  LIB$SIGNAL(py_s_iosb.status);
X}
X
Xif (info_flag);
X{
V  status = SYS$QIOW(py_s_efn, py_chan, IO$_SENSEMODE, &py_s_iosb, 0, 0, &curren
Xt_char, 12, 0, 0, 0, 0);
X  if (!(status & SS$_NORMAL))
X  {
X    printf("Error reading current characteristics on PYDEVICE");
X    LIB$SIGNAL(status);
X  }
X  if (!(py_s_iosb.status & SS$_NORMAL))
X  {
X    printf("Error reading current characteristics on PYDEVICE");
X    LIB$SIGNAL(py_s_iosb.status);
X  }
X
X  len = sprintf(buffer,"\015\012 Current device characteristics \015\012");
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X  len = sprintf(buffer,"Device class:        %8X\015\012",current_char.class);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X  len = sprintf(buffer,"Devic type:          %8X\015\012",current_char.type);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
V  len = sprintf(buffer,"Buffer size:         %8X\015\012",current_char.buffer_s
Xize);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
V  len = sprintf(buffer,"Basic chars & witdh:%8X\015\012",current_char.basic_cha
Xr);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
V  len = sprintf(buffer,"Extended chars.:     %8X\015\012",current_char.extended
X_char);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X
V  status = SYS$QIOW(py_s_efn, py_chan, IO$_SENSECHAR, &py_s_iosb, 0, 0, &perm_c
Xhar, 8, 0, 0, 0, 0);
X  if (!(status & SS$_NORMAL))
X  {
X    printf("Error reading current characteristics on PYDEVICE");
X    LIB$SIGNAL(status);
X  }
X  if (!(py_s_iosb.status & SS$_NORMAL))
X  {
X    printf("Error reading current characteristics on PYDEVICE");
X    LIB$SIGNAL(py_s_iosb.status);
X  }
X
X  len = sprintf(buffer,"\015\012Permanent device characteristics \015\012");
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X  len = sprintf(buffer,"Device class:        %8X\015\012",perm_char.class);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X  len = sprintf(buffer,"Devic type:          %8X\015\012",perm_char.type);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
V  len = sprintf(buffer,"Buffer size:         %8X\015\012",perm_char.buffer_size
X);
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
V  len = sprintf(buffer,"Basic chars & witdh: %8X\015\012",perm_char.basic_char)
X;
V  status = SYS$QIOW(0, info_chan, IO$_WRITEVBLK, &info_w_iosb, 0, 0, &buffer[0]
X, len, 0, 0, 0, 0);
X
X}
X
X}
$ GOSUB UNPACK_FILE
$ FILE_IS = "PYDRIVER.MAR"
$ CHECKSUM_IS = 576816862
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.TITLE`009PYDRIVER - Pseudo terminal driver interface
X`009.IDENT 'V05-007A'
X
X;++
X; FACILITY:
X;
X;`009VAX/VMS Pseudo Terminal Driver interface
X;
X; ABSTRACT:
X;
X;`009The pseudo terminal consists of two devices.
X;`009This is the non terminal part of the two devices.
X;
X; AUTHOR:
X;
X;`00919-Nov-1982`009Dale Moore`009Redid the TW driver for VMS 3.0
X;
X;`009This program has been granted to the public domain by the author.
X;
X; Revision History:
X;
X;`009Version 'V03-001'
X;`009`009DWM`009- Added Page seperators
X;`009`009`009- On Last cancel, invoke hangup on TW device
X;`009`009`009- changed PY_STOP and PY_STOP2 to return instead
X;`009`009`009  of looping for more.
X;`009`009`009- Changed last cancel to call ioc$reqcom instead of
X;`009`009`009  using macro REQCOM which is a branch ioc$reqcom.
X;`009Version V03-002`009- Changed to Clear word rather than clear byte
X;`009`009`009  in startio routine on word field.
X;
X;`009Version V03-003 (Thu Dec  9 12:42:38 1982) D. Kashtan
X;`009`009`009  Made into a TEMPLATE driver.
X;`009Version V03-004 (Fri Dec 10 11:40:35 1982) D. Kashtan
X;`009`009`009  Made EXE$... into +EXE$... in FDT dispatch table,
X;`009`009`009  fixing bug that crashed system in SET/SENSE MODE/CHAR
X;`009Version V03-005`009(14-Jun-1983) Dale Moore
X;`009`009`009  Add R4 to calls to IOC$INITIATE.
X;`009`009`009  TTY$STARTIO mucks R4
X;`009Version V03-006`009(12-Jul-1983) Mark London, MIT Plasma Fusion Center
X;`009`009`009- Set terminal to NOBROADCAST when no READ QIO avail-
X;`009`009`009  able so as to allow Broadcasts without hanging up.
X;`009`009`009  (When no QIO available, UCB$M_INT is enabled, and
X;`009`009`009  the Broadcast don't get handled.  The sender of a
X;`009`009`009  Broadcast goes into a wait state until the broadcast
X;`009`009`009  is completed or timed-out, neither or which can
X;`009`009`009  happen.  Setting NOBROADCASTs at least allow the
X;`009`009`009  Broadcast to finish. What is needed is a CTRLS state
X;`009`009`009  that doesn't allow Broadcasts to break through.)
X;`009`009`009- Added MOVC3 instruction for burst data in PY$STARTIO,
X;`009`009`009  which "should" speed up the transfers.
X;`009`009`009- Fixed data transfer problem by raising to fork IPL
X;`009`009`009  while calling PUTNXT in PY$FDTWRITE. NOTE: TWA0 must
X;`009`009`009  be a mailbox to avoid TT reads from timing out.
X;
X;`009Version V04-001 - Doug Davis, Digital Equipment
X;`009`009`009- Most of the changes required for migration to
X;`009`009`009  Version 4.0 relate to the new handling of UCB
X;`009`009`009  creation and deletion. This includes adding
X;`009`009`009  a CLONEDUCB entry point to the dispatch table,
X;`009`009`009  and "cloning" the UNITINIT routine to handle the
X;`009`009`009  required entry. Also changed the call from
X;`009`009`009  IOC$CREATE_UCB to IOC$CLONE_UCB, with associated
X;`009`009`009  maintainence of the UCB$V_DELETEUCB bit in the
X;`009`009`009  UCB$L_STS field.
X;`009`009`009- Changes were also incorporated reflecting new
X;`009`009`009  methods of  XON/XOFF flow control.
X;`009`009`009- Although pieces of the original code have been
X;`009`009`009  superceded by these changes ( example - functions
X;`009`009`009  that were performed by Unit_Init for new units
X;`009`009`009  are are now performed by Clone_Init ), most of
X;`009`009`009  the original code was left in place and/or commented
X;`009`009`009  out.
X;
X;`009`009`009NOTE - No subroutines preambles were modified to
X;`009`009`009       reflect these changes.
X;
X;`009Version V04-002`009(20-Jan-1985) Mark London, MIT Plasma Fusion Center
X;`009`009`009- Changed test for output characters after call to
X;`009`009`009  UCB$L_TT_PUTNXT and UCB$L_TT_GETNXT.  Output is
X;`009`009`009  indicated in UCB$B_TT_OUTYPE.
X;
X;`009Version V04-003 (24-Jun-1985) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Cleaned this thing up quite a bit.
X;`009`009`009- Got rid of MBX characteristic on the devices.  This
X;`009`009`009  was a holdover to before cloned devices really
X;`009`009`009  existed.
X;`009`009`009- Got rid of the UNIT_INIT routine completely.  This
X;`009`009`009  was replaced by a CLONE_UCB routine.
X;`009`009`009- Leave the PY template device OFFLINE.  This is what
X;`009`009`009  other TEMPLATE devices do, to indicate that you
X;`009`009`009  really cannot do I/O to the template.
X;`009`009`009- Rewrote the CANCEL_IO routine to issue a DISCONNECT
X;`009`009`009  on the TW device at last deassign of the PY device.
X;`009`009`009  This causes the TW device to hangup on it's process.
X;`009`009`009  Works quite nicely with VMS V4 connect/disconnect
X;`009`009`009  mechanism.  Also, the devices should never stay
X;`009`009`009  around after last deassign on the PY, if you want to
X;`009`009`009  reconnect, count on VMS connect/disconnect instead,
X;`009`009`009  it's much less of a security hole.
X;`009`009`009- Got rid of all modem operations.  Improper use tended
X;`009`009`009  to crash the system and they are not necessary.  TW
X;`009`009`009  device is always NOMODEM.  HANGUP works as you want
X;`009`009`009  it to without the modem stuff.
X;`009`009`009- Got rid of the BRDCST on/off stuff.  It doesn't seem
X;`009`009`009  to be necessary any more.  It also had a bug in it
X;`009`009`009  somewhere that caused the terminal to start off
X;`009`009`009  NOBRDCST when it shouldn't.
X;`009`009`009- General house-cleaning.  Got rid of commented out
X;`009`009`009  lines from VMS V3 version.  Fixed up typos in
X;`009`009`009  comments.
X;
X;`009Version V04-004 (10-Feb-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Changed all references to PTDRIVER to TPDRIVER because
X;`009`009`009DEC (bless their little hearts) invented the *#&#$&
X;`009`009`009TU81 and use PTA0: now.
X;
X;`009Version V04-005 (3-Sep-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Fixed bug whereby the sequence ^S followed by ^Y
X;`009`009`009would cause a system hang.  The fix is really in
X;`009`009`009TWDRIVER.
X;
X;`009Version V04-006 (5-Dec-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Fixed the infamous character munging bug.  Turns
X;`009`009`009out that in FDTWRITE we were enabling interrupts
X;`009`009`009after doing the PUTNXT and before checking for
X;`009`009`009a char.  Now check for the character and then
X;`009`009`009ENBINT after we've decided what to do.  I assume
X;`009`009`009UCB$B_TT_OUTYPE field was getting corrupted.
X;
X;`009Version V04-007 (10-JUL-1987) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Fix in TWDRIVER for timeouts.  Don't bother
X;`009`009`009clearing the TIM bit all the time in here now.
X;
X;`009`009`009Also, while we're in here, lets make the device
X;`009`009`009acquire "NODE$" prefixes, since mailboxes do.
X;
X;`009Version V04-008`009(2-NOV-1987) Kevin Carosso, Network Research Co.
X;`009`009`009In PY$FDTWRITE we were overwriting the status in
X;`009`009`009R0 just before jumping to EXE$ABORTIO when something
X;`009`009`009goes wrong.  Don't POPR into R0, but into R1.  We
X;`009`009`009only care about what we POPR into R3 anyway.
X;
X;`009`009`009Fix thanks to Gerard K Newman @ San Diego
X;`009`009`009Supercomputer Center.
X;
X;`009Version V05-001 Digital Equipment Corp.
X;`009`009`009Add support for Symmetric Multiprocessing.
X;
X;`009Version`009V05-002`009Digital Equipment Corp.
X;`009`009`009Modify PY$CLONE_INIT to make newly cloned
X;`009`009`009owned by person requesting new device.
X;
X;`009Version`009V05-003`009Digital Equipment Corp.
X;`009`009`009Modify PY$CLONE_INIT to change device protection
X;`009`009`009to be S:RWLP,O:RWLP.
X;
X;`009Version`009V05-004`009Digital Equipment Corp
X;`009`009`009Change TP driver names to TW. (TP driver it turns
X;`009`009`009out, conflicted with the VAX/PSI terminal driver.)
X;`009`009`009TWDRIVER and PYDRIVER are now registered with SQM
X;`009`009`009so there will be no more conflicts.
X;
X;`009Version`009V05-005 Digital Equipment Corp
X;`009`009`009If input stopped then exit PY$FDTWRITE immediately
X;`009`009`009with reason of SS$_DATAOVERUN.  If we detect input
X;`009`009`009stopping while inserting data return with
X;`009`009`009SS$_DATAOVERUN and number of bytes inserted.
X;
X;`009Version V05-006`009Digital Equipment Corp.
X;`009`009`009Add CODE for sending an AST if PORT XON, PORT XOFF,
X;`009`009`009and PORT SET_LINE routines are called.  Also add
X;`009`009`009SENSEMODE, and SENSECHAR routine for reading TW device
X;`009`009`009characteristics.
X;
X;`009Version V05-006A Kevin Carosso @ Network Research Co.
X;`009`009`009Conditionalize assembly for VMS V4 or V5.  There
X;`009`009`009is a magic symbol at the top that is commented
X;`009`009`009out for VMS V5.
X;
X;`009Version V05-007A Kevin Carosso @ Network Research Co.
X;`009`009`009Add a missing # on an immediate.
X;`009`009`009Modify PY$FDTWRITE to allow writes larger than
X;`009`009`00964K by using longword rather than word instructions.
X;`009`009`009Make the conditional assembly for VMS V5 automatic
X;`009`009`009driven off existence of SS$_INVLICENSE.
X;
X;--
X`012
X`009.PAGE
X`009.SBTTL`009Declarations
X
X`009.LIBRARY`009/SYS$LIBRARY:LIB.MLB/
X
X;
X; External Definitions:
X;
X.NOCROSS
X`009$CRBDEF`009`009`009`009; Define CRB
X`009$CANDEF`009`009`009`009; Define cancel codes
X`009$DDBDEF`009`009`009`009; DEFINE DDB
X`009$DDTDEF`009`009`009`009; DEFINE DDT
X`009$DEVDEF`009`009`009`009; DEVICE CHARACTERISTICS
X`009$DYNDEF`009`009`009`009; Dynamic structure definitions
X`009$IODEF`009`009`009`009; I/O Function Codes
X`009$IRPDEF`009`009`009`009; IRP definitions
X`009$JIBDEF`009`009`009`009; Define JIB offsets
X`009$ORBDEF`009`009`009`009; Define ORB offsets
X`009$PCBDEF`009`009`009`009; Define PCB
X`009$PRDEF`009`009`009`009; Define PR
X`009$SSDEF`009`009`009`009; DEFINE System Status
X;
X; If SS$_INVLICENSE exists, we must be building on V5.  Go ahead and
X; define our conditionals so we can build a V5 driver.
X;
X.IF`009DEFINED`009SS$_INVLICENSE
X`009VMS_V5 = 1
X`009.PRINT`009`009; PYDRIVER -- Building VMS V5 compatible driver
X.IF_FALSE
X`009.PRINT`009`009; PYDRIVER -- Building VMS V4 compatible driver
X.ENDC
X
X.IF`009DEFINED`009VMS_V5
X`009$SPLCODDEF`009`009`009; Spin lock code definitions
X.ENDC
X
X`009$TTDEF`009`009`009`009; DEFINE TERMINAL TYPES
X`009$TT2DEF`009`009`009`009; Define Extended Characteristics
X`009$TTYDEF`009`009`009`009; DEFINE TERMINAL DRIVER SYMBOLS
X`009$TTYDEFS`009`009`009; DEFINE TERMINAL DRIVER SYMBOLS
X`009$TTYMACS`009`009`009; DEFINE TERMINAL DRIVER MACROS
X`009$UCBDEF`009`009`009`009; DEFINE UCB
X`009$VECDEF`009`009`009`009; DEFINE VECTOR FOR CRB
X.CROSS
X
X;
X; Local definitions
X;
X; QIO Argument list offsets
X;
XP1 = 0
XP2 = 4
XP3 = 8
XP4 = 12
XP5 = 16
XP6 = 20
X;
X; New device class for control end
X;
XDC$_PY = ^XFF
XDT$_PY = 0
X
X;
X; Definitions that follow the standard UCB fields for TW driver
X;  This will all probably have to be the same as the standard term
X
X`009$DEFINI`009UCB`009`009`009; Start of UCB definitions
X
X`009.=UCB$K_TT_LENGTH`009`009; Position at end of UCB
X
X$DEF`009UCB$L_TW_XUCB`009.BLKL`0091`009; UCB of corresponding
X`009`009`009`009`009;  control/application unit
X`009`009`009`009`009; call
X$DEF`009UCB$L_TW_XON_AST .BLKL`0091`009; AST list for XON event notification
X$DEF`009UCB$L_TW_XOFF_AST .BLKL`0091`009; AST list for XOFF event notification
X$DEF`009UCB$L_TW_SET_AST .BLKL`0091`009; AST list for notification of SET_LINE
X$DEF`009UCB$K_TW_LEN`009`009`009; Size of UCB
X
X`009$DEFEND`009UCB`009`009`009; End of UCB definitions
X
X;
X; Definitions that follow the standard UCB fields in PY devices
X;
X
XBUFFER_SIZE = 32
X
X`009$DEFINI UCB`009`009`009; Start of UCB definitions
X `009.=UCB$K_LENGTH`009`009`009; position at end of UCB
V$DEF`009UCB$L_PY_XUCB`009.BLKL 1`009`009; UCB of terminal part of pseudo termin
Xal
V$DEF`009UCB$T_PY_BUFFER`009.BLKB`009BUFFER_SIZE ; Buffer to store characters to
X be transmitted
X$DEF`009UCB$K_PY_LEN`009`009`009; Size of UCB
X
X `009$DEFEND UCB`009`009`009; end of UCB definitions
X`012
X`009.PAGE
X;
X; LOCAL Storage
X;
X`009.PSECT $$$105_PROLOGUE
X
X`009.SBTTL`009Standard Tables
X
X;
X; Driver prologue table:
X;
XPY$DPT::
X`009DPTAB`009-`009`009`009; Driver Prologue table
X`009`009END = PY$END,-`009`009; End and offset to INIT's vectors
X`009`009UCBSIZE = UCB$K_PY_LEN,-; Size of UCB
X`009`009FLAGS=DPT$M_NOUNLOAD,-`009`009; Don't allow unload
X`009`009ADAPTER=NULL,-`009`009`009; ADAPTER TYPE
X`009`009NAME`009= PYDRIVER`009`009; Name of driver
X`009DPT_STORE INIT
X`009DPT_STORE UCB,UCB$W_UNIT_SEED,W,0`009; SET UNIT # SEED TO ZERO
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DPT_STORE UCB,UCB$B_FIPL,B,8 `009`009; FORK IPL
X.IF_FALSE
X`009DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ; FORK LOCK
X.ENDC
X
X`009DPT_STORE UCB,UCB$W_STS,W,-`009`009; TEMPLATE device
X`009`009`009<UCB$M_TEMPLATE>
X`009DPT_STORE UCB,UCB$L_DEVCHAR,L,<-`009; Characteristics
X`009`009`009DEV$M_REC!-`009`009;   record oriented
X`009`009`009DEV$M_AVL!-`009`009;   available
X`009`009`009DEV$M_IDV!-`009`009;   input device
X`009`009`009DEV$M_ODV>`009`009;   output device
X`009DPT_STORE UCB,UCB$L_DEVCHAR2,L, -`009`009; Device characteristics
X`009`009`009<DEV$M_NNM>`009`009`009; prefix with "NODE$"
X`009DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_PY
X`009DPT_STORE UCB,UCB$B_DIPL,B,8`009`009; Device IPL = FIPL (no device)
X`009DPT_STORE DDB,DDB$L_DDT,D,PY$DDT
X
X`009DPT_STORE REINIT
X`009DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,D,PY$INITIAL`009; Controller
X`009DPT_STORE END
X`012
X`009.PAGE
X`009.SBTTL Driver Dispatch table and function decision table
X;
X; Driver Dispatch table
X;
X`009DDTAB`009DEVNAM`009= PY,-`009`009`009; Device name
X`009`009START`009= PY$STARTIO,-`009`009; Start I/O routine
X`009`009FUNCTB`009= PY$FUNCTAB,-`009`009; The function table
X`009`009CANCEL`009= PY$CANCEL,-`009`009; the cancel i/o routine
X`009`009CLONEDUCB = PY$CLONE_INIT`009; Entry when template cloned.
X;
X; Function Decision table for PY devices
X;
XPY$FUNCTAB:
X`009FUNCTAB`009,-`009`009`009; Legal Functions
X`009`009<READLBLK,-
X`009`009WRITELBLK,-
X`009`009READVBLK,-
X`009`009WRITEVBLK,-
X`009`009READPBLK,-
X`009`009WRITEPBLK,-
X`009`009SETMODE,-
X`009`009SETCHAR,-
X`009`009SENSEMODE,-
X`009`009SENSECHAR,-
X`009`009>
X`009FUNCTAB`009,-`009`009`009; Buffered I/O functions
X`009`009<READLBLK,-
X`009`009WRITELBLK,-
X`009`009READVBLK,-
X`009`009WRITEVBLK,-
X`009`009READPBLK,-
X`009`009WRITEPBLK,-
X`009`009>
X`009FUNCTAB`009PY$FDTREAD,<READLBLK,READVBLK,READPBLK>
X`009FUNCTAB PY$FDTWRITE,<WRITELBLK,WRITEVBLK,WRITEPBLK>
X`009FUNCTAB PY$FDTSET,<SETMODE,SETCHAR>
X`009FUNCTAB PY$FDTSENSEM,<SENSEMODE>
X`009FUNCTAB`009PY$FDTSENSEC,<SENSECHAR>
X
X
X`009.SBTTL`009Local Storage - Name of companion device
X
XTWSTRING:`009.ASCII`009/TWA/
XTWLENGTH = . - TWSTRING
X`012
X`009.PAGE
X`009.SBTTL`009PY$FDTREAD - Function decision routine for PY control read
X;++
X; PY$FDTREAD
X;
X; Functional Description:
X;
X;`009This routine is called from the function decision table dispatcher
X; `009to process a read physical, read logical, read virtual I/O function.
X;
X;`009The function first verifies the caller's parameters, terminating
X;`009the request with immediate success or error if necessary.
X;`009A system buffer is allocated and its
X;`009address is saved in the IRP.  The caller's quota is updated, and
X;`009the read request is queued to the driver for startup.
X;
X; Inputs:
X;
X;`009R0,R1,R2`009= Scratch
X;`009R3`009`009= IRP Address
X;`009R4`009`009= Address of PCB for current process
X;`009R5`009`009= Device UCB address
X;`009R6`009`009= Address of CCB
X;`009R7`009`009= I/O function code
X;`009R8`009`009= FDT Dispatch addr
X;`009R9,R10,R11`009= Scratch
X;`009AP`009`009= Address of function parameter list
X;`009`009`009P1(AP) = Buffer Address
X;`009`009`009P2(AP) = Buffer Size
X;
X; Outputs:
X;
X;`009R0,R1,R2,R11`009= Destroyed
X;`009R3-R10,AP`009= Preserved (pickled)
X;`009IRP$L_SVAPTE(R3)= Address of allocated system buffer
X;`009IRP$W_BOFF(R3)`009= Requested byte count
X;
X;`009System Buffer:
X;`009`009LONGWORD/0`009= Address of start of data= buff+12
X;`009`009LONGWORD/1`009= Address of user buffer
X;
X;--
XPY$FDTREAD::
X`009MOVZWL`009P2(AP),R1`009; Get buffer Size
X`009BNEQ`00915$
X`009JMP`00910$`009`009; Is the size zero? If so, go do it easy.
X15$:`009MOVL`009P1(AP),R0`009; Get buffer Address
X`009JSB`009G^EXE$READCHK`009; Do we have access to the buffer
X`009PUSHR`009#^M<R0,R3>`009; Save user buffer address and IRP address
X`009ADDL`009#12,R1`009`009; Add 12 bytes for buffer header
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009JSB`009G^EXE$BUFFRQUOTA`009; Is there enough buffer space left in
X`009`009`009`009`009;  the quota?
X`009BLBC`009R0, 30$`009`009`009; Branch if insufficient quota
X`009JSB`009G^EXE$ALLOCBUF`009`009; Allocate a system buffer
X.IF_FALSE
V`009JSB`009G^EXE$DEBIT_BYTCNT_ALO `009; Verify enough byte quota allocate buffe
Xr
X`009`009`009`009`009; and charge process for useage
X.ENDC
X
X`009BLBC`009R0,30$`009`009`009; If error report it
X`009POPR`009#^M<R0,R3>`009`009; Restore user buffer and irp address
X`009MOVL`009R2,IRP$L_SVAPTE(R3)`009; Save address of buffer
X`009MOVW`009R1,IRP$W_BOFF(R3)`009;  and requested byte count
X`009MOVZWL`009R1,R1`009`009`009; convert to longword count
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009MOVL`009PCB$L_JIB(R4),R11`009; Get Jib address
X`009SUBL`009R1,JIB$L_BYTCNT(R11)`009; Adjust quota count
X.ENDC
X
X`009MOVAB`00912(R2),(R2)`009`009; Save addr of start of user data
X`009MOVL`009R0,4(R2)`009`009; Save user buffer address in 2nd
X`009`009`009`009`009; longword
X`009JMP`009G^EXE$QIODRVPKT`009; Queue I/O packet to start I/O routine
X;
X; Did he request a read of zero bytes?
X;
X10$:`009MOVL`009#SS$_NORMAL,R0`009`009; Everything is ok
X`009JMP`009G^EXE$FINISHIOC`009`009; complete I/O request
X;
X; Come here when something goes wrong
X;
X30$:`009POPR`009#^M<R1,R3>`009`009; Clear buffer addr and restore IRP
X`009JMP`009G^EXE$ABORTIO`009`009; complete I/O request
X`012
X`009.PAGE
X`009.SBTTL`009PY$FDTWRITE - Function decision routine for PY control write
X;++
X; PY$FDTWRITE
X;
X; Functional Description:
X;
X;`009This routine is called from the function decision table dispatcher
X; `009to process a write physical, write logical, write virtual I/O
X;`009function.
X;
X;`009The function first verifies the caller's parameters, terminating
X;`009the request with immediate success or error if necessary.
X;`009The routine then immediately start cramming the characters into
X;`009the associated units typeahead buffer by calling putnxtchr.
X;
X; Inputs:
X;
X;`009R0,R1,R2`009= Scratch
X;`009R3`009`009= IRP Address
X;`009R4`009`009= Address of PCB for current process
X;`009R5`009`009= Device UCB address
X;`009R6`009`009= Address of CCB
X;`009R7`009`009= I/O function code
X;`009R8`009`009= FDT Dispatch addr
X;`009R9,R10,R11`009= Scratch
X;`009AP`009`009= Address of function parameter list
X;`009`009P1(AP)`009= Buffer Address
X;`009`009P2(AP)`009= Buffer Size
X;
X; Outputs:
X;
X;`009R0,R1,R2`009= Destroyed
X;`009R3-R7,AP`009= Preserved (pickled)
X;
X;
X;`009N O T E:
X;`009`009This routine now assumes that TW and PY's fork and DEVICE
X;`009locks are the same lock.  This allows use to keep from having to
X;`009do an extra unecessary lock acquisition.
X;
X;
X;
X; External Routines:
X;
X;`009EXE$ABORTIO - FDT abort io routine
X;`009Input Parameters:
X;`009`009R0 - First longword of IOSB
X;`009`009R3 - IRP Address
X;`009`009R4 - PCB Address
X;`009`009R5 - UCB Address
X;
X;`009EXE$FINISHIOC - FDT finish IO routine
X;`009Input Parameters:
X;`009`009R0 - First longword of IOSB
X;`009`009R3 - IRP Address
X;`009`009R4 - PCB Address
X;`009`009R5 - UCB Address
X;
X;`009EXE$WRITECHK - Check access to buffer
X;`009Input Parameters:
X;`009`009R0 - Address of buffer
X;`009`009R1 - Size of buffer
X;`009`009R3 - IRP Address
X;`009Output Parameters:
X;`009`009R0,R1,R3 - Preserved
X;`009`009R2 - clear
X;
X;`009@UCB$L_TT_PUTNXT(R5) - Port driver input character routine
X;`009Input Parameters:
X;`009`009R3 - character
X;`009`009R5 - UCB Address
X;`009Output Parameters:
X;`009`009R3 - if EQL then nothing
X;`009`009     if LSS then Burst address to output
X;`009`009     if GTR then char to output
X;`009`009R5 - UCB Address
X;`009`009R1,R2,R4 - trashed
X;`009`009R0 - Is this trashed or preserved? Documentation say preserve.
X;
X;--
XPY$FDTWRITE::
X`009MOVZWL`009P2(AP),R1`009`009; Get buffer Size
X`009BNEQ`00910$`009`009`009; Is the non zero? If so, do it easy.
X`009BRW`009160$`009`009`009; Zero size buffer just finish it now
X
X10$:
X`009MOVL`009P1(AP),R0`009`009; Get buffer Address
X`009JSB`009G^EXE$WRITECHK`009`009; Do we have access to the buffer
X`009`009`009`009`009; No return means no access
X`009MOVL`009R1,R9`009`009`009; Number of characters to send
X`009CLRL`009R10`009`009`009; Clear count of characters sent
X`009MOVL`009R5,R11`009`009`009; Save away PY UCB ptr
X`009PUSHR`009#^M<R3,R4,R5>`009`009; Save PCB, IRP,and UCB address
X;
X;`009User request ok.
X;
X;`009R0`009-> `009Address of characters to input
X;`009R5`009->`009Address of TW's UCB
X;`009R8`009->`009Number of characters to send this time
X;`009R9`009->`009Total number of characters to send
X;`009R10`009->`009Numbers of characters already sent
X;`009R11`009->`009Address of Py's UCB
X;
X20$:
X`009SUBL3`009R10,R9,R8`009`009; Get number of characters send
X`009CMPL`009R8,#BUFFER_SIZE`009`009; More data than buffer can hold
X`009BGEQ`00930$`009`009`009; GEQ then use BUFFER_SIZE segment
X`009CMPL`009R8,#1`009`009`009; Test for one byte only
X`009BGTR`00940$`009`009`009; GTR more than one fill up buffer
X`009MOVZBL`009(R0),R3`009`009`009; Move single character into R3
X`009BRB`00960$`009`009`009; Now go ahead and send it
X30$:
X`009MOVC3`009#BUFFER_SIZE,(R0)[R10],-; Store data in UCB buffer
X`009`009UCB$T_PY_BUFFER(R11)`009;
X`009MOVZBL`009#BUFFER_SIZE,R8`009`009; Number of characters in burst
X`009BRB`00950$`009`009`009; Now finish setup for transfer
X40$:
X`009MOVC3`009R8,(R0)[R10],`009-`009; Store data in UCB buffer
X`009`009UCB$T_PY_BUFFER(R11)`009;
X50$:
X`009MOVAB`009UCB$T_PY_BUFFER(R11),R0`009; Get buffer address
X`009MOVZBL`009(R0)+,R3`009`009; Get first character
X60$:
X`009MOVL`009UCB$L_PY_XUCB(R11),R5`009; Get TW's UCB address
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DSBINT`009UCB$B_DIPL(R5)
X.IF_FALSE
X`009DEVICELOCK`009`009-`009; Take device lock for TW device
X`009`009LOCKADDR=UCB$L_DLCK(R5),- ;
X`009`009LOCKIPL=UCB$B_DIPL(R5), - ;
X`009`009SAVIPL=-(SP),`009-`009;
X`009`009PRESERVE=YES`009`009;
X.ENDC
X
X70$:
X`009INCL`009R10`009`009`009; Increment sent character count
X`009JSB`009@UCB$L_TT_PUTNXT(R5)`009; Buffer character
X`009BLSS`00990$`009`009`009; LSS burst
X`009BGTR`009100$`009`009`009; GTR single character
X80$:`009BBS`009#TTY$V_TP_XOFF,`009-`009; See if XOFFED is so then
X`009`009UCB$B_TP_STAT(R5),120$`009; stop input and check for echoed data
X`009DECL`009R8`009`009`009; Decrease number to send in burst
X`009BLEQ`009110$`009`009`009; LEQ block done see if request done
X`009MOVZBL`009(R0)+,R3`009`009; Get next character
X`009BRB`00970$`009`009`009; Send next character
X90$:
X`009BISW`009#TTY$M_TANK_BURST, -`009; Signal burst
X`009`009UCB$W_TT_HOLD(R5)`009;
X`009BRB`00980$`009`009`009; Continue processing
X100$:
X`009MOVB`009R3,UCB$W_TT_HOLD(R5)`009; Store character in tank
X`009BISW`009#TTY$M_TANK_HOLD, -`009; Signal character in tank
X`009`009UCB$W_TT_HOLD(R5)`009;
X`009BRB`00980$`009`009`009; Continue processing
X
X;
X; See if this request is done or if more to do
X;
X110$:
X`009CMPL`009R10,R9`009`009`009; All done
X`009BGEQ`009120$`009`009`009; GEQ done so check for echo
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009ENBINT
X.IF_FALSE
X`009DEVICEUNLOCK`009`009-`009; More in request release lock
X`009`009LOCKADDR=UCB$L_DLCK(R5), - ; and go back and get it
X`009`009NEWIPL=(SP)+,`009-`009;
X`009`009PRESERVE=YES`009`009;
X.ENDC
X
X`009MOVL`009P1(AP),R0`009`009; Restore users buffer address
X`009BRW`00920$`009`009`009;
X
X;
X; See if need to start up pending read
X;
X120$:
X`009BBS`009#TTY$V_TANK_HOLD, -`009; If storing character in hold
X`009`009UCB$W_TT_HOLD(R5),130$`009;  start output
X`009BBC`009#TTY$V_TANK_BURST, -`009; If no output burst then all done
X`009`009UCB$W_TT_HOLD(R5),140$`009;  finish up
X130$:
X`009BBC`009#UCB$V_BSY,`009-`009; PY ready to take data
X`009`009UCB$W_STS(R11),140$`009;
X`009MOVL`009UCB$L_IRP(R11),R3`009; Get IRP address
X`009MOVL`009R11,R5`009`009`009; Get PY UCB address
X`009JSB`009G^IOC$INITIATE`009`009; Now start PY read
X140$:
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009ENBINT
X.IF_FALSE
X`009DEVICEUNLOCK`009`009-`009; Done release lock
X`009`009LOCKADDR=UCB$L_DLCK(R11), - ; NOTE PY & TW lock are the same
X`009`009NEWIPL=(SP)+`009`009;
X.ENDC
X
X`009BBS`009#TTY$V_TP_XOFF,`009-`009; See if XOFFED report this special
X`009`009UCB$B_TP_STAT(R5),170$`009; case
X;
X; Finish up the read
X;
X150$:
X`009POPR`009#^M<R3,R4,R5>`009`009; Restore IRP, PCB, and UCB
X160$:
X`009INSV`009R10,#16,#16,R0`009`009; Move number of bytes INPUT
X`009MOVW`009#SS$_NORMAL,R0`009`009; Everything is just fine
X`009JMP`009G^EXE$FINISHIOC`009`009; Complete the I/O request
X
X;+
X; Special code to deal with input while xoffed.
X;-
X`009TTY$M_TP_XOFF = 8
X`009TTY$V_TP_XOFF = 3
X`009ASSUME`009TTY$M_TP_XOFF EQ TTY$M_TP_DLLOC+4
X`009ASSUME  TTY$V_TP_XOFF EQ TTY$V_TP_DLLOC+1
X
X170$:
X`009POPR`009#^M<R3,R4,R5>`009`009; Restore IRP, PCB, and UCB
X`009INSV`009R10,#16,#16,R0`009`009; Move number of bytes INPUT
X`009MOVW`009#SS$_DATAOVERUN,R0`009; Cannot input more data
X`009JMP`009G^EXE$FINISHIOC`009`009; Complete the I/O request
X`012
X`009.PAGE
X`009.SBTTL`009PY$CANCEL - Cancel the IO on the PY device
X;++
X;
X; Functional Description:
X;
X;`009This routine is entered to stop io on a PY unit.  If this is the last
X;`009deassign on the PY device, issue a CLASS_DISCONNECT on our associated
X;`009TW device to get it away from any processes using it.
X;
X; Inputs:
X;
X;`009R2 = Negative of the Channel Number,
X;`009`009also called channel index number
X;`009R3 = Current IO package address
X;`009R4 = PCB of canceling process
X;`009R5 = UCB Address
X;`009R8 = CAN$C_CANCEL on CANCEL IO or CAN$C_DASSGN on DEASSIGN
X;
X; Outputs:
X;`009Everything should be preserved
X;--
XPY$CANCEL::`009`009`009`009`009; Cancel PY usage
X`009JSB`009G^IOC$CANCELIO`009`009`009; Call the cancel routine
X`009BBC`009#UCB$V_CANCEL,UCB$W_STS(R5),10$`009; Branch if not for this guy
X`009MOVQ`009#SS$_ABORT,R0`009`009`009; Status is request canceled
X`009BICW`009#<UCB$M_BSY!UCB$M_CANCEL>,-`009;
X`009`009UCB$W_STS(R5)`009`009`009; Clear unit status flags
X`009JSB`009G^IOC$REQCOM`009`009`009; Complete request
X10$:`009TSTW`009UCB$W_REFC(R5)`009`009`009; Last Deassign
X`009BNEQ`009100$`009`009`009`009; No, just exit
X;
X; Last DEASSIGN we need to get rid of AST's
X;
X`009pushr`009#^M<r2, r3, r4, r5, r7>
X`009movl`009UCB$L_PY_XUCB(r5), r5`009`009; Switch to TW UCB
X`009beql`00920$`009`009`009`009; if not there, skip
X`009MOVAB`009UCB$L_TW_XON_AST(R5),R7`009`009; Get XON list head address
X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver
X`009BEQL`00911$`009`009`009`009; EQL 0 do not flush it
X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it
X11$:`009MOVAB`009UCB$L_TW_XOFF_AST(R5),R7`009; Get XOFF list head address
X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver
X`009BEQL`00912$`009`009`009`009; EQL 0 do not flush it
X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it
V12$:`009MOVAB`009UCB$L_TW_SET_AST(R5),R7`009`009; Get SET_LINE list head addres
Xs
X`009TSTL`009(R7)`009`009`009`009; Any ast to deliver
X`009BEQL`00913$`009`009`009`009; EQL 0 do not flush it
X`009JSB`009G^COM$FLUSHATTNS`009`009; Flush it
X;
X; Do a DISCONNECT on the TW device.
X;
X13$:
X`009clrl`009UCB$L_TW_XUCB(r5)`009`009; Clear backlink to PY device
X`009bisl2`009#UCB$M_DELETEUCB, UCB$L_STS(r5) ; Set it to go bye-bye
X`009bicw2`009#UCB$M_ONLINE,UCB$W_STS(R5)`009; Mark offline
X`009bicb2`009#UCB$M_INT, UCB$W_STS(r5)`009; Don't expect interrupt
X`009movl`009UCB$L_TT_LOGUCB(r5), r1`009`009; Look at logical term UCB
X`009tstw`009UCB$W_REFC(r1)`009`009`009; See if TW has any references
X`009bneq`00915$`009`009`009`009; If so, go and do disconnect
X`009jsb`009G^IOC$DELETE_UCB`009`009; if not, delete the UCB
X`009brb`00920$
X15$:`009clrl`009r0`009`009`009`009; indicate that we must hangup
X`009movl`009UCB$L_TT_CLASS(r5), r1
X`009jsb`009@CLASS_DISCONNECT(r1)`009`009; Force disconnect
X20$:`009popr`009#^M<r2, r3, r4, r5, r7>`009`009; Switch back to PY UCB
X`009clrl`009UCB$L_PY_XUCB(r5)`009`009; Clear link to deleted TW
X`009bisl2`009#UCB$M_DELETEUCB, UCB$L_STS(r5)`009; Set our own delete bit
X100$:`009rsb
X`012
X`009.PAGE
X`009.SBTTL PY$INITIAL - Initialize Pseudo terminal interface
X
X;++
X; PY$INITIAL - Initialize the interface
X;
X; Functional Description:
X;
X;`009This routine is entered at device connect time and power recovery.
X;`009There isn't much to do to the device.
X;
X; Inputs:
X;
X;`009R4 = The devices CSR  (but there is no csr!)
X;`009R5 = address of IDB
X;`009R6 = address of DDB
X;`009R7 = address of CRB
X;
X; Outputs:
X;
X;`009All registers preserved
X;
X;--
XPY$INITIAL::
X`009RSB
X`012
X`009.PAGE
X`009.SBTTL`009PY$CLONE_INIT - initialize the unit
X;++
X; PY$CLONE_INIT - Initialize new PY device
X;
X; Functional Description:
X;
X;`009Main thing we do here is clone up an associated terminal device
X;`009and initialize fields in the two new UCB's.
X;
X; Inputs:
X;
X;`009R5`009= Address of UCB
X;
X; Outputs:
X;
X;`009All preserved
X;--
X
XPY$CLONE_INIT::
X
X;+ ---
X;`009Ignore inits on UNIT #0 (the template PY UCB)
X;- ---
X`009TSTL`009UCB$W_UNIT(R2)`009`009`009;UNIT #0??
X`009BNEQ`00910$`009`009`009`009;No: Initialize
X`009RSB`009`009`009`009`009;Yes: Return
X
X10$:`009PUSHR`009#^M<R0,R1,R2,R4,R6,R7,R8>
X`009Bicl2`009#UCB$M_DELETEUCB,UCB$L_STS(R2)`009; Clear ucbdelete - dec
X`009Movl`009R2,R5
X;
X; Find the associated device.
X;
X; NOTE: We can't call IOC$SEARCHDEV because it expects the string to
X;`009be accessible from the previous access mode. (It executes the
X;`009prober instruction with mode=#0). I don't know how to make the
X;`009string accessible from the previous access mode cleanly, but I
X;`009do know how to move most of IOC$SEARCHDEV into the py driver.
X;
X`009MOVAL`009G^IOC$GL_DEVLIST-DDB$L_LINK,-`009; Get address of i/o database
X`009`009R8`009`009`009`009; listhead
X`009CLRL`009R6`009`009`009`009; Desired mate = PTY UNIT 0
X`009MOVAB`009L^TWSTRING,R7`009`009`009; String address for TWA
X`009MOVL`009#TWLENGTH,R4`009`009`009; String length
X`009BSBW`009SEARCHDEV`009`009`009; Find the DDB
X`009BNEQ`00920$`009`009`009`009; Device not found
X`009BSBW`009SEARCHUNIT`009`009`009; Search for specific unit
X`009BNEQ`00930$`009`009`009`009; unit found
X20$:`009POPR`009#^M<R0,R1,R2,R4,R6,R7,R8>`009; NOT FOUND: Return
X`009RSB
X
X;
X; Create the PTY, R1 has template UCB of TW device
X;
X30$:`009PUSHL`009R5`009`009`009`009; Save R5
X`009MOVL`009UCB$L_DDB(R5),R0`009`009; Find UNIT #0 UCB FOR PY DEV.
X`009MOVL`009DDB$L_UCB(R0),R0
X`009MOVL`009R1,R5`009`009`009`009; R5 = UCB to CLONE
X`009JSB`009G^IOC$CLONE_UCB`009`009`009; Clone UCB
X
X`009MOVL`009R2,R1`009`009`009`009; Put PTY UCB back into R1
X`009POPL`009R5`009`009`009`009; Restore R5
X`009BLBS`009R0,40$`009`009`009`009; WIN!!! (big deal.)
X;+ ---
X;`009CREATE_UCB failed, mark our PY device offline
X;- ---
X`009BICW2`009#UCB$M_ONLINE,UCB$W_STS(R5)`009; Mark offline
X`009BRW`009100$`009`009`009`009; And return
X;+ ---
X;`009PTY UCB created successfully, link the UCBs together
X;- ---
X40$:`009MOVL`009R1,UCB$L_PY_XUCB(R5)`009`009; Store associated UCB
X`009MOVL`009R5,UCB$L_TW_XUCB(R1)`009`009; Store the other one back
X`009CLRL`009UCB$L_PID(R1)`009`009`009; Clear the owner PID in PTY
X`009CLRW`009UCB$W_REFC(R1)`009`009`009; Reference count is ZERO
X`009Bicl2`009#UCB$M_DELETEUCB,UCB$L_STS(R1)`009; Inhibit deletion
X`009MOVW`009UCB$W_UNIT(R1),-`009`009; Set associated TW unit
X`009`009UCB$L_DEVDEPEND(R5)`009`009; number in PY devdepend
X;+ ---
X;`009Call the PTY unit init routine
X;- ---
X`009MOVL`009UCB$L_DDT(R1),R0`009`009; Get DDT
X`009MOVL`009DDT$L_UNITINIT(R0),R0`009`009; Get Unit Init Addr in DDT
X`009CMPL`009R0,#IOC$RETURN`009`009`009; Null Address??
X`009BNEQ`00950$`009`009`009`009; No: Call it
X`009MOVL`009UCB$L_CRB(R1),R0`009`009; Yes: Look in the CRB
X`009MOVL`009CRB$L_INTD+VEC$L_UNITINIT(R0),R0
X`009BEQL`009100$`009`009`009`009; No: Unit init routine
X
X50$:`009PUSHL`009R5`009`009`009`009; Save R5
X`009MOVL`009R1,R5`009`009`009`009; R5 = PTY UCB
X`009JSB`009(R0)`009`009`009`009; CALL THE UNIT INIT ROUTINE
X`009MOVL`009G^CTL$GL_PCB,R4`009`009`009; Use current PCB
X`009MOVL`009UCB$L_ORB(R5),R0`009`009; Fetch ORB address
X`009MOVL`009PCB$L_UIC(R4),ORB$L_OWNER(R0)`009; Set device owner
V`009BISB`009#ORB$M_PROT_16,ORB$B_FLAGS(R0)`009; Indicate using SOGW device prot
Xection
X`009BICW`009#^XFF,ORB$W_PROT(R0)`009`009; Make device S:O:RWLP
X `009POPL`009R5`009`009`009`009; Restore R5
X
X100$:`009POPR`009#^M<R0,R1,R2,R4,R6,R7,R8>
X`009RSB
X`012
X`009.PAGE
X`009.SBTTL`009DDB finding Routines
X;++
X; SearchDev - Search for device DDB
X;
X; This routine is called to search the device database for a DDB.
X; This is the first step in finding another devices UCB.
X;
X; This routine copied out of IOC$SEARCHDEV in IOSUBPAGD
X;
X; Inputs:
X;
X;`009R8 = DDB Head
X;`009R7 = Address of String
X;`009`009String = ddc format: example = /TTA/
X;`009R4 = Length of string
X;
X; Outputs:
X;
X;`009R8 = DDB of desired device if EQL, otherwise not found
X;`009R0 is trashed
X;`009R1 is trashed
X;--
XSEARCHDEV:`009`009`009`009; Search for device name
X10$:`009MOVL`009DDB$L_LINK(R8),R8`009; Get address of next ddb
X`009BEQL`00920$`009`009`009; If eql end of list
X`009MOVAL`009DDB$T_NAME(R8),R0`009; Get address of generic device name
X`009MOVB`009(R0)+,R1`009`009; Calculate len of string to compare
X`009CMPB`009R1,R4`009`009`009; Length of names match?
X`009BNEQ`00910$`009`009`009; If neq no
X`009CMPC`009R4,(R0),(R7)`009`009; Compare device names
X`009BNEQ`00910$`009`009`009; If neq names do not match
X`009RSB
X20$:`009INCL`009R8`009`009`009; indicate search failure
X`009RSB
X
X`009.SBTTL`009UCB finding routine
X;++
X; SEARCHUNIT - Subroutine to search for UCB given DDB
X;
X; Given the DDB of a device, get the UCB and run down the ucb list until
X; we get the ucb with the desired unit number.  This code is taken out of
X; IOC$SEARCHDEV in IOSUBPAGD.
X;
X; Inputs:
X;
X;`009R8 = DDB of device
X;`009R6 = unit number of desired UCB
X;
X; Outputs:
X;
X;`009R1 = UCB of device if NEQ, otherwise not found
X;`009R0 is trashed
X;
X;--
XSEARCHUNIT:`009`009`009`009; Search for unit number
X`009MOVAL`009DDB$L_UCB-UCB$L_LINK(R8),-
X`009`009R1`009`009`009; Get address of next ucb address
X10$:`009MOVL`009UCB$L_LINK(R1),R1`009; Get Address of next ucb
X`009BEQL`00940$`009`009`009; If EQL then end of list
X`009CMPW`009R6,UCB$W_UNIT(R1)`009; Unit number match?
X`009BEQL`00930$`009`009`009; If eql yes
X`009BRB`00910$
X30$:`009MOVL`009#SS$_NORMAL,R0`009`009; Indicate match
X40$:`009RSB
X`012
X`009.PAGE
X`009.SBTTL`009PY$STARTIO - Device Startio routines
X;++
X; PY$STARTIO`009- Start Input on idle device
X;
X; Functional Description:
X;
X;`009If after the read FDT routines are done and nobody is doing
X;`009anything on the device (UCB$V_BSY = 0) then call the start io
X;`009routine.
X;
X; Called from:
X;
X;`009Called from any one of five places:
X;`009- The EXE$QIODRVPKT in the PY FDT READ routine
X;`009`009which calls EXE$INSIOQ which calls IOC$INITIATE
X;`009- The IOC$REQCOM at the end of this PY startio routine
X;`009`009which calls IOC$INITIATE
X;`009- The TW startio routine which calls IOC$INITIATE
X;`009- The PY write fdt routine which calls IOC$INITIATE.
X;`009`009In case we must echo a character.
X;`009- The PY$RESUME routine which calls IOC$INITIATE.
X;
X; Inputs:
X;
X;`009R3 = IRP Address
X;`009R5 = UCB Address
X;`009`009UCB$W_BCNT and UCB$L_SVAPTE are written by IOC$INITIATE
X;
X; Outputs:
X;
X;`009R5 - UCB Address
X;
X;--
XPY$STARTIO::
X`009.ENABLE LSB
X
X`009MOVL`009@UCB$L_SVAPTE(R5),-`009`009; Initialize buffer
X`009`009UCB$L_SVAPTE(R5)`009`009;  pointers
XPY_OUT_LOOP:
X;
X; Here R5 must point at the PY device UCB and not at
X;  the UCB of the associated TW device.
X;
X5$:`009TSTW`009UCB$W_BCNT(R5)`009`009`009; Any space left in rd packet
X`009BLEQ`00950$`009`009`009`009; No, Completed I/O
X;
X; Switch to terminal UCB
X;
X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009`009; Set to TW ucb
X;
X; Look for next output in state tank
X;
X; Change Case statement to reflect V4 changes in routines - DEC
X;
X10$:`009FFS`009#0,#6,UCB$W_TT_HOLD+1(R5),R3
X`009CASE`009R3,TYPE=B,<-`009`009`009; Dispatch
X`009`009PY_PREMPT,-`009`009`009; Send Prempt Characte - DEC
X`009`009PY_STOP,-`009`009`009; Stop output
X`009`009PY_CHAR,-`009`009`009; Char in tank
X`009`009PY_BURST,-`009`009`009; Burst in progress
X`009`009>
X;
X; No Pending Data - Look for next character
X;
X`009BICB`009#UCB$M_INT, UCB$W_STS(R5)`009; Clear interrupt expected
X;
X; Call class driver for more output
X;
X`009JSB`009@UCB$L_TT_GETNXT(R5)`009; Get the next character
X`009CASEB`009UCB$B_TT_OUTYPE(R5),#-1,#1
X1$:`009.WORD`009PY_START_BURST-1$`009; Burst specified
X`009.WORD`009PY_DONE-1$`009`009; None
X`009BRW`009BUFFER_CHAR`009`009; Buffer the character
X;
X; Output queue exhausted
XPY_DONE:
X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Switch UCBs to PY UCB
X`009BBC`009#UCB$V_BSY,-`009`009; If not BSY then ignore
X`009`009UCB$W_STS(R5),47$`009; the char
X`009MOVL`009UCB$L_IRP(R5),R3`009; Restore IRP
X`009CMPW`009IRP$W_BCNT(R3),-`009; Any characters moved
X`009`009UCB$W_BCNT(R5)
X`009BNEQ`00950$`009`009`009; Yes complete I/O
X47$:`009RSB
X;
X; read buffer exhausted
X;
X50$:`009MOVL`009UCB$L_IRP(R5),R3`009; Restore IRP
X`009MOVW`009#SS$_NORMAL,-`009`009; Set successful completetion
X`009`009IRP$L_IOST1(R3)
X`009SUBW`009UCB$W_BCNT(R5),-`009; Update byte count
X`009`009IRP$W_BCNT(R3)
X`009MOVW`009IRP$W_BCNT(R3),-`009; Set in status
X`009`009IRP$L_IOST1+2(R3)
X;
X; If we wanted to here we could set the second longword of the device status
X;
X`009CLRL`009IRP$L_IOST2(R3)`009`009; No status
X`009MOVQ`009IRP$L_IOST1(R3),R0`009; Load IOSB return values
X
X`009JMP`009G^IOC$REQCOM
X;
X; Put the character into the read buffer
X;
XBUFFER_CHAR:
X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Switch UCBs to PY UCB
X`009BBC`009#UCB$V_BSY,-
X`009`009UCB$W_STS(R5), 60$`009; If no PY IRP, ignore
X`009MOVB`009R3,@UCB$L_SVAPTE(R5)`009; Add character to buffer
X`009INCL`009UCB$L_SVAPTE(R5)`009; Bump pointer
X`009DECW`009UCB$W_BCNT(R5)`009`009; Show character added
X60$:`009BRW`009PY_OUT_LOOP`009`009; Go for another char
X;
X; Take care of Burst mode R5 must be TW UCB
X;
XPY_START_BURST:
X`009BISW`009#TTY$M_TANK_BURST,-`009; Signal burst active
X`009`009UCB$W_TT_HOLD(R5)
X;
X; Continue burst
X;
XPY_BURST:
X`009MOVL`009UCB$L_TW_XUCB(R5),R1`009; Save PY UCB in R1
X`009CLRL`009R3`009`009`009; Initialize output size
X`009CMPW`009UCB$W_TT_OUTLEN(R5),UCB$W_BCNT(R1)  ; Is buffer too small?
X`009BGTR`00961$`009`009`009; Yes
X`009MOVW`009UCB$W_TT_OUTLEN(R5),R3`009; Nope, so output all
X`009BRB`00962$
X61$:`009MOVW`009UCB$W_BCNT(R1),R3`009; Just output what we can
X
X62$:`009PUSHR`009#^M<R0,R1,R2,R3,R4,R5>`009; MOVC3 destroys these registers
X`009MOVC3`009R3,@UCB$L_TT_OUTADR(R5),@UCB$L_SVAPTE(R1)
X`009`009`009`009`009; Transfer burst to the buffer
X`009POPR`009#^M<R0,R1,R2,R3,R4,R5>`009; Restore the registers
X
X`009ADDL2`009R3,UCB$L_SVAPTE(R1)`009; Update output pointer
X`009SUBW2`009R3,UCB$W_BCNT(R1)`009; Update output count
X`009ADDL2`009R3,UCB$L_TT_OUTADR(R5)`009; Update input pointer
X`009SUBW2`009R3,UCB$W_TT_OUTLEN(R5)`009; Update input count
X`009BNEQ`00965$`009`009`009; Not the last character
X`009BICW`009#TTY$M_TANK_BURST,-
X`009`009UCB$W_TT_HOLD(R5)`009; Reset burst not active
X65$:`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Swicht UCBs to PY UCB
X`009BRW`009PY_OUT_LOOP
X;
X; Get a single char from tt and put in read buffer R5 = TW UCB
X;
XPY_CHAR:
X`009MOVB`009UCB$W_TT_HOLD(R5),R3`009; Get the next byte
X`009BICW`009#TTY$M_TANK_HOLD,-`009; Show tank empty
X`009`009UCB$W_TT_HOLD(R5)
X`009BRW`009BUFFER_CHAR
X;
X; Stop the output R5 = TW UCB
X;
X; Deleted PY_STOP2 routine and changed bit clear to byte operation - DEC
X;
XPY_STOP:
X`009BICB`009#UCB$M_INT, -
X`009`009UCB$W_STS(R5)`009`009; Reset output active
X`009BRW`009PY_DONE`009`009`009; DON'T go for anymore
X`009`009`009`009`009; Or we'll get into an infinite loop
X;
X; Send Xon or Xoff characters, R5 = TW UCB
X;
X; Changed PY_XOFF and PY_XON to be PY_PREMPT - DEC
X;
XPY_PREMPT:
X`009movb`009UCB$B_TT_PREMPT(r5), r3`009; Pick up the character
X`009BICW`009#TTY$M_TANK_PREMPT,-`009; Reset Xoff state
X`009`009UCB$W_TT_HOLD(R5)
X`009BRW`009BUFFER_CHAR
X`009.DISABLE LSB
X`012
X`009.SBTTL`009PY$SET - Set up ATTENTION AST's
X;++
X; PY$FDTSET - FUNCTION DECISION ROUTINE FOR SET MODE/CHAR FUNCTIONS
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine is the function decision routine for SET MODE/CHAR
X; functions.
X;
X; P4(AP)`009Determines what AST get's setup.
X;`009`009`0091 -> XON AST
X;`009`009`0092 -> XOFF AST
X;`009`009`0093 -> SET_LINE AST
X;
X; INPUTS:
X;
X;`009R3 = I/O PACKET ADDRESS
X;`009R4 = PCB ADDRESS OF CURRENT PROCESS
X;`009R5 = UCB ADDRESS
X;`009R6 = CCB ADDRESS FOR ASSIGNED UNIT
X;`009AP = ADDRESS OF ARGUMENT LIST AT USER PARAMETERS
X;
X; OUTPUTS:
X;
X;`009The function is completed here by "EXE$FINISHIO".
X;
X; IMPLICIT OUTPUTS:
X;
X; `009R3,R5 ARE PRESERVED.
X;--
XPY$FDTSET:
X`009PUSHL`009R5
X`009MOVZWL`009#SS$_NOSUCHDEV,R0`009; Assume no TW device
X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB
X`009BEQL`009SET_ABORT`009`009; No TW UCB exit
X`009CASE`009P4(AP),LIMIT=#1,TYPE=B,<- ; Figure out what to set
X`009`009SET_XON_AST,-`009`009;
X`009`009SET_XOFF_AST,-`009`009;
X`009`009SET_LINE_AST>`009`009;
XBAD_SET:
X`009MOVZWL`009#SS$_BADPARAM,R0`009; Failure reason
XSET_ABORT:
X`009POPL`009R5
X`009JMP`009G^EXE$ABORTIO
X
XSET_XON_AST:
X`009MOVAB`009UCB$L_TW_XON_AST(R5),R7`009; XON AST list head address
X`009BRB`009SET_CMN`009`009`009; Go to common code
X
XSET_XOFF_AST:
X`009MOVAB`009UCB$L_TW_XOFF_AST(R5),R7 ; XOFF AST list head address
X`009BRB`009SET_CMN`009`009`009; Go to common code
X
XSET_LINE_AST:
X`009MOVAB`009UCB$L_TW_SET_AST(R5),R7`009; SET_LINE AST list head address
X
XSET_CMN:
X`009POPL`009R5
X`009JSB`009G^COM$SETATTNAST`009; Insert into AST list
X`009JMP`009G^EXE$FINISHIOC`009`009; Complete request
X`012
X`009.SBTTL`009PY$FDTSENSEM - Sense mode routine
X;++
X; TTY$FDTSENSEM - SENSE MODE
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine passes the the current characteristics for SENSEMODE.
X; The buffer returned is a 8 or 12 bytes depending upon users request.
X;
X; INPUTS:
X;
X;`009R3 = I/O PACKET ADDRESS
X;`009R4 = CURRENT PCB ADDRESS
X;`009R5 = UCB ADDRESS
X;`009R6 = CCB ADDRESS
X;`009R7 = FUNCTION CODE
X;`009AP = ARG LIST FROM QIO
X;
X; OUTPUTS:
X;
X;`009CONTROL IS PASSED TO EXE$ABORTIO ON FAILURE
X;`009OR COMPLETED VIA EXE$FINISHIO
X;
X; STATUS RETURNS:
X;
X;`009SS$_NORMAL - SUCCESSFULL
X;`009SS$_ACCVIO - BUFFER NOT ACCESSIBLE
X;
X; NOTE:
X;`009The following code assumes that the DEVICE and FORK lock
X;`009for the TW device are the same.  If this changes then this
X;`009code is broken.
X;
X;--
XPY$FDTSENSEM::
X`009BSBW`009VERIFY_SENSE`009`009; VERIFY USER STORAGE
X`009PUSHR`009#^M<R5,R6,R7,R8,R10,R11>
X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB
X`009BEQL`009PY$SENSE_ERR`009`009; Have UCB
X`009MOVL`009UCB$L_TT_LOGUCB(R5),R5`009; Switch to logical device is one exists
X`009BSBW`009GET_DCL`009`009`009; BUILD SPECIAL CHARACTERISTICS
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DSBINT`009UCB$B_DIPL(R5)
X.IF_FALSE
X`009DEVICELOCK LOCKADDR=UCB$L_DLCK(R5),- ; Lock out TW activity
X`009`009LOCKIPL=UCB$B_DIPL(R5),-; RAISE IPL
X`009`009SAVIPL=-(SP),`009-`009; SAVE CURRENT IPL
X`009`009PRESERVE=YES`009`009;
X.ENDC
X
X`009MOVL`009UCB$B_DEVCLASS(R5),R6`009; BUILD TYPE, AND BUFFER SIZE
X`009MOVL`009UCB$L_DEVDEPEND(R5),R7`009;RETURN 1ST CHARACTERISTICS LONGWORD
X`009BISL3`009R2,UCB$L_DEVDEPND2(R5),R8;AND 2ND LONGWORD (IF REQUESTED)
X`009MOVL`009UCB$W_TT_SPEED-2(R5),R10; RETURN SPEED
X`009MOVL`009UCB$B_TT_PARITY-2(R5),R11; RETURN PARITY INFO
X`009BICL`009#^XFF000000,R11`009`009; ZERO HIGH BYTE
X`009MOVW`009UCB$B_TT_CRFILL(R5),R11`009; AND CR/LF FILL
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009ENBINT
X.IF_FALSE
X`009DEVICEUNLOCK LOCKADDR=UCB$L_DLCK(R5),- ; RELEASE INTERLOCK
X`009`009NEWIPL=(SP)+,`009-`009; RESTORE IPL
X`009`009CONDITION=RESTORE, -`009;
X`009`009PRESERVE=YES`009`009;
X.ENDC
X
X`009MOVL`009R6,(R1)`009`009`009; RETURN USER DATA
X`009MOVL`009R7,4(R1)`009`009;
X`009CMPB`009R0,#12`009`009`009; DID HE ASK FOR 2ND ?
X`009BLSS`00910$`009`009`009; NO
X`009MOVL`009R8,8(R1)`009`009;
X10$:`009MOVL`009R10,R0`009`009`009; RETURN IOSB DATA
X`009MOVL`009R11,R1`009`009`009;
X`009BRW`009CMN_EXIT`009`009; EXIT RETURNING R0,R1
X`012
X;`009If no TW device abort with SS$_NOSUCHDEV
XPY$SENSE_ERR:
X`009POPR`009#^M<R5,R6,R7,R8,R10,R11>
X`009MOVZWL`009#SS$_NOSUCHDEV,R0`009; Save error reason
X`009JMP`009G^EXE$ABORTIO`009`009; Abort request
X`012
X`009.SBTTL`009PY$FDTSENSEC - Sense char routine
X;++
X; TTY$FDTSENSEC - SENSE CHARACTERISTICS
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine passes the the permanent characteristics for SENSECHAR.
X; The buffer returned is a 8 or 12 bytes depending upon users request.
X;
X; INPUTS:
X;
X;`009R3 = I/O PACKET ADDRESS
X;`009R4 = CURRENT PCB ADDRESS
X;`009R5 = UCB ADDRESS
X;`009R6 = CCB ADDRESS
X;`009R7 = FUNCTION CODE
X;`009AP = ARG LIST FROM QIO
X;
X; OUTPUTS:
X;
X;`009CONTROL IS PASSED TO EXE$ABORTIO ON FAILURE
X;`009OR COMPLETED VIA EXE$FINISHIO
X;
X; STATUS RETURNS:
X;
X;`009SS$_NORMAL - SUCCESSFULL
X;`009SS$_ACCVIO - BUFFER NOT ACCESSIBLE
X;
X; NOTE:
X;`009The following code assumes that the DEVICE and FORK lock
X;`009for the TW device are the same.  If this changes then this
X;`009code is broken.
X;--
XPY$FDTSENSEC::`009`009`009`009; SENSE CHAR
X`009BSBW`009VERIFY_SENSE`009`009; VERIFY USER STORAGE
X`009PUSHR`009#^M<R5,R6,R7,R8,R10,R11>
X`009MOVL`009UCB$L_PY_XUCB(R5),R5`009; Switch to TW UCB
X`009BEQL`009PY$SENSE_ERR`009`009; Have UCB
X`009BSBW`009GET_DCL`009`009`009; BUILD SPECIAL CHARACTERISTICS
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DSBINT`009UCB$B_DIPL(R5)
X.IF_FALSE
X`009DEVICELOCK LOCKADDR=UCB$L_DLCK(R5),- ; Lock out TW activity
X`009`009LOCKIPL=UCB$B_DIPL(R5),-; RAISE IPL
X`009`009SAVIPL=-(SP)`009`009; SAVE CURRENT IPL
X.ENDC
X
X`009MOVL`009UCB$B_TT_DETYPE-1(R5),R6; BUILD TYPE, AND BUFFER SIZE
X`009MOVB`009#DC$_TERM,R6`009`009; BUILD DEVICE CLASS
X`009MOVL`009UCB$L_TT_DECHAR(R5),R7`009;RETURN 1ST CHARACTERISTICS LONGWORD
X`009BISL3`009R2,UCB$L_TT_DECHA1(R5),R8;AND 2ND LONGWORD (IF REQUESTED)
X`009MOVL`009UCB$W_TT_DESPEE-2(R5),R10; RETURN SPEED
X`009MOVL`009UCB$B_TT_DEPARI-2(R5),R11; RETURN PARITY INFO
X`009BICL`009#^XFF000000,R11`009`009; ZERO HIGH BYTE
X`009MOVW`009UCB$B_TT_DECRF(R5),R11`009; AND CR/LF FILL
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009ENBINT
X.IF_FALSE
X`009DEVICEUNLOCK LOCKADDR=UCB$L_DLCK(R5),- ; RELEASE INTERLOCK
X`009`009NEWIPL=(SP)+,`009-`009; RESTORE IPL
X`009`009CONDITION=RESTORE`009;
X.ENDC
X
X`009MOVL`009R6,(R1)`009`009`009; RETURN USER DATA
X`009MOVL`009R7,4(R1)`009`009;
X`009CMPB`009R0,#12`009`009`009; DID HE ASK FOR 2ND ?
X`009BLSS`00910$`009`009`009; NO
X`009MOVL`009R8,8(R1)`009`009;
X10$:`009MOVL`009R10,R0`009`009`009; RETURN IOSB DATA
X`009MOVL`009R11,R1`009`009`009;
X`009BRW`009CMN_EXIT`009`009; EXIT RETURNING R0,R1
X`012
X;`009THIS ROUTINE BUILDS DCL PRIVATE CHARACTERISTICS
X
XGET_DCL:
X`009CLRL`009R2`009`009`009; INIT RETRUN ARGUMENT
X`009TSTL`009UCB$L_AMB(R5)`009`009; ANY ASSOCIATED MAILBOX?
X`009BEQL`00910$`009`009`009; NO
X`009BISL`009#TT2$M_DCL_MAILBX,R2`009; YES, SO BUILD CHARACTERISTIC
X10$:`009RSB
X`012
X;`009Common exit path for PY$FDTSENSEM and PY$FDTSENSEC
X
XCMN_EXIT:
X`009POPR`009#^M<R5,R6,R7,R8,R10,R11> ; RESTORE SCRATCH REGISTERS
X`009MOVW`009#SS$_NORMAL,R0
X`009JMP`009G^EXE$FINISHIO`009`009; COMPLETE REQUEST IOSB WORD 0,1
X`012
X;`009This routine verifies that the user buffer is accessable
X
XVERIFY_SENSE:`009`009`009`009;
X`009MOVL`009P1(AP),R1`009`009; ADDRESS USER BUFFER
X`009IFNOWRT`009#8,(R1),20$`009`009; BR IF NO ACCESS TO QUADWORD BUFFER
X`009MOVL`009#8,R0`009`009`009; INIT DEFAULT ARGUMENT SIZE
X`009CLRQ`009(R1)`009`009`009; INIT RETURN DATA
X`009MOVZWL`009P2(AP),R2`009`009; GET SIZE ARGUMENT
X`009CMPL`009R2,#12`009`009`009; ROOM FOR SECOND DEVDEPEND SPECIFIED?
X`009BLSSU`00910$`009`009`009; NO
X`009IFNOWRT`009#12,(R1),20$`009`009; CHECK IF WRITE ACCESS
X`009MOVW`009#12,R0`009`009`009; SAVE ARGUMENT SIZE
X`009CLRL`0098(R1)`009`009`009; INIT RETURN FIELD
X10$:
X`009RSB
X20$:
X`009MOVZWL`009#SS$_ACCVIO,R0`009`009; SET ERROR STATUS
X`009JMP`009G^EXE$ABORTIO`009`009; ABORT THE IO
X`012
X`009.SBTTL`009PY$END - End of driver
XPY$END:
X`009`009`009`009`009; End of driver
X`009.END
$ GOSUB UNPACK_FILE
$ FILE_IS = "TWDRIVER.MAR"
$ CHECKSUM_IS = 1332422334
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.TITLE`009TWDRIVER - Pseudo terminal driver for Front End and ethernet
X`009.IDENT`009'V05-005A'
X
X;++
X; FACILITY:
X;
X;`009VAX/VMS TERMINAL DRIVER
X;
X; ABSTRACT:
X;
X;`009PSEUDO TERMINAL ROUTINES.
X;
X; AUTHOR:
X;
X;`00919-NOV-1982`009Dale Moore (dwm) at CMU
X;`009`009Redone for VMS V3.0
X;
X;`009This program has been granted to the public domain by the author.
X;
X; MODIFICATIONS:
X;
X;`009Version V05-005A Kevin Carosso @ Network Research Co.
X;`009`009Make the conditional assembly for VMS V5 automatic
X;`009`009driven off existence of SS$_INVLICENSE.
X;
X;`009V05-004A Kevin Carosso @ Network Research Co.
X;`009`009Conditionalize assembly for VMS V4 or V5.  There
X;`009`009is a magic symbol at the top that is commented
X;`009`009out for VMS V5.
X;
X;`009V05-004`009Digital Equipment Corp.`00924-May-1988
X;`009`009Add code to delivered ASTs if PORT XON, PORT XOFF, or
X;`009`009PORT SET_LINE routines are called.
X;
X;`009V05-003`009Digital Equipment Corp.`00913-May-1988
X;`009`0091) Add hooks to indicate if line is XOFFed.
X;`009`0092) Set TTY$M_PC_NOMODEM bit in UCB$W_TT_PRTCTL.
X;`009`0093) Set device to HOSTSYNC.
X;
X;`009V05-002`009Digital Equipment Corp.`00915-Feb-1988
X;`009`009Add TTY$M_PC_MULTISESSION bit to UCB$W_TT_PRTCTL so that
X;`009`009this device is not counted as a user in LOGIN.
X;
X;---------- Previous history ---------------------
X;
X;`009`009DWM`009- Added .Page above each .sbttl
X;`009`009`009- added modem transition routines in disco and init
X;`009`009`009- removed $ACBDEF external def's
X;`009`009`009- restored timeout to resume
X;`009`009`009- added ioc$initiate call in xoff and xon routines.
X;`009Version V03-002 - Changed TP startio to clear TIM in UCB$W_STS
X;`009Version V03-003 - Changed TW$RESUME to not set timeout bit in sts
X;
X;`009Version V03-004 (Thu Dec  9 12:43:17 1982) D. Kashtan
X;`009`009`009  Made into a TEMPLATE driver.
X;`009`009`009  (***WARNING*** -- LOOK AT COMMENTS FOR ROUTINE
X;`009`009`009   TW$SET_LINE.  THERE IS IMPORTANT INFORMATION
X;`009`009`009   ABOUT CHANGES TO VMS THAT WILL AFFECT THE TWDRIVER)
X;`009Version V03-005 - (14-Jun-1983 )Dale Moore
X;`009`009`009  Add R4 to masks on calls to ioc$initiate.
X;`009`009`009  TTY$STARTIO clobber R4.
X;`009Version V03-006`009- Change TW$XON and TW$XOFF routines from
X;`009`009`009  unconditionally calling IOC$INITIATE.
X;`009`009`009  IOC$INITIATE will branch to PY$STARTIO,
X;`009`009`009  Which will call TTY$GETNEXTCHAR (UCB$L_TT_GETNEXT),
X;`009`009`009  Which will branch to EOLSEEN,
X;`009`009`009  which calls TTY$READONE,
X;`009`009`009  which calls the PORT_XOFF routine which is TW$XOFF.
X;`009`009`009  This cycle was eating up all of the kernel stack.
X;`009Version V03-007 - (12-Jul-1983) Mark London
X;`009`009`009  Set default of TW to TERM to allow REPLY/USERS.
X;`009`009`009  Make TW owned and not a TEMPLATE in order that
X;`009`009`009  SHO TERM TWA0 does not cause a crash (SHOW attempts
X;`009`009`009  an ASSIGN to the device.)
X;`009Verison V04-001 - ( 9-Nov-1984 ) L. Bellamy and D. Davis
X;`009`009`009  In order of appearance:
X;
X;`009`009`009  Added Object Rights Block offset definitions.
X;`009`009`009  Add TEMPLATE bit to UCB$W_STS.
X;`009`009`009  Add ORB definitions in prologue.
X;`009`009`009  Modify to allow vector definitions using VEC macro.
X;`009`009`009  Use CLASS_CTRL_INIT and CLASS_UNIT_INIT to locate
X;`009`009`009   vector table.
X;`009`009`009  Update powerfail routines.
X;`009`009`009  Use new methodology for XON/XOFF flow control.
X;`009`009`009  Get rid of all the SET_LINE stack manipulation
X;`009`009`009  since the terminal driver does not do anything
X;`009`009`009  malicious as suggested.
X;
X;`009`009`009  NOTE - Comments in subroutine preambles not altered
X;`009`009`009  to reflect changes in most places.
X;
X;`009Version V04-003 (24-Jun-1985) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Cleaned this thing up quite a bit.
X;`009`009`009- Got rid of MBX characteristic on the devices.  This
X;`009`009`009  was a holdover to before cloned devices really
X;`009`009`009  existed.
X;`009`009`009- Leave the TW template device OFFLINE.  This is what
X;`009`009`009  other TEMPLATE devices do, to indicate that you
X;`009`009`009  really cannot do I/O to the template.  Also left
X;`009`009`009  it UNAVAILABLE, since the only way it is supposed to
X;`009`009`009  get used is by cloning in the PY device.
X;`009`009`009- Got rid of all modem operations.  Improper use tended
X;`009`009`009  to crash the system and they are not necessary.  TW
X;`009`009`009  device is always NOMODEM.  HANGUP works as you want
X;`009`009`009  it to without the modem stuff.
X;`009`009`009- Setup forced characteristics and default permanent
X;`009`009`009  characteristics.  Forced are: NOAUTOBAUD, and NODMA.
X;`009`009`009  Default is HANGUP.
X;`009`009`009- Fixed up TW$DISCONNECT to properly send a message
X;`009`009`009  to PY device's associated mailbox only if we are
X;`009`009`009  actually doing a hangup.  It used to do it every
X;`009`009`009  time.  Changed the message to MSG$_TRMHANGUP.
X;`009`009`009- Got rid of the BRDCST on/off stuff.  It doesn't seem
X;`009`009`009  to be necessary any more.  It also had a bug in it
X;`009`009`009  somewhere that caused the terminal to start off
X;`009`009`009  NOBRDCST when it shouldn't.
X;`009`009`009- General house-cleaning.  Got rid of commented out
X;`009`009`009  lines from VMS V3 version.  Fixed up typos in
X;`009`009`009  comments.
X;
X;`009Version V04-004 (10-Feb-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Changed all references to PTDRIVER to TPDRIVER because
X;`009`009`009DEC (bless their little hearts) invented the %*%#$%
X;`009`009`009TU81 and use PTA0: now.
X;
X;`009Version V04-005 (3-Sep-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Fixed bug whereby the sequence ^S followed by ^Y
X;`009`009`009would cause a system hang.  Apparently the class
X;`009`009`009driver calls the port RESUME routine when doing
X;`009`009`009an ABORT and again when canceling the ^S.  Calling
X;`009`009`009RESUME twice like this is bad.  In general, the
X;`009`009`009port RESUME routine should not restart the output.
X;`009`009`009In this driver, the RESUME and STOP routines aren't
X;`009`009`009needed, so I got rid of them completely.
X;
X;`009`009`009Now on ^Y the ^S state is not cleared.  You still
X;`009`009`009need to type ^Q to get your output (including the
X;`009`009`009*INTERRUPT* echo string.  I thought this was another
X;`009`009`009bug, but it's how my DHU-11 based terminals act
X;`009`009`009and makes sense, because only a ^Q should really
X;`009`009`009cancel a ^S.
X;
X;`009`009`009Also removed the TEMPLATE bit from the TWA0: template
X;`009`009`009device since it was allowing people to $ASSIGN channels
X;`009`009`009and get unhappy (lonely) TW devices that could crash
X;`009`009`009the system.  Now, the only way to clone TW devices
X;`009`009`009is through the code in PYDRIVER, hence by assigning
X;`009`009`009a channel to PYA0:.  You can still $ASSIGN to TWA0:,
X;`009`009`009but since the device is offline that shouldn't hurt
X;`009`009`009anything.  This fixed crashes caused by KERMIT and
X;`009`009`009other things attempting to use TWA0:.  You now get
X;`009`009`009an error "DEVOFFLINE".
X;
X;`009`009`009Fixed a bug that caused a system crash from SHOW
X;`009`009`009DEVICE/FULL of TWA0:.  The ACL_QUEUE bit was set
X;`009`009`009in the ORB but the ACL queue was invalid (was zeroed).
X;`009`009`009I got rid of the bit, now all is well.
X;
X;`009Version V04-006 (5-Dec-1986) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009Fixed the infamous character munging bug.  The fix
X;`009`009`009is really in PYDRIVER.
X;
X;`009Version V04-007 (10-JUL-1987) Kevin Carosso, Hughes Aircraft Co., S&CG
X;`009`009`009In TW$INITLINE make sure to tell the class driver
X;`009`009`009never to time out.  This fix from Forrest Kenney
X;`009`009`009at DEC.
X;
X;`009`009`009Also, while we're in here, lets make the device
X;`009`009`009acquire "NODE$" prefixes, since all the other
X;`009`009`009terminal drivers do.
X;
X;`009Version V04-008`009(2-NOV-1987) Kevin Carosso, Network Research Co.
X;`009`009`009Only a version change here to keep in sync with
X;`009`009`009TWDRIVER which has the real change.
X;
X;`009`009`009Fix thanks to Gerard K Newman @ San Diego
X;`009`009`009Supercomputer Center.
X;
X;`009Version V05-001 (21-Dec-1987) Digital Equipment Corp.
X;`009`009`009Add support for Symmetric Multiprocessing.
X;
X;`009Version V05-002 Digital Equipment Corp.
X;`009`009`009Change TP driver names to TW. (TP driver it turns
X;`009`009`009out, conflicted with the VAX/PSI terminal driver.)
X;`009`009`009TWDRIVER and PYDRIVER are now registered with SQM
X;`009`009`009so there will be no more conflicts.
X;--
X`012
X`009.PAGE
X`009.SBTTL`009Declarations
X
X`009.LIBRARY`009/SYS$LIBRARY:LIB.MLB/
X
X;
X; EXTERNAL DEFINITIONS:
X;
X.NOCROSS
X`009$ACBDEF`009`009`009`009; AST control block definitions
X`009$CRBDEF`009`009`009`009; DEFINE CRB
X`009$DCDEF`009`009`009`009; DEVICE CLASSES AND TYPES
X`009$DDBDEF`009`009`009`009; DEFINE DDB
X`009$DDTDEF`009`009`009`009; DEFINE DDT
X`009$DEVDEF`009`009`009`009; DEVICE CHARACTERISTICS
X`009$DYNDEF`009`009`009`009; Dynamic structure definitions
X`009$IDBDEF`009`009`009`009; DEFINE IDB OFFSETS
X`009$IODEF`009`009`009`009; I/O Function Codes
X`009$IRPDEF`009`009`009`009; IRP definitions
X`009$MSGDEF`009`009`009`009; Message types
X`009$ORBDEF`009`009`009`009; Define Object's Rights Block offsets
X`009$SSDEF`009`009`009`009; DEFINE System Status
X;
X; If SS$_INVLICENSE exists, we must be building on V5.  Go ahead and
X; define our conditionals so we can build a V5 driver.
X;
X.IF`009DEFINED`009SS$_INVLICENSE
X`009VMS_V5 = 1
X`009.PRINT`009`009; TWDRIVER -- Building VMS V5 compatible driver
X.IF_FALSE
X`009.PRINT`009`009; TWDRIVER -- Building VMS V4 compatible driver
X.ENDC
X
X.IF`009DEFINED`009VMS_V5
X`009$SPLCODDEF`009`009`009; Spin lock code definitions
X.ENDC
X
X`009$TTDEF`009`009`009`009; DEFINE TERMINAL TYPES
X`009$TT2DEF`009`009`009`009; Define Extended Characteristics
X`009$TTYDEF`009`009`009`009; DEFINE TERMINAL DRIVER SYMBOLS
X`009$TTYDEFS`009`009`009; DEFINE TERMINAL DRIVER SYMBOLS
X`009$TTYMACS`009`009`009; DEFINE TERMINAL DRIVER MACROS
X`009$UCBDEF`009`009`009`009; DEFINE UCB
X`009$VECDEF`009`009`009`009; DEFINE VECTOR FOR CRB
X.CROSS
X
X;
X; LOCAL DEFINITIONS
X;
XDT$_TW = ^XFF
X;
X; Definitions that follow the standard UCB fields for TW driver
X;  This will all probably have to be the same as the standard term
X
X`009$DEFINI`009UCB`009`009`009; Start of UCB definitions
X
X`009.=UCB$K_TT_LENGTH`009`009; Position at end of UCB
X
X$DEF`009UCB$L_TW_XUCB`009.BLKL`0091`009; UCB of corresponding
X`009`009`009`009`009;  control/application unit
X$DEF`009UCB$L_TW_XON_AST .BLKL`0091`009; AST list for XON event notification
X$DEF`009UCB$L_TW_XOFF_AST .BLKL`0091`009; AST list for XOFF event notification
X$DEF`009UCB$L_TW_SET_AST .BLKL`0091`009; AST list for notification of SET_LINE
X$DEF`009UCB$K_TW_LEN`009`009`009; Size of UCB
X
X`009$DEFEND`009UCB`009`009`009; End of UCB definitions
X;
X; Definitions that follow the standard UCB fields in PY devices
X;
X
XBUFFER_SIZE = 32
X
X`009$DEFINI UCB`009`009`009; Start of UCB definitions
X `009.=UCB$K_LENGTH`009`009`009; position at end of UCB
V$DEF`009UCB$L_PY_XUCB`009.BLKL 1`009`009; UCB of terminal part of pseudo termin
Xal
V$DEF`009UCB$T_PY_BUFFER`009.BLKB`009BUFFER_SIZE ; Buffer to store characters to
X be transmitted
X$DEF`009UCB$K_PY_LEN`009`009`009; Size of UCB
X
X `009$DEFEND UCB`009`009`009; end of UCB definitions
X
X;
X; LOCAL STORAGE
X;
X`009.PSECT`009$$$105_PROLOGUE
X`012
X`009.PAGE
X`009.SBTTL`009Standard Tables
X
X;
X; Driver prologue table:
X;
XTW$DPT::
X`009DPTAB`009-`009`009`009; DRIVER PROLOGUE TABLE
X`009`009END=TW_END,-`009`009; End and offset to INIT's vectors
X`009`009UCBSIZE=UCB$K_TW_LEN,- `009; SIZE OF UCB
X`009`009FLAGS=DPT$M_NOUNLOAD,-`009; Do not allow unload
X`009`009ADAPTER=NULL,-`009`009; ADAPTER TYPE
X`009`009NAME=TWDRIVER,-`009`009; NAME OF DRIVER
X`009`009VECTOR=PORT_VECTOR
X`009DPT_STORE INIT
X`009DPT_STORE UCB,UCB$W_UNIT_SEED,W,0`009; SET UNIT # SEED TO ZERO
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DPT_STORE UCB,UCB$B_FIPL,B,8 `009`009; FORK IPL
X.IF_FALSE
X`009DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ; FORK LOCK
X.ENDC
X
X`009DPT_STORE UCB,UCB$L_DEVCHAR,L,<-; CHARACTERISTICS
X`009`009`009DEV$M_REC!-`009;
X`009`009`009DEV$M_IDV!-`009;
X`009`009`009DEV$M_ODV!-`009;
X`009`009`009DEV$M_TRM!-`009;
X`009`009`009DEV$M_CCL>
X`009DPT_STORE UCB,UCB$L_DEVCHAR2,L, -`009`009; Device characteristics
X`009`009`009<DEV$M_NNM>`009`009`009; prefix with "NODE$"
X`009DPT_STORE UCB,UCB$B_DEVCLASS,B,DC$_TERM`009`009;
X`009DPT_STORE UCB,UCB$B_TT_DETYPE,B,TT$_UNKNOWN`009; TYPE
X`009DPT_STORE UCB,UCB$W_TT_DESIZE,@W,TTY$GW_DEFBUF`009; BUFFER SIZE
X`009DPT_STORE UCB,UCB$L_TT_DECHAR,@L,TTY$GL_DEFCHAR`009; DEFAULT CHARACTERS
X`009DPT_STORE UCB,UCB$L_TT_DECHA1,@L,TTY$GL_DEFCHAR2; DEFAULT CHARACTERS
X`009DPT_STORE UCB,UCB$W_TT_DESPEE,@B,TTY$GB_DEFSPEED; DEFAULT SPEED
X`009DPT_STORE UCB,UCB$W_TT_DESPEE+1,@B,TTY$GB_RSPEED; DEFAULT SPEED
X`009DPT_STORE UCB,UCB$B_TT_DEPARI,@B,TTY$GB_PARITY`009; DEFAULT PARITY
X`009DPT_STORE UCB,UCB$B_TT_PARITY,@B,TTY$GB_PARITY`009; DEFAULT PARITY
X`009DPT_STORE UCB,UCB$B_DEVTYPE,B,TT$_UNKNOWN`009; TYPE
X`009DPT_STORE UCB,UCB$W_DEVBUFSIZ,@W,TTY$GW_DEFBUF`009; BUFFER SIZE
X`009DPT_STORE UCB,UCB$L_DEVDEPEND,@L,TTY$GL_DEFCHAR`009; DEFAULT CHARACTERS
X`009DPT_STORE UCB,UCB$L_TT_DEVDP1,@L,TTY$GL_DEFCHAR2; Default Characters
X`009DPT_STORE UCB,UCB$W_TT_SPEED,@B,TTY$GB_DEFSPEED`009; DEFAULT SPEED
X`009DPT_STORE UCB,UCB$W_TT_SPEED+1,@B,TTY$GB_RSPEED`009; DEFAULT SPEED
X`009DPT_STORE UCB,UCB$B_DIPL,B,8`009`009`009; DEV IPL (no device)
X`009DPT_STORE UCB,UCB$L_TT_WFLINK,L,0`009; Zero write queue.
X`009DPT_STORE UCB,UCB$L_TT_WBLINK,L,0`009; Zero write queue.
X`009DPT_STORE UCB,UCB$L_TT_RTIMOU,L,0`009; Zero read timed out disp.
X;
X; Added ORB definitions
X;
X`009DPT_STORE ORB, ORB$B_FLAGS, B, <ORB$M_PROT_16>
X`009DPT_STORE ORB, ORB$W_PROT, @W, TTY$GW_PROT
X`009DPT_STORE ORB, ORB$L_OWNER, @L, TTY$GL_OWNUIC
X
X`009DPT_STORE DDB,DDB$L_DDT,D,TW$DDT
X
X`009DPT_STORE REINIT
X`009DPT_STORE CRB,CRB$L_INTD+VEC$L_INITIAL,D,TW$INITIAL; CONTROLLER INIT
X`009DPT_STORE CRB,CRB$L_INTD+VEC$L_UNITINIT,D,TW$INITLINE; UNIT INIT
X`009DPT_STORE END
X
X`009DDTAB`009DEVNAM`009= TW,-`009`009; Dummy TW port Driver Dispatch table
X`009`009START`009= 0,-
X`009`009FUNCTB`009= 0
X
X`009.PSECT $$$115_DRIVER,LONG
X
X; The associated class driver uses this table to command the port driver.
X; The address of the table is contained in the terminal UCB extension area.
X; The offset definitions are defined by the ttydefs.
X
X;
X; TW specific dispatch table
X;
XPORT_VECTOR:
X;
X; Added port vector table using VEC macros
X;
X`009$VECINI`009TW,TW$NULL
X`009$VEC`009STARTIO,TW$STARTIO
X`009$VEC`009DISCONNECT,TW$DISCONNECT
X`009$VEC`009SET_LINE,TW$SET_LINE
X`009$VEC`009XON,TW$XON
X`009$VEC`009XOFF,TW$XOFF
X`009$VEC`009ABORT,TW$ABORT
X`009$VECEND
X
XTW$NULL:`009`009`009`009; Null port routine
X`009RSB
X
X`012
X`009.PAGE
X`009.SBTTL`009TW$INITIAL - Initialize pseudo terminal interface
X;++
X; TW$INITIAL - INITIALIZE INTERFACE
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine is entered at device CONNECT time and power recovery.
X; All we do is connect ourselves up to the class driver.
X;
X; INPUTS:
X;
X;`009R4 = ADDRESS OF THE UNIT CSR
X;`009R5 = IDB OF UNIT
X;`009R8 = ADDRESS OF THE UNIT CRB
X;
X; OUTPUTS:
X;
X;`009R0, R1, R2, R3 are destroyed.
X;
X; IMPLICIT INPUTS:
X;
X;`009IPL = IPL$_POWER
X;
X;--
XTW$INITIAL::
X
X`009CLASS_CTRL_INIT TW$DPT,PORT_VECTOR
X`009MOVB`009#DT$_TW,CRB$B_TT_TYPE(R8)
X`009RSB
X`012
X`009.PAGE
X`009.SBTTL`009TW$INITLINE - RESET INDIVIDUAL LINE
X;++
X; TW$INITLINE - RESET pseudo terminal control state
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine performs a simple unit initialization.
X;
X;
X; INPUTS:
X;
X;`009R5 = UCB ADDRESS
X;
X; OUTPUTS:
X;
X;`009R2,R5 ARE PRESERVED.
X;--
XTW$INITLINE::`009`009`009`009; RESET SINGLE LINE
X`009MOVAL`009TW$VEC,R0`009`009; Set TW port vector table
X`009CLASS_UNIT_INIT
X`009TSTL`009UCB$W_UNIT(R5)`009`009; Skip initialization of TEMPLATE
X`009BEQL`00940$`009`009`009; Unit #0 = Template: Skip everything!
X
X`009BBS`009#UCB$V_POWER,UCB$W_STS(R5),-`009; Skip if powerfail recovery
X`009`00920$
X`009MOVL`009UCB$L_TT_LOGUCB(r5), r1`009`009; Look at logical term UCB
X`009BEQL`00910$`009`009`009`009; If none, then has no refs
X`009TSTW`009UCB$W_REFC(R1)`009`009`009; See if TW has any references
X`009BNEQ`00920$`009`009`009`009; If so don't reinit ucb
X10$:`009BSB`009SET_FORCED_CHARS`009`009; Set required characteristics
X`009BISL`009#TT2$M_HANGUP,-`009`009`009; Set default characteristics
X`009`009UCB$L_TT_DECHA1(R5)`009`009;
X`009MOVL`009UCB$L_TT_CLASS(R5),R1`009`009; Address class vector table
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009BISW`009#<TTY$M_PC_NOTIME!`009-`009; Tell class driver not to time out,
X`009`009  TTY$M_PC_MULTISESSION>,-`009; and do not count as user
X`009`009UCB$W_TT_PRTCTL(R5)`009`009;
X.IF_FALSE
X`009BISW`009#<TTY$M_PC_NOTIME!`009-`009; Tell class driver not to time out,
X`009`009  TTY$M_PC_NOMODEM!`009-`009; do not allow modem processing,
X`009`009  TTY$M_PC_MULTISESSION>,-`009; and do not count as user
X`009`009UCB$W_TT_PRTCTL(R5)`009`009;
X.ENDC
X
V`009BICL2`009#TT$M_MODEM,UCB$L_DEVDEPEND(R5) ; Do not allow modem bit to ever b
Xe
X`009BICL2`009#TT$M_MODEM,UCB$L_TT_DECHAR(R5) ; set.
X`009BISL2`009#TT$M_HOSTSYNC,UCB$L_DEVDEPEND(R5) ; Always set device to HOSTSYNC
X`009BISL2`009#TT$M_HOSTSYNC,UCB$L_TT_DECHAR(R5) ;
X`009JSB`009@CLASS_SETUP_UCB(R1)`009`009; Init ucb fields
X20$:`009BBC`009#UCB$V_POWER,UCB$W_STS(R5),40$`009; Powerfail handler
X`009MOVL`009UCB$L_TT_CLASS(R5),R0`009`009;
X`009JMP`009@CLASS_POWERFAIL(R0)`009`009;
X
X40$:`009RSB
X
X
X`012
X;++
X; TW$SET_LINE - Used to Reset SPEED and UCB
X;
X; FUNCTIONAL DESCRIPTION:
X;
X;`009Called whenever someone tries to set terminal modes/characteristics.
X;`009All we do is reset anything that we think should never be changed.
X;
X; INPUTS:
X;
X;`009R5 = UCB ADDRESS of TW
X;
X; OUTPUTS:
X;
X;`009none
X;--
XTW$SET_LINE::
X`009MOVAB`009UCB$L_TW_SET_AST(R5),R4`009`009; Get list head address
X`009TSTL`009(R4)`009`009`009`009; See if list is empty
X`009BEQL`009SET_FORCED_CHARS`009`009; Empty do not deliver ASTs
X`009JSB`009G^COM$DELATTNAST`009`009; Delliver all ASTs
X
XSET_FORCED_CHARS:
X;
X; This little routine sets certain required characteristics.  It is called by
X; the INITLINE code to set them at the outset and by the SETLINE code to reset
X; them unconditionally if someone tries to set them.
X;
X`009BICL2`009#<TT2$M_DMA ! TT2$M_AUTOBAUD>, -
X`009`009UCB$L_DEVDEPND2(R5)
X`009BICL2`009#<TT2$M_DMA ! TT2$M_AUTOBAUD>, -
X`009`009UCB$L_TT_DECHA1(R5)
X
X.IF`009NOT_DEFINED`009VMS_V5
V`009BICL2`009#TT$M_MODEM,UCB$L_DEVDEPEND(R5) ; Do not allow modem bit to ever b
Xe
X`009BICL2`009#TT$M_MODEM,UCB$L_TT_DECHAR(R5) ; set.
X.ENDC
X
X`009RSB
X
X`012
X
X`009.Page
X;++
X; TW$DISCONNECT - SHUT OFF UNIT
X;
X; FUNCTIONAL DESCRIPTION:
X;
X; This routine is used when for some reason the unit must be disconnected.
X; This can be at hangup or last deassign.  If the PY device has an associated
X; mailbox, signal an MSG$_TRMHANGUP in it.
X;
X; Although we are disconnecting a virtual device, we don't do anything
X; more than send a hangup message because we want to allow the device to
X; be reusable.  It's really only if the control device (PY) goes away
X; that we mark the TW offline and delete it's UCB.  That code's all in
X; PYDRIVER.
X;
X; INPUTS:
X;
X;`009R0 = (0 for hangup, 1 for nohangup)
X;`009R5 = UCB ADDRESS of TW
X;
X; OUTPUTS:
X;
X;`009R3,R4 ARE USED.
X;--
XTW$DISCONNECT::
X`009blbs`009r0, 99$`009`009`009; If no hangup, skip all this.
X
X`009PUSHR`009#^M<R0,R1,R2,R3,R4,R5>`009; Save the registers
X
X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Get PY UCB
X`009BEQL`00910$`009`009`009; If disconnected, ignore
X`009MOVL`009UCB$L_AMB(R5),R3`009; Load Associated Mailbox of PY UCB
X`009BEQL`00910$`009`009`009; If EQL then no mailbox
X`009MOVZWL`009#MSG$_TRMHANGUP,R4`009; Load Message Type
X`009JSB`009G^EXE$SNDEVMSG`009`009; Send the message
X10$:`009POPR`009#^M<R0,R1,R2,R3,R4,R5>`009; Restore everything
X99$:`009RSB
X
X
X`012
X`009.PAGE
X`009.SBTTL`009TW START I/O ROUTINE
X;++
X; TW$STARTIO - START I/O OPERATION ON TW
X;
X; FUNCTIONAL DESCRIPTION:
X;
X;`009This routine is entered from the device independent terminal startio
X;`009routine to enable output interrupts on an idle TW unit
X;
X; INPUTS:
X;
X;`009R3 =`009Character`009AND`009CC = Plus (N EQL 0)
X;`009R3 =`009Address`009`009AND`009CC = Negative (N EQL 1)
X;
X;`009R5 = UCB ADDRESS
X;
X; OUTPUTS:
X;
X;`009R5 = UCB ADDRESS
X;--
XTW$STARTIO::`009`009`009`009; START I/O ON UNIT
X`009BGEQ`00920$`009`009`009; Single character
X`009BISW`009#TTY$M_TANK_BURST,-`009; Signal burst active
X`009`009UCB$W_TT_HOLD(R5)
X10$:
X;
X; Here we must do something to notify our mate device that
X; there is data to pick up
X;
X`009PUSHR`009#^M<R0,R2,R3,R4,R5>`009; Save TW UCB
X`009MOVL`009UCB$L_TW_XUCB(R5),R5`009; Switch to PY UCB
X`009BEQL`00917$`009`009`009; PY is disconnected: skip
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009DSBINT`009UCB$B_FIPL(R5)
X.IF_FALSE
X`009FORKLOCK`009`009-`009; Take out PY device FORK LOCK
X`009`009LOCK=UCB$B_FLCK(R5), -`009;
X`009`009SAVIPL=-(SP),`009-`009;
X`009`009PRESERVE=NO
X.ENDC
X
X`009BBC`009#UCB$V_BSY,-`009`009; If the device isn't busy,
X`009`009UCB$W_STS(R5),15$`009; then dont do i/o
X`009MOVL`009UCB$L_IRP(R5),R3`009; Get IRP address
X`009JSB`009G^IOC$INITIATE`009`009; IOC$INITIATE needs IRP addr
X15$:
X
X.IF`009NOT_DEFINED`009VMS_V5
X`009ENBINT
X.IF_FALSE
X`009FORKUNLOCK`009`009-`009; Release PY drvice FORK LOCK
X`009`009LOCK=UCB$B_FLCK(R5), -`009;
X`009`009NEWIPL=(SP)+,`009-`009;
X`009`009PRESERVE=NO,`009-`009;
X`009`009CONDITION=RESTORE`009;
X.ENDC
X
X16$:`009POPR`009#^M<R0,R2,R3,R4,R5>`009; Switch back to TW UCB
X`009RSB
X;
X; Come here if we have no PY control device to send stuff to.  Just
X; suck all the data we can out of the class driver and throw it away.
X;
X17$:`009POPR`009#^M<R0,R2,R3,R4,R5>`009; Switch back to TW UCB
X18$:`009BICB`009#UCB$M_INT, UCB$W_STS(r5)
X`009JSB`009@UCB$L_TT_GETNXT(r5)
X`009TSTB`009UCB$B_TT_OUTYPE(r5)
X`009BNEQ`00918$
X`009RSB
X
X20$:
X`009MOVB`009R3,UCB$W_TT_HOLD(R5)`009; Save output character
X`009BISW`009#TTY$M_TANK_HOLD,-`009; Signal charater in tank
X`009`009UCB$W_TT_HOLD(R5)
X`009BRB`00910$
X`012
X`009.PAGE
X`009.SBTTL`009Port Routines Stop,Resume,XON,XOFF
X;++
X; TW$XOFF -`009Send Xoff
X; TW$XON -`009Send Xon
X; TW$ABORT -`009Abort current output
X;
X; Functional Description:
X;
X;`009These routines are used by the terminal class driver to
X;`009control output on the port
X;
X; Inputs:
X;
X;`009R5 = UCB Address
X;
X; Outputs:
X;
X;`009R5 = UCB Address
X;--
X`009TTY$M_TP_XOFF = 8
X`009TTY$V_TP_XOFF = 3
X`009ASSUME`009TTY$M_TP_XOFF EQ TTY$M_TP_DLLOC+4
X`009ASSUME  TTY$V_TP_XOFF EQ TTY$V_TP_DLLOC+1
X
XTW$XOFF:
X`009PUSHR`009#^M<R0,R1,R4> `009`009; Save registers
X`009MOVAB`009UCB$L_TW_XOFF_AST(R5),R4 ; Get address of AST list
X`009CMPB`009R3,#^X13`009`009; Is XOFF
X`009BNEQ`009TW$XON_XOFF_CMN`009; NEQ not XONN use common rotuine
X`009BISB`009#TTY$M_TP_XOFF,`009-`009; Set XOFF bit in UCB
X`009`009UCB$B_TP_STAT(R5)`009;
X`009BRB`009TW$XON_XOFF_CMN`009`009; Do common processing
X
XTW$XON:
X`009PUSHR`009#^M<R0,R1,R4>`009`009; Save registers
X`009MOVAB`009UCB$L_TW_XON_AST(R5),R4 ; Get address of AST list
X`009CMPB`009R3,#^X11`009`009; Is it XON
X`009BNEQ`009TW$XON_XOFF_CMN`009; NEQ not XONN use common rotuine
X`009BICB`009#TTY$M_TP_XOFF,`009-`009; Clear XOFF bit in UCB
X`009`009UCB$B_TP_STAT(R5)`009;
X;
X; Schedule xon/xoff to be sent, and changed schedule bit mask
X;
XTW$XON_XOFF_CMN:`009`009`009; Common XONN/XOFF code
X`009TSTL`009(R4)`009`009`009; See if AST present
X`009BEQL`00930$`009`009`009; EQL no AST to deliver
X`009MOVL`009R4,R0`009`009`009; Copy list address
X
X10$:
X`009MOVL`009(R0),R0`009`009`009; Get next entry
X`009BEQL`00920$`009`009`009; All done so deliver ASTs
X`009MOVZBW`009R3,ACB$L_KAST+4(R0)`009; Store new param value
X`009BRB`00910$`009`009`009; Look for another entry
X20$:
X`009JSB`009G^COM$DELATTNAST`009; Deliver the ASTs
X30$:
X`009POPR`009#^M<R0,R1,R4>`009`009; Restore registers
X`009BISW`009#TTY$M_TANK_PREMPT,UCB$W_TT_HOLD(R5)`009; Schedule xon
X`009MOVB`009R3,UCB$B_TT_PREMPT(R5)`009`009`009; Save character
X`009RSB
X
X;
X; Abort any port currently active
X;
XTW$ABORT:
X`009BBCC`009#TTY$V_TANK_BURST, -`009; reset burst active
X`009`009UCB$W_TT_HOLD(R5),10$`009;
X10$:
X`009RSB
X`012
XTW_END:`009`009`009`009; End of driver
X
X`009.END
$ GOSUB UNPACK_FILE
$ EXIT
