[comp.os.vms] VMS pseudo-terminal drivers 3/5

KVC@BUSTER.NRC.COM (Kevin Carosso) (06/22/88)

+-+-+-+ Beginning of part 3 +-+-+-+
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 = 1281048260
$ COPY SYS$INPUT VMS_SHARE_DUMMY.DUMMY
X`009.TITLE`009PYDRIVER - Pseudo terminal driver interface
X`009.IDENT 'V05-006A'
X;
X; Comment out the following line if NOT building for VMS V4 (in other
X; words comment out if you want a V5 driver).
X;
X;;;`009VMS_V4 = 1
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;`009`009`009
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;--
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; Define ACB
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
X.IF`009NOT_DEFINED`009VMS_V4
X`009$SPLCODDEF`009`009`009; Spin lock code definitions
X.ENDC
X
X`009$SSDEF`009`009`009`009; DEFINE System Status
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`009DEFINED`009VMS_V4
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`009DEFINED`009VMS_V4
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`009DEFINED`009VMS_V4
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
-+-+-+-+-+ End of part 3 +-+-+-+-+-