{$C Copyright (c) 1983 SAGE Computer Technology, All Rights Reserved}

{ SAGE II/IV Utility Program

  File:	    SG4.UTIL.TEXT
  Date:	     7-Jan-84
  Version:  1.3


  Development History:

  1    23-Mar-83  Initial SAGE IV release.
  1.1	3-May-83  Added restrictions for Multi-User configuration.
		  Allow copy of Multi-User bootstrap.
  1.2  29-Jul-83  Added new device information field for CP/M.
		  Changed NCI 80 track format to remove IBM flag.
		  Added 10 sector per track format.
		  Cancel redirection of some errors.
		  Exit cleanly on no file for copy bootstrap.
		  Fixed limit on subdevices.
		  Put in check to only handle BIOS 2.3.
		  Changed temporary Winchester drive 1 to device 17.
  1.3	7-Jan-84  Changed Universal Media to IBM format.  Added IBM 1280
		  block floppies.  Allow BIOS 2.4 & 3.3.
		  Restore original channel map while doing on-line changes.
		  Only allow Multi-User access to visible devices.
		  Allow Multi-User restricted update priviledges.
		  Allow Multi-User to move to ship position.

 

  Description:

  This program provides a set of utility functions for the
  SAGE II and SAGE IV Computer systems.	 These functions are:
  
    A.	On-line BIOS Memory Configuration Management.
    B.	Off-line BIOS File Configuration Management.
    C.	Bootstrap Copy Facility.
    D.	Floppy Diskette Formatting.

}

PROGRAM SG4_Util;

USES {$U COMMANDIO.CODE} COMMANDIO,
     {$U MNU_UNIT.CODE} MNU_Unit,
     {$U SAGETOOLS.CODE} SIO_Unit,
     {$U SCREENOPS.CODE} SCREENOPS,
     {$U CONFIGSAGE.CODE} Config_Sage;

CONST
  Version = '1.3';
  
  MN_MAIN	= 0; M_MAIN   = 'MAIN';
  MN_OLC	= 1; M_OLC    = 'OLC';
  MN_TRM	= 2; M_TRM    = 'TRM';
  MN_REM	= 3; M_REM    = 'REM';
  MN_FL4	= 4; M_FL4    = 'FL4';
  MN_FL5	= 5; M_FL5    = 'FL5';
  MN_RDK	= 6; M_RDK    = 'RDK';
  MN_PRT	= 7; M_PRT    = 'PRT';
  MN_XS1	= 8; M_XS1    = 'XS1';
  MN_XS2	= 9; M_XS2    = 'XS2';
  MN_XS3	=10; M_XS3    = 'XS3';
  MN_XS4	=11; M_XS4    = 'XS4';
  MN_WD1	=12; M_WD1    = 'WD1';
  MN_WD2	=13; M_WD2    = 'WD2';
  MN_WD3	=14; M_WD3    = 'WD3';
  MN_WD4	=15; M_WD4    = 'WD4';
  MN_TAJ	=16; M_TAJ    = 'TAJ';
  MN_MAP	=17; M_MAP    = 'MAP';
  MN_BFC	=18; M_BFC    = 'BFC';
  MN_FMT	=19; M_FMT    = 'FMT';
  MN_BSC	=20; M_BSC    = 'BSC';
  MN_LLC	=21; M_LLC    = 'LLC';
  
  MN_BAUD	=22; M_BAUD   = 'BAUD';
  MN_PAR	=23; M_PAR    = 'PAR';
  MN_STOP	=24; M_STOP   = 'STOP';
  MN_DATA	=25; M_DATA   = 'DATA';
  
  MN_RBAUD	=26; M_RBAUD  = 'RBAUD';
  MN_RPAR	=27; M_RPAR   = 'RPAR';
  
  MN_FL4D	=29; M_FL4D   = 'FL4D';
  MN_FL5D	=30; M_FL5D   = 'FL5D';
  MN_FLS	=31; M_FLS    = 'FLS';
  
  MN_PMODE	=32; M_PMODE  = 'PMODE';
  MN_MAP1	=33; M_MAP1   = 'MAP1';
  
  MN_OPSY	=34; M_OPSY   = 'OPSY';
  MN_SHIP	=35; M_SHIP   = 'SHIP';
  MN_PPORT	=36; M_PPORT  = 'PPORT';
  MN_DINFO	=37; M_DINFO  = 'DINFO';
  MN_WD1INFO	=38; M_WD1INFO= 'WD1INFO';
  MN_WD2INFO	=39; M_WD2INFO= 'WD2INFO';
  MN_WD3INFO	=40; M_WD3INFO= 'WD3INFO';
  MN_WD4INFO	=41; M_WD4INFO= 'WD4INFO';
  
  
  S_Xon	     = 0;
  S_TBreak   = 1;
  
  S_XonIn    = 0;
  S_XonOut   = 1;
  S_DSRpoll  = 2;
  S_DSRinter = 3;

  
  D_BR19200  = 0;
  D_BR9600   = 1;
  D_BR4800   = 2;
  D_BR2400   = 3;
  D_BR2000   = 4;
  D_BR1800   = 5;
  D_BR1200   = 6;
  D_BR600    = 7;
  D_BR300    = 8;
  D_BR200    = 9;
  D_BR150    =10;
  D_BR110    =11;
  D_BR75     =12;
  D_BR50     =13;
  D_BRdipsw  =14;

  D_EvenP    = 0;
  D_OddP     = 1;
  D_DisP     = 2;
  D_DipP     = 3;

  D_1Stop    = 0;
  D_1_5Stop  = 1;
  D_2Stop    = 2;

  D_5Data    = 0;
  D_6Data    = 1;
  D_7Data    = 2;
  D_8Data    = 3;

  D_WNcyl    = 1;
  D_WBPS     = 2;
  D_WStepT   = 3;
  D_WSlewT   = 4;
  D_WSctr    = 5;
  D_Wsettle  = 6;
  D_Wprecomp = 7;
  D_Wstype   = 8;
  D_Wtest    = 9;
  D_Wship    =10;
  D_Wheadc   =11;
  D_Wlowc    =12;
  D_Whighc   =13;
  D_Wheads   =14;
  D_WSPT     =15;
  D_Wselect  =16;
  D_Wretries =17;
  D_Wsync    =18;
  D_Wexhst   =19;
  D_Wrawrt   =20;
  D_Wwtries  =21;

  D_Fsides   = 0;
  D_FNcyl    = 1;
  D_FSPT     = 2;
  D_FIBM     = 3;
  D_Fretries = 4;
  D_Fignore  = 5;
  D_F48on96  = 6;
  D_FNCI     = 7;
  D_FRAW     = 8;
  D_FBPS     = 9;
  D_FGap3    =10;
  D_Fdataleng=11;
  D_FGap3F   =12;
  D_Fforpat  =13;
  D_Fforskew =14;
  D_Fmotoron =15;
  
  D_Fdensity = 0;
  D_Fsteprate= 1;
  D_Fheadload= 2;
  D_Fheadunld= 3;
  
  D_FCnonstan= 0;
  D_FCsg1280 = 1;
  D_FCsg640  = 2;
  D_FCibm320 = 3;
  D_FCibm640 = 4;
  D_FCnci400 = 5;
  D_FCnci800 = 6;
  D_FCnci1600= 7;
  D_FCuniv   = 8;
  D_FCnodrv  = 9;
  D_FCsg1600 =10;
  D_FCibm1280=11;
  
  D_RDbase   = 0;
  D_RDtop    = 1;
  D_RDboot   = 2;
  
  D_Pinter   = 0;
  D_Ppolltime= 1;
  D_Ptimeout = 2;
  
  D_Pmode    = 0;
  D_Pnolf    = 1;
    
  D_Pserial  = 0;
  D_Ppar     = 1;
  D_Pex1     = 2;
  D_Pex2     = 3;
  D_Pex3     = 4;
  D_Pex4     = 5;
  D_Pdisable = 6;
  
  D_Tseconds = 0;
  D_Tdays    = 1;

  NumDevices =33;

VAR
  Device:INTEGER;
  DevChange:ARRAY[0..NumDevices] OF BOOLEAN;
  DevDefined:ARRAY[0..NumDevices] OF BOOLEAN;
  DevNumber:ARRAY[0..NumDevices] OF INTEGER;
  Config:Conf_File;
  F:FILE;
  FileName:STRING;
  TempMap:Conf_ChanTable;
  TermCopy:Conf_Terminal;
  TempWinch:Conf_Winch;
  TempFloppy:Conf_Floppy;
  SAGE4:BOOLEAN;
  MultiUser:BOOLEAN;
  MultiWrite:BOOLEAN;
  OldChanTable:Conf_ChanTable;

{$I SG4.UTIL1.TEXT} { Menu initialization }

PROCEDURE LoadConfig;
VAR
  I,J:INTEGER;
  Sub:INTEGER;
  Ver:PACKED RECORD
	Major:0..255;
	Minor:0..255;
	Dummy:ARRAY[0..100] OF INTEGER;
      END;
BEGIN
  FILLCHAR(Ver,SIZEOF(Ver),0);
  UNITREAD(128,Ver,0,4,0);
  IF Ver.Major = 3 THEN MultiUser:=TRUE ELSE MultiUser:=FALSE;
  SAGE4:=Conf_SGIV;
  WITH Config DO
    BEGIN
      Conf_RD_ChanTable(ChanTable);
      OldChanTable:=ChanTable;
      FOR I:= 0 TO NumDevices DO
	BEGIN
	  DevChange[I]:=FALSE;
	  DevDefined[I]:=FALSE;
	  DevNumber[I]:=0;
	END;
      IF MultiUser THEN
	BEGIN
	  FOR I:= 0 TO 31 DO
	    BEGIN
	      CASE ChanTable[I].Channel OF
		1,2:BEGIN
		      UNITREAD(128,Terminal,0,0,1);
		      TermCopy:=Terminal;
		      DevDefined[1]:=TRUE;
		      DevNumber[1]:=I;
		    END;
		4:BEGIN
		    Conf_RD_Floppy(I,Floppy0);
		    DevDefined[ChanTable[I].Channel]:=TRUE;
		    DevNumber[ChanTable[I].Channel]:=I;
		  END;
		5:BEGIN
		    Conf_RD_Floppy(I,Floppy1);
		    DevDefined[ChanTable[I].Channel]:=TRUE;
		    DevNumber[ChanTable[I].Channel]:=I;
		  END;
		6:BEGIN
		    UNITREAD(128,Printer,0,0,I);
		    DevDefined[ChanTable[I].Channel]:=TRUE;
		    DevNumber[ChanTable[I].Channel]:=I;
		  END;
		7,8:BEGIN
		      UNITREAD(128,Remote,0,0,I);
		      DevDefined[7]:=TRUE;
		      DevNumber[7]:=I;
		    END;
		9:IF SAGE4 THEN
		  BEGIN
		    Sub:=ChanTable[I].SubChannel;
		    IF Sub < 16 THEN
		      BEGIN
			UNITREAD(128,Winch1,0,0,I);
			DevDefined[17]:=TRUE;
			DevNumber[17]:=I;
		      END
		    ELSE
		      IF Sub < 32 THEN
			BEGIN
			  UNITREAD(128,Winch2,0,0,I);
			  DevDefined[18]:=TRUE;
			  DevNumber[18]:=I;
			END
		      ELSE
			IF Sub < 48 THEN
			  BEGIN
			    UNITREAD(128,Winch3,0,0,I);
			    DevDefined[19]:=TRUE;
			    DevNumber[19]:=I;
			  END
			ELSE
			  IF Sub < 64 THEN
			    BEGIN
			      UNITREAD(128,Winch4,0,0,I);
			      DevDefined[20]:=TRUE;
			      DevNumber[20]:=I;
			    END;
		  END;
	       11,21,22,23:BEGIN
		    UNITREAD(128,RamDisk,0,0,I);
		    DevDefined[ChanTable[I].Channel]:=TRUE;
		    DevNumber[ChanTable[I].Channel]:=I;
		  END;
	       13,14:IF SAGE4 THEN
		  BEGIN
		    UNITREAD(128,XSerial1,0,0,I);
		    DevDefined[28]:=TRUE;
		    DevNumber[28]:=I;
		  END;
	       15,16:IF SAGE4 THEN
		  BEGIN
		    UNITREAD(128,XSerial2,0,0,I);
		    DevDefined[29]:=TRUE;
		    DevNumber[29]:=I;
		  END;
	       17,18:IF SAGE4 THEN
		  BEGIN
		    UNITREAD(128,XSerial3,0,0,I);
		    DevDefined[30]:=TRUE;
		    DevNumber[30]:=I;
		  END;
	       19,20:IF SAGE4 THEN
		  BEGIN
		    UNITREAD(128,XSerial4,0,0,I);
		    DevDefined[31]:=TRUE;
		    DevNumber[31]:=I;
		  END;
	      END; {Case}
	    END;
	  DevDefined[32]:=TRUE; { Channel Map }
	  IF SAGE4 THEN Conf_RD_WDInfo(WinDevInfo);
	  Conf_RD_System(TimeAdj);
	  DevDefined[0]:=TRUE;
	  Conf_RD_OpSystem(Opsystem);
	  DevDefined[33]:=TRUE;
	  Conf_RD_DevInfo(DevInfo);
	  Conf_WT_OpSystem(OpSystem);
	  IF IORESULT <> 0 THEN MultiWrite:=FALSE ELSE MultiWrite:=TRUE;
	END
      ELSE
	FOR I:= 0 TO NumDevices DO
	  BEGIN
	    DevDefined[I]:=TRUE;
	    DevNumber[I]:=I;
	  END;
      IF NOT MultiUser THEN
	BEGIN
	  FOR I:= 0 TO 12 DO
	    BEGIN
	      TempMap[I].Channel:=I;
	      TempMap[I].SubChannel:=0;
	    END;
	  FOR I:= 13 TO 16 DO
	    BEGIN
	      TempMap[I].Channel:=0;
	      TempMap[I].SubChannel:=0;
	    END;
	  TempMap[17].Channel:=9;
	  TempMap[17].SubChannel:=0;
	  TempMap[18].Channel:=9;
	  TempMap[18].SubChannel:=16;
	  TempMap[19].Channel:=9;
	  TempMap[19].SubChannel:=32;
	  TempMap[20].Channel:=9;
	  TempMap[20].SubChannel:=48;
	  FOR I:= 21 TO 27 DO
	    BEGIN
	      TempMap[I].Channel:=0;
	      TempMap[I].SubChannel:=0;
	    END;
	  FOR I:= 28 TO 31 DO
	    BEGIN
	      TempMap[I].Channel:=I-28+13;
	      TempMap[I].SubChannel:=0;
	    END;
	  Conf_WT_ChanTable(TempMap);
	  Conf_RD_Terminal(Terminal);
	  TermCopy:=Terminal;
	  Conf_RD_Remote(Remote);
	  Conf_RD_Printer(Printer);
	  Conf_RD_Floppy(4,Floppy0);
	  Conf_RD_Floppy(5,Floppy1);
	  Conf_RD_RamDisk(RamDisk);
	  Conf_RD_System(TimeAdj);
	  Conf_RD_OpSystem(OpSystem);
	  Conf_RD_DevInfo(DevInfo);
	  IF SAGE4 THEN
	    BEGIN
	      Conf_RD_Winch(17,Winch1);
	      Conf_RD_Winch(18,Winch2);
	      Conf_RD_Winch(19,Winch3);
	      Conf_RD_Winch(20,Winch4);
	      Conf_RD_XSerial(28,XSerial1);
	      Conf_RD_XSerial(29,XSerial2);
	      Conf_RD_XSerial(30,XSerial3);
	      Conf_RD_XSerial(31,XSerial4);
	      Conf_RD_WDInfo(WinDevInfo);
	    END;
	  Conf_WT_ChanTable(OldChanTable);
	END;
    END;
END;

PROCEDURE StoreConfig;
VAR
  I:INTEGER;
  MustWrite:BOOLEAN;
  Dummy:BOOLEAN;
BEGIN
  IF MNU_Aborted THEN EXIT(StoreConfig);
  MustWrite:=FALSE;
  FOR I:= 0 TO NumDevices DO
    IF DevChange[I] THEN MustWrite:=TRUE;
  IF NOT MustWrite THEN EXIT(StoreConfig);
  MNU_ClrScreen;
  IF MNU_YesorNo('Make on-line changes? ') THEN
    WITH Config DO
      BEGIN
	IF NOT MultiUser THEN Conf_WT_ChanTable(TempMap);
	IF DevChange[1] THEN
	  BEGIN
	    IF (Terminal.BaudRate <> TermCopy.BaudRate) OR
	       (Terminal.DataBits <> TermCopy.DataBits) OR
	       (Terminal.StopBits <> TermCopy.StopBits) OR
	       (Terminal.ParityEnabled <> TermCopy.ParityEnabled) OR
	       (Terminal.ParityEven <> TermCopy.ParityEven) THEN
	      BEGIN
		IF MNU_YesorNo(
		'Do you really want to change the terminal now?') THEN
		   Conf_WT_Terminal(Terminal);
	      END
	    ELSE
	      UNITWRITE(128,Terminal,0,0,DevNumber[1]);
	  END;
	IF DevChange[7] THEN UNITWRITE(128,Remote,0,0,DevNumber[7]);
	IF DevChange[6] THEN UNITWRITE(128,Printer,0,0,DevNumber[6]);
	IF DevChange[4] THEN Conf_WT_Floppy(DevNumber[4],Floppy0);
	IF DevChange[5] THEN Conf_WT_Floppy(DevNumber[5],Floppy1);
	IF DevChange[11] THEN UNITWRITE(128,RamDisk,0,0,DevNumber[11]);
	IF DevChange[0] THEN Conf_WT_System(TimeAdj);
	IF DevChange[17] THEN Conf_WT_Winch(DevNumber[17],Winch1);
	IF DevChange[18] THEN Conf_WT_Winch(DevNumber[18],Winch2);
	IF DevChange[19] THEN Conf_WT_Winch(DevNumber[19],Winch3);
	IF DevChange[20] THEN Conf_WT_Winch(DevNumber[20],Winch4);
	IF DevChange[33] THEN Conf_WT_OpSystem(OpSystem);
	IF DevChange[28] THEN Conf_WT_XSerial(DevNumber[28],XSerial1);
	IF DevChange[29] THEN Conf_WT_XSerial(DevNumber[29],XSerial2);
	IF DevChange[30] THEN Conf_WT_XSerial(DevNumber[30],XSerial3);
	IF DevChange[31] THEN Conf_WT_XSerial(DevNumber[31],XSerial4);
	IF NOT MultiUser THEN
	  BEGIN
	    Conf_WT_DevInfo(DevInfo);
	    Conf_WT_WDInfo(WinDevInfo);
	    Conf_WT_ChanTable(ChanTable);
	  END;
      END;
END;

PROCEDURE FileRead;
VAR
  I:INTEGER;
  Dummy:BOOLEAN;
BEGIN
  MultiUser:=FALSE;
  FOR I:= 0 TO NumDevices DO DevChange[I]:=FALSE;
  MNU_ClrScreen;
  WRITE('BIOS file name: ');
  READLN(FileName);
  WRITELN;
  IF LENGTH(FileName)=0 THEN
    BEGIN
      MNU_Aborted:=TRUE;
      EXIT(FileRead);
    END;
  {$I-}
  RESET(F,FileName);
  {$I+}
  IF IORESULT<>0 THEN
    BEGIN
      Exception(TRUE);
      WRITE('Could not open ',FileName);
      MNU_Reject:=TRUE;
    END
  ELSE
    BEGIN
      {$I-}
      I:=BLOCKREAD(F,Config,(SIZEOF(Config)-1) DIV 512,1);
      {$I+}
      IF IORESULT<>0 THEN
	BEGIN
	  Exception(TRUE);
	  WRITE('Error reading ',FileName);
	  MNU_Reject:=TRUE;
	  CLOSE(F);
	END
      ELSE
	WITH Config DO
	  BEGIN
	    IF (Header[6]<>1) AND (Header[6]<>256) THEN
	      BEGIN
		Exception(TRUE);
		WRITE('Illegal code file format - wrong byte sex');
		MNU_Reject:=TRUE;
		CLOSE(F);
	      END
	    ELSE
	      BEGIN
		IF Header[12]<>-1 THEN
		  BEGIN
		    Exception(TRUE);
		    WRITE('File has DataSize of ',Header[12],
			    ' instead of -1');
		    MNU_Reject:=TRUE;
		    CLOSE(F);
		  END
		ELSE
		  BEGIN
		    IF (Name[0]='B') AND
		       (Name[1]='I') AND
		       (Name[2]='O') AND
		       (Name[3]='S') THEN
		      BEGIN
			IF BiosVersion = 3 THEN
			  BEGIN
			    Exception(TRUE);
			    WRITE('Cannot configure Multi-User BIOS');
			    CLOSE(F);
			    MNU_Reject:=TRUE;
			  END
			ELSE
			  BEGIN
			    WRITELN('BIOS Version ',BiosVersion,'.',
				     BiosSubVersion,
				     ' header read successfully');
			    WRITELN('Size including buffers: ',BiosSize+
				     BiosBuffers,' bytes');
			    WRITELN;
			    IF (BiosVersion<>2) OR ((BiosSubVersion<>3) AND
			       (BiosSubVersion <> 4)) THEN
			      BEGIN
				Exception(TRUE);
				WRITE('This SAGE4UTIL is only compatible',
				      ' with BIOS version 2.3 or 2.4');
				CLOSE(F);
				MNU_Reject:=TRUE;
			      END
			    ELSE
			      BEGIN
				TermCopy:=Config.Terminal;
				Dummy:=sc_space_wait(FALSE);
				SAGE4:=Config.BiosVersion=2;
			      END;
			  END;
		      END
		    ELSE
		      BEGIN
		      Exception(TRUE);
		      WRITE('Data in ',FileName,' was not BIOS code file');
		      CLOSE(F);
		      MNU_Reject:=TRUE;
		      END;
		  END;
	      END;
	  END;
    END;
END;

PROCEDURE FileWrite;
VAR
  ch:CHAR;
  MustWrite:BOOLEAN;
  I:INTEGER;
  Question:STRING;
  Dummy:BOOLEAN;

BEGIN
  MustWrite:=FALSE;
  IF NOT MNU_Aborted THEN
    FOR I:= 0 TO NumDevices DO
      IF DevChange[I] THEN MustWrite:=TRUE;
  IF NOT MustWrite THEN
    BEGIN
      CLOSE(F);
      EXIT(FileWrite);
    END;
  MNU_ClrScreen;
  Question:=CONCAT('Ready to write changes to ',Filename,': ');
  IF MNU_YesorNo(Question) THEN 
    BEGIN
      {$I-}
      I:=BLOCKWRITE(F,Config,(SIZEOF(Config)-1) DIV 512,1);
      {$I+}
      IF IORESULT<>0 THEN
	BEGIN
	  Exception(TRUE);
	  WRITELN('Error writing new BIOS information to ',FileName);
	END
      ELSE
	BEGIN
	  WRITELN;
	  WRITELN('BIOS changes saved.');
	END;
      {$I-}
      CLOSE(F);
      {$I+}
      IF IORESULT<>0 THEN
	BEGIN
	  Exception(TRUE);
	  WRITELN('Error closing BIOS information file ',FileName);
	END;
    END
  ELSE
    BEGIN
      WRITELN;
      WRITELN('BIOS changes abandoned');
      CLOSE(F);
    END;
  Dummy:=sc_space_wait(FALSE);
END;


{$I SG4.UTIL2.TEXT} { Serial information}
{$I SG4.UTIL3.TEXT} { Floppy information}
{$I SG4.UTIL4.TEXT} { Bootstrap copy	}
{$I SG4.UTIL5.TEXT} { Floppy Formatter	}

PROCEDURE ShipPosition;
VAR
  TempChanTable:Conf_ChanTable;
  OldWinch:Conf_Winch;
  Drive:INTEGER;
  Cylinder:INTEGER;
  Dummy:INTEGER;
  DummyBoolean:BOOLEAN;
  CH:CHAR;
  Chan:INTEGER;
  Found:BOOLEAN;
  AnyFound:BOOLEAN;
  Ver:PACKED RECORD
	Major:0..255;
	Minor:0..255;
      END;
BEGIN
  MNU_ClrScreen;
  AnyFound:=FALSE;
  Conf_RD_ChanTable(TempChanTable);
  FILLCHAR(Ver,SIZEOF(Ver),0);
  UNITREAD(128,Ver,0,4,0);
  IF Ver.Major = 3 THEN
    BEGIN { Multi-User }
      FOR Drive := 0 TO 3 DO
	BEGIN
	  Found:=FALSE;
	  Chan:=0;
	  WHILE (NOT Found) AND (Chan < 32) DO
	    BEGIN
	      IF TempChanTable[Chan].Channel = 9 THEN
		IF (TempChanTable[Chan].SubChannel DIV 16) = Drive THEN
		  BEGIN
		    Conf_RD_Winch(Chan,OldWinch);
		    Cylinder:=OldWinch.ShipTrack;
		    UNITREAD(Chan,Dummy,1,Cylinder,16384);
		    IF IORESULT = 0 THEN
		      BEGIN
			WRITELN('Drive ',Drive,' positioned for shipping');
			Found:=TRUE;
			AnyFound:=TRUE;
		      END;
		  END;
	      Chan:=Chan+1;
	    END;
	END;
    END
  ELSE
    BEGIN { Single User }
      FOR Drive := 0 TO 3 DO
	BEGIN
	  Conf_Assign(9,9,Drive*16);
	  Conf_RD_Winch(9,OldWinch);
	  Cylinder:=OldWinch.ShipTrack;
	  UNITREAD(9,Dummy,1,Cylinder,16384);
	  IF IORESULT = 0 THEN
	    BEGIN
	      WRITELN('Drive ',Drive,' positioned for shipping');
	      AnyFound:=TRUE;
	    END;
	END;
      Conf_Restore;
    END;
  WRITELN;
  IF AnyFound THEN
    WRITELN('Ready to power system down')
  ELSE
    BEGIN
      WRITELN('Cannot position Winchester heads');
      WRITELN('Type space to continue');
    END;
  WRITELN;
  REPEAT
    READ(KEYBOARD,CH);
  UNTIL CH = ' ';
END;

PROCEDURE GetInfo;
BEGIN
  CASE MNU_MenuNumber OF
    MN_BAUD,
    MN_RBAUD:GetBaud;
    MN_PAR,
    MN_RPAR:GetParity;
    MN_STOP:GetStop;
    MN_DATA:GetData;
    MN_TRM:CASE MNU_ItemNumber OF
	     S_Xon:GetRXonIn;
	     S_TBreak:MNU_Boolean:=Config.Terminal.BreakAllowed;
	   END;
    MN_REM,
    MN_XS1,
    MN_XS2,
    MN_XS3,
    MN_XS4:CASE MNU_ItemNumber OF
	     S_XonIn:GetRXonIN;
	     S_XonOut:GetRXonOut;
	     S_DSRpoll:GetDSR;
	     S_DSRinter:GetDSRinter;
	   END;
    MN_WD1,
    MN_WD2,
    MN_WD3,
    MN_WD4:WITH TempWinch DO
	    CASE MNU_ItemNumber OF
	     D_WNcyl:MNU_Value:=Cylinders;
	     D_WBPS:MNU_Value:=BytesPerSector;
	     D_WStepT:MNU_Value:=StepTime;
	     D_WSlewT:MNU_Value:=SlewTime;
	     D_WSctr:MNU_Value:=StepCtr;
	     D_Wsettle:MNU_Value:=HeadSettleTime;
	     D_Wprecomp:MNU_Value:=PreCompTrack;
	     D_Wstype:MNU_Value:=SpecialType;
	     D_Wtest:MNU_Value:=Tests;
	     D_Wship:MNU_Value:=ShipTrack;
	     D_Wheadc:MNU_Value:=HeaderCount;
	     D_Wlowc:MNU_Value:=LowReadCounter;
	     D_Whighc:MNU_Value:=HighReadCounter;
	     D_Wheads:MNU_Value:=Heads;
	     D_WSPT:MNU_Value:=SectorsPerTrack;
	     D_Wselect:MNU_Value:=SelectBit;
	     D_Wretries:MNU_Value:=Tries-1;
	     D_Wsync:MNU_Value:=SyncBit;
	     D_Wexhst:MNU_Value:=ExtraHeadSettle;
	     D_Wwtries:MNU_Value:=WriteTries-1;
	     D_Wrawrt:MNU_Value:=RawTries-1;
	   END;
    MN_FL4,
    MN_FL5:MNU_Value:=WhatFloppy(TempFloppy);
    MN_FL4D,
    MN_FL5D:WITH TempFloppy DO
	     CASE MNU_ItemNumber OF
	       D_Fsides:MNU_Value:=Sides;
	       D_FNcyl:MNU_Value:=Cylinders;
	       D_FSPT:MNU_Value:=SectorsPerTrack;
	       D_FIBM:MNU_Boolean:=IBMflag;
	       D_Fretries:MNU_Value:=Tries-1;
	       D_Fignore:MNU_Boolean:=IgnoreErrors;
	       D_F48on96:MNU_Boolean:=DoubleStep;
	       D_FNCI:MNU_Boolean:=NCIflag;
	       D_FRAW:MNU_Boolean:=RAWflag;
	       D_FBPS:MNU_Value:=BytesPerSectors;
	       D_FGap3:MNU_Value:=Gap3;
	       D_Fdataleng:MNU_Value:=DataLength;
	       D_FGap3F:MNU_Value:=Gap3Format;
	       D_Fforpat:MNU_Value:=PatternFormat;
	       D_Fforskew:MNU_Value:=Skew;
	       D_Fmotoron:MNU_Value:=MotorOnDelay;
	     END;
    MN_FLS:WITH Config DO
	     CASE MNU_ItemNumber OF
	       D_Fdensity:MNU_Boolean:=Floppy0.MFMflag;
	       D_Fsteprate:MNU_Value:=Conf_RD_Conversion(4,
			     Conf_CvStepRate,Floppy0.StepRate);
	       D_Fheadload:MNU_Value:=Floppy0.Headload;
	       D_Fheadunld:MNU_Value:=Floppy0.HeadUnload;
	     END;
    MN_RDK:WITH Config.RamDisk DO
	     CASE MNU_ItemNumber OF
	       D_RDbase:BEGIN
			  MNU_Value:=BaseLow;
			  MNU_HighValue:=BaseHigh;
			END;
	       D_RDtop: BEGIN
			  MNU_Value:=TopLow;
			  MNU_HighValue:=TopHigh;
			END;
	       D_RDboot:MNU_Boolean:=BootRamDisk;
	     END;
     MN_PRT:WITH Config.Printer DO
	      CASE MNU_ItemNumber OF
		D_Pnolf:MNU_Boolean:=NOT NoLF;
	      END;
     MN_PMODE:WITH Config.Printer DO
		BEGIN
		  MNU_Value:=D_Pdisable;
		  CASE Config.ChanTable[6].Channel OF
		    8:MNU_Value:=D_Pserial;
		    6:MNU_Value:=D_Ppar;
		    13:MNU_Value:=D_Pex1;
		    14:MNU_Value:=D_Pex2;
		    15:MNU_Value:=D_Pex3;
		    16:MNU_Value:=D_Pex4;
		    0:MNU_Value:=D_Pdisable;
		  END;
		END;
    MN_PPORT:WITH Config.Printer DO
	       CASE MNU_ItemNumber OF
		 D_Ppolltime:MNU_Value:=PollTime;
		 D_Ptimeout:MNU_Value:=Timeout;
		 D_Pinter:MNU_BOOLEAN:= Mode = Conf_ParInterrupt;
	       END;
    MN_TAJ:WITH Config.TimeAdj DO
	     CASE MNU_ItemNumber OF
	       D_Tseconds:MNU_Value:=Seconds;
	       D_Tdays:MNU_Value:=Days;
	     END;
     MN_MAP1,
     MN_MAP:WITH Config DO
	      IF MNU_ItemNumber < 16 THEN
		MNU_Value:=ChanTable[MNU_ItemNumber].Channel
	      ELSE
		IF MNU_ItemNumber < 32 THEN
		  MNU_Value:=ChanTable[MNU_ItemNumber-16].SubChannel
		ELSE
		  IF MNU_ItemNumber < 48 THEN
		    MNU_Value:=ChanTable[MNU_ItemNumber-16].Channel
		  ELSE
		    IF MNU_ItemNumber < 64 THEN
		      MNU_Value:=ChanTable[MNU_ItemNumber-32].SubChannel;
     MN_OPSY:MNU_Value:=Config.OpSystem[MNU_ItemNumber];
     MN_DINFO:MNU_Value:= Config.DevInfo[MNU_ItemNumber];
     MN_WD1INFO:MNU_Value:=Config.WinDevInfo[0,MNU_ItemNumber];
     MN_WD2INFO:MNU_Value:=Config.WinDevInfo[1,MNU_ItemNumber];
     MN_WD3INFO:MNU_Value:=Config.WinDevInfo[2,MNU_ItemNumber];
     MN_WD4INFO:MNU_Value:=Config.WinDevInfo[3,MNU_ItemNumber];
   END;
END;

PROCEDURE PutInfo;
BEGIN
  IF (NOT (MNU_MenuNumber = MN_MAIN)) THEN
     IF MultiUser AND ((NOT MultiWrite) OR (NOT DevDefined[Device]) OR 
		      ((MNU_MenuNumber=MN_FLS) AND (NOT DevDefined[5])) OR
		      (MNU_MenuNumber IN [MN_TAJ,MN_MAP,MN_MAP1,MN_DINFO,
					  MN_WD1INFO,MN_WD2INFO,MN_WD3INFO,
					  MN_WD4INFO,MN_PMODE,MN_WD1,MN_WD2,
					  MN_WD3,MN_WD4,MN_RDK]))
      THEN
       BEGIN
	 MNU_Error;
	 WRITE('Cannot change this field under Multi-User');
	 MNU_Reject:=TRUE;
	 EXIT(PutInfo);
       END;
  CASE MNU_MenuNumber OF
    MN_MAIN:BEGIN
	      IF MNU_ItemNumber = MN_BSC THEN BootCopy
	      ELSE
		IF MNU_ItemNumber = MN_FMT THEN Format
		ELSE
		  IF MNU_ItemNumber = MN_SHIP THEN ShipPosition;
	      EXIT(PutInfo);
	    END;
    MN_BAUD,
    MN_RBAUD:PutBaud;
    MN_PAR,
    MN_RPAR:PutParity;
    MN_STOP:PutStop;
    MN_DATA:PutData;
    MN_TRM:CASE MNU_ItemNumber OF
	     S_Xon:PutRXonIn;
	     S_TBreak:Config.Terminal.BreakAllowed:=MNU_Boolean;
	   END;
    MN_REM,
    MN_XS1,
    MN_XS2,
    MN_XS3,
    MN_XS4:CASE MNU_ItemNumber OF
	     S_XonIn:PutRXonIN;
	     S_XonOut:PutRXonOut;
	     S_DSRpoll:PutDSR;
	     S_DSRinter:PutDSRinter;
	   END;
    MN_WD1,
    MN_WD2,
    MN_WD3,
    MN_WD4:WITH TempWinch DO
	    CASE MNU_ItemNumber OF
	     D_WNcyl:Cylinders:=MNU_Value;
	     D_WBPS:BytesPerSector:=MNU_Value;
	     D_WStepT:StepTime:=MNU_Value;
	     D_WSlewT:SlewTime:=MNU_Value;
	     D_WSctr:StepCtr:=MNU_Value;
	     D_Wsettle:HeadSettleTime:=MNU_Value;
	     D_Wprecomp:PreCompTrack:=MNU_Value;
	     D_Wstype:SpecialType:=MNU_Value;
	     D_Wtest:Tests:=MNU_Value;
	     D_Wship:ShipTrack:=MNU_Value;
	     D_Wheadc:HeaderCount:=MNU_Value;
	     D_Wlowc:LowReadCounter:=MNU_Value;
	     D_Whighc:HighReadCounter:=MNU_Value;
	     D_Wheads:Heads:=MNU_Value;
	     D_WSPT:SectorsPerTrack:=MNU_Value;
	     D_Wselect:SelectBit:=MNU_Value;
	     D_Wretries:Tries:=MNU_Value+1;
	     D_Wsync:SyncBit:=MNU_Value;
	     D_Wexhst:ExtraHeadSettle:=MNU_Value;
	     D_Wwtries:WriteTries:=MNU_Value+1;
	     D_Wrawrt:RawTries:=MNU_Value+1;
	   END;
    MN_FL4,
    MN_FL5:FloppyStandard(TempFloppy);
    MN_FL4D,
    MN_FL5D:WITH TempFloppy DO
	     CASE MNU_ItemNumber OF
	       D_Fsides:Sides:=MNU_Value;
	       D_FNcyl:Cylinders:=MNU_Value;
	       D_FSPT:SectorsPerTrack:=MNU_Value;
	       D_FIBM:IBMflag:=MNU_Boolean;
	       D_Fretries:Tries:=MNU_Value+1;
	       D_Fignore:IgnoreErrors:=MNU_Boolean;
	       D_F48on96:DoubleStep:=MNU_Boolean;
	       D_FNCI:NCIflag:=MNU_Boolean;
	       D_FRAW:RAWflag:=MNU_Boolean;
	       D_FBPS:BytesPerSectors:=MNU_Value;
	       D_FGap3:Gap3:=MNU_Value;
	       D_Fdataleng:DataLength:=MNU_Value;
	       D_FGap3F:Gap3Format:=MNU_Value;
	       D_Fforpat:PatternFormat:=MNU_Value;
	       D_Fforskew:Skew:=MNU_Value;
	       D_Fmotoron:MotorOnDelay:=MNU_Value;
	     END;
    MN_FLS:WITH Config DO
	     BEGIN
	       CASE MNU_ItemNumber OF
		 D_Fdensity:BEGIN
			      Floppy0.MFMflag:=MNU_Boolean;
			      Floppy1.MFMflag:=MNU_Boolean;
			    END;
		 D_Fsteprate:BEGIN
			       Floppy0.StepRate:=
				 Conf_WT_Conversion(DevNumber[4],
				 Conf_CvStepRate,MNU_Value);
			       Floppy1.StepRate:=
				 Conf_WT_Conversion(DevNumber[5],
				 Conf_CvStepRate,MNU_Value);
			     END;
		   D_Fheadload:BEGIN
				 Floppy0.Headload:=MNU_Value;
				 Floppy1.Headload:=MNU_Value;
			       END;
		   D_Fheadunld:BEGIN
				 Floppy0.HeadUnload:=MNU_Value;
				 Floppy1.HeadUnload:=MNU_Value;
			       END;
		 END;
	       DevChange[5]:=TRUE;
	     END;
    MN_RDK:WITH Config.RamDisk DO
	     CASE MNU_ItemNumber OF
	       D_RDbase:BEGIN
			  BaseLow:=MNU_Value;
			  BaseHigh:=MNU_HighValue;
			END;
	       D_RDtop: BEGIN
			  TopLow:=MNU_Value;
			  TopHigh:=MNU_HighValue;
			END;
	       D_RDboot:BootRamDisk:=MNU_Boolean;
	     END;
     MN_PRT:WITH Config.Printer DO
	      CASE MNU_ItemNumber OF
		D_Pnolf:NoLF:=NOT MNU_Boolean;
	      END;
     MN_PMODE:WITH Config.ChanTable[6] DO
		BEGIN
		  CASE MNU_ItemNumber OF
		    D_Pserial:Channel:=8;
		    D_Ppar:Channel:=6;
		    D_Pex1:Channel:=13;
		    D_Pex2:Channel:=14;
		    D_Pex3:Channel:=15;
		    D_Pex4:Channel:=16;
		    D_Pdisable:Channel:=0;
		  END;
		END;
    MN_PPORT:WITH Config.Printer DO
	       CASE MNU_ItemNumber OF
		 D_Pinter:IF MNU_BOOLEAN THEN Mode := Conf_ParInterrupt
			  ELSE
			    Mode := Conf_ParPoll;
		 D_Ppolltime:PollTime:=MNU_Value;
		 D_Ptimeout:Timeout:=MNU_Value;
	       END;
    MN_TAJ:WITH Config.TimeAdj DO
	     CASE MNU_ItemNumber OF
	       D_Tseconds:Seconds:=MNU_Value;
	       D_Tdays:Days:=MNU_Value;
	     END;
     MN_MAP1,
     MN_MAP:WITH Config DO
	      IF MNU_ItemNumber < 16 THEN
		ChanTable[MNU_ItemNumber].Channel:=MNU_Value
	      ELSE
		IF MNU_ItemNumber < 32 THEN
		  ChanTable[MNU_ItemNumber-16].SubChannel:=MNU_Value
		ELSE
		  IF MNU_ItemNumber < 48 THEN
		    ChanTable[MNU_ItemNumber-16].Channel:=MNU_Value
		  ELSE
		    IF MNU_ItemNumber < 64 THEN
		      ChanTable[MNU_ItemNumber-32].SubChannel:=MNU_Value;
     MN_OPSY:Config.OpSystem[MNU_ItemNumber]:=MNU_Value;
     MN_DINFO:Config.DevInfo[MNU_ItemNumber]:=MNU_Value;
     MN_WD1INFO:Config.WinDevInfo[0,MNU_ItemNumber]:=MNU_Value;
     MN_WD2INFO:Config.WinDevInfo[1,MNU_ItemNumber]:=MNU_Value;
     MN_WD3INFO:Config.WinDevInfo[2,MNU_ItemNumber]:=MNU_Value;
     MN_WD4INFO:Config.WinDevInfo[3,MNU_ItemNumber]:=MNU_Value;
  END;
  DevChange[Device]:=TRUE;
END;

BEGIN { Main Program }
  Device:=0;
  MEMLOCK('OSUTIL,SEGSCCHE');
  InitMenu;
  MNU_Show(M_MAIN);
  REPEAT
    MNU_Loop;
    CASE MNU_State OF
      MNU_Get:GetInfo;
      MNU_Put:PutInfo;
      MNU_ReEnter:IF MNU_MenuNumber = MN_Main THEN MNU_Aborted:=FALSE;
      MNU_Enter:BEGIN
		  IF (NOT SAGE4) AND
		   (MNU_MenuNumber IN [MN_XS1,MN_XS2,MN_XS3,MN_XS4,
				       MN_WD1,MN_WD2,MN_WD3,MN_WD4,
				       MN_WD1INFO,MN_WD2INFO,MN_WD3INFO,
				       MN_WD4INFO]) THEN
		      BEGIN
			MNU_Reject:=TRUE;
			WRITE('Only valid for system with Winchester board');
		      END
		  ELSE
		    BEGIN
		      CASE MNU_MenuNumber OF
			MN_OLC:LoadConfig;
			MN_TRM:Device:=1;
			MN_REM:Device:=7;
			MN_RDK:Device:=11;
			MN_PPORT,
			MN_PRT:Device:=6;
			MN_XS1:Device:=28;
			MN_XS2:Device:=29;
			MN_XS3:Device:=30;
			MN_XS4:Device:=31;
			MN_FLS:Device:=4;
			MN_WD1:BEGIN
				 TempWinch:=Config.Winch1;
				 Device:=17;
			       END;
			MN_WD2:BEGIN
				 TempWinch:=Config.Winch2;
				 Device:=18;
			       END;
			MN_WD3:BEGIN
				 TempWinch:=Config.Winch3;
				 Device:=19;
			       END;
			MN_WD4:BEGIN
				 TempWinch:=Config.Winch4;
				 Device:=20;
			       END;
			MN_FL4,
			MN_FL4D:BEGIN
				  TempFloppy:=Config.Floppy0;
				  Device:=4;
				END;
			MN_FL5,
			MN_FL5D:BEGIN
				  TempFloppy:=Config.Floppy1;
				  Device:=5;
				END;
			MN_BFC:FileRead;
			MN_MAP,
			MN_MAP1:Device:=32;
			MN_OPSY:Device:=33;
			MN_TAJ:Device:=0;
		      END;
		      IF MultiUser AND (MNU_MenuNumber IN [MN_TRM,MN_REM,
				       MN_RDK,MN_PRT,MN_XS1,MN_XS2,MN_XS3,
				       MN_XS4,MN_FLS,MN_WD1,MN_WD2,MN_WD3,
				       MN_WD4,MN_FL4,MN_FL4D,MN_FL5,MN_FL5D,
				       MN_MAP,MN_MAP1,MN_OPSY,MN_TAJ]) THEN
			IF NOT DevDefined[Device] THEN
			  BEGIN
			    MNU_Error;
			    WRITE('Cannot access this information under',
				  ' Multi-User');
			    MNU_Reject:=TRUE;
			  END;
		    END;
	       END;
      MNU_Exit:BEGIN
		 CASE MNU_MenuNumber OF
		   MN_OLC:StoreConfig;
		   MN_WD1:Config.Winch1:=TempWinch;
		   MN_WD2:Config.Winch2:=TempWinch;
		   MN_WD3:Config.Winch3:=TempWinch;
		   MN_WD4:Config.Winch4:=TempWinch;
		   MN_FL4,
		   MN_FL4D:Config.Floppy0:=TempFloppy;
		   MN_FL5,
		   MN_FL5D:Config.Floppy1:=TempFloppy;
		   MN_BFC:FileWrite;
		 END;
		 END;
    END;
  UNTIL MNU_State = MNU_Done;
  MEMSWAP('OSUTIL,SEGSCCHE');
END.

                 