home *** CD-ROM | disk | FTP | other *** search
- (*
- (*
- * $Id: NoiseSaver.mod,v 2.3 1994/11/02 14:52:34 mh Exp mh $
- *
- *)
- *)
-
- MODULE NoiseSaver; (* $JOIN NoiseSaver.o *)
-
- IMPORT Conversions, Strings, SCSIDisk, Timer, Dos, Exec, sys: SYSTEM;
-
- PROCEDURE MyProc{"MyProc"}();
-
- VAR
- OrigProc["OrigProc"] : Exec.PROC;
- CallBack["CallBack"] : PROCEDURE(ior{9}:Exec.IOStdReqPtr);
- MyTask["MyTask"] : Exec.TaskPtr;
- ExecBase["ExecBase"] : Exec.ExecBasePtr;
-
-
- CONST
- Template = "DEVICE/K,TIMEOUT/N,UNIT/N,"
- "T2/N,U2/N,T3/N,U3/N,T4/N,U4/N,T5/N,U5/N,T6/N,U6/N,T7/N,U7/N,T8/N,U8/N,"
- "-H=HELP/S";
- Version = "$VER: NoiseSaver 2.1 (02.11.94)\n\o$";
- Help = "\e[1mNoiseSaver\e[0m © 1994 by Martin Horneffer\n\n"
- "\e[1mNoiseSaver\e[0m stops connected SCSI-Units, whenever they have been idle\n"
- "for at certain time, and automagically switches them on again when needed.\n\n"
- "You can specify up to 8 units with an optional timeout each.\n"
- "Default DEVICE is 'scsi.device', default TIMEOUT is 300 seconds.\n"
- "If no UNIT is specified, the units 0 to 6 are tried.\n\n"
- "When \e[1mNoiseSaver\e[0m is running, use\n"
- " 'BREAK $NoiseSaver e' to stop the drives,\n"
- " 'BREAK $NoiseSaver f' to start them and\n"
- " 'BREAK $NoiseSaver c' to quit \e[1mNoiseSaver\e[0m.\n";
- DefTimeout = 300;
- JMP = 4EF9H;
-
-
- TYPE
- UnitPtr = POINTER TO Unit;
- Unit = RECORD
- next : UnitPtr;
- unit : LONGINT;
- sem : Exec.SignalSemaphore;
- timer : Timer.TimeRequestPtr;
- timeout: LONGINT;
- ior : Exec.IOStdReqPtr;
- sc : SCSIDisk.SCSICmd;
- command: ARRAY 6 OF SHORTINT;
- active : BOOLEAN;
- stopped: BOOLEAN;
- haveSem: BOOLEAN;
- END;
- JmpPtr = POINTER TO Jmp;
- Jmp = STRUCT jmp: INTEGER; proc: Exec.PROC; END;
-
-
- VAR
- unitlist: UnitPtr;
- lastunit: UnitPtr;
- mp : Exec.MsgPortPtr;
- scsiBase: Exec.LibraryPtr;
-
- PROCEDURE TryUnit(deviceName: ARRAY OF CHAR; unit, timeout: LONGINT);
- (* $CopyArrays- *)
- VAR n: UnitPtr;
- BEGIN
- NEW(n);
- n.unit := unit;
- Exec.InitSemaphore(n.sem);
- n.timeout := timeout;
-
- n.ior := Exec.CreateIORequest(mp, SIZE(n.ior^));
- IF n.ior # NIL THEN
- IF Exec.OpenDevice(deviceName, unit, n.ior, LONGSET{}) = 0 THEN
- scsiBase := n.ior.device;
- n.timer := Exec.CreateIORequest(mp, SIZE(n.timer^));
- IF n.timer # NIL THEN
- IF Exec.OpenDevice( Timer.timerName, Timer.vBlank, n.timer, LONGSET{}) = 0 THEN
- n.timer.node.error := Exec.aborted;
- Exec.ReplyMsg(n.timer);
- IF lastunit = NIL THEN
- unitlist := n;
- ELSE
- lastunit.next := n;
- END;
- lastunit := n;
- RETURN;
- ELSE
- Exec.DeleteIORequest(n.timer);
- END;
- END;
- ELSE
- Exec.DeleteIORequest(n.ior);
- END;
- END;
-
- DISPOSE(n);
- END TryUnit;
-
-
- PROCEDURE (me:UnitPtr) StartStop(start: BOOLEAN);
- BEGIN
- IF me.active THEN RETURN END;
- IF NOT start AND NOT me.haveSem THEN
- Exec.ObtainSemaphore(me.sem);
- me.haveSem := TRUE;
- END;
- me.command[0] := 1BH; (* start/stop unit *)
- me.command[1] := 1; (* Bit1: immediate *)
- me.command[2] := 0;
- me.command[3] := 0;
- me.command[4] := 0; (* Bit1: start *)
- me.command[5] := 0;
- IF start THEN
- me.command[1] := 0;
- me.command[4] := 1;
- END;
- me.sc.data := NIL;
- me.sc.length := 0;
- me.sc.command := sys.ADR(me.command);
- me.sc.cmdLength:= SHORT(LEN(me.command));
- me.sc.flags := SHORTSET{SCSIDisk.read};
- IF start THEN
- Dos.PrintF("starting unit %ld..\n", me.unit);
- ELSE
- Dos.PrintF("stopping unit %ld..\n", me.unit);
- END;
- me.ior.command := SCSIDisk.scsiCmd;
- me.ior.data := sys.ADR(me.sc);
- me.ior.length := SIZE(me.sc);
-
- Exec.SendIO(me.ior);
- me.active := TRUE;
- me.stopped := NOT start;
- END StartStop;
-
-
- PROCEDURE (me:UnitPtr) Close();
- BEGIN
- IF me.active THEN Exec.OldWaitIO(me.ior) END;
- IF me.stopped THEN
- me.StartStop(TRUE);
- Exec.OldWaitIO(me.ior);
- IF me.haveSem THEN Exec.ReleaseSemaphore(me.sem) END;
- END;
- Exec.CloseDevice(me.ior);
- Exec.DeleteIORequest(me.ior);
-
- Exec.AbortIO(me.timer);
- Exec.OldWaitIO(me.timer);
- Exec.CloseDevice(me.timer);
- Exec.DeleteIORequest(me.timer);
- END Close;
-
-
- PROCEDURE (me:UnitPtr) HandleIO();
- BEGIN
- me.active := FALSE;
- Exec.Permit();
- IF me.ior.error # 0 THEN
- Dos.PrintF("unit %ld error: %ld, status: %ld\n",
- me.unit, me.ior.error, me.sc.status);
- ELSE
- Dos.PrintF("unit %ld ok.\n", me.unit);
- END;
- IF me.haveSem AND NOT me.stopped THEN
- Exec.ReleaseSemaphore(me.sem);
- me.haveSem := FALSE;
- Exec.AbortIO(me.timer);
- END;
- END HandleIO;
-
-
- PROCEDURE (me:UnitPtr) HandleTimer();
- VAR ok: BOOLEAN;
- BEGIN
- ok := me.timer.node.error = 0;
- me.timer.node.command := Timer.addRequest;
- me.timer.time.micro := 0;
- IF ok THEN
- me.timer.time.secs := 80000000H;
- ELSE
- me.timer.time.secs := me.timeout;
- END;
- Exec.SendIO(me.timer);
- Exec.Permit();
- IF ok # me.stopped THEN
- me.StartStop(me.stopped);
- END;
- END HandleTimer;
-
-
- PROCEDURE CallBackProc(ior{9}:Exec.IOStdReqPtr); (* $SaveRegs+ *)
- (* $Debug- $StackChk- $NilChk- $ClearVars- *)
- VAR u: UnitPtr;
- BEGIN
- u := unitlist;
- WHILE u # NIL DO
- IF u.ior.unit = ior.unit THEN
- Exec.AbortIO(u.timer);
- Exec.ObtainSemaphoreShared(u.sem);
- Exec.ReleaseSemaphore(u.sem);
- RETURN;
- END;
- u := u.next;
- END;
- END CallBackProc;
- (* $Debug= $StackChk= $NilChk= $ClearVars= *)
-
-
- PROCEDURE DispatchMsg(): BOOLEAN;
- VAR msg: Exec.MessagePtr; unit: UnitPtr;
- BEGIN
- Exec.Forbid();
- msg := Exec.GetMsg(mp);
- IF msg = NIL THEN
- Exec.Permit();
- RETURN FALSE;
- END;
- unit := unitlist;
- WHILE unit # NIL DO
- IF unit.timer = msg THEN
- unit.HandleTimer();
- RETURN TRUE;
- ELSIF unit.ior = msg THEN
- unit.HandleIO();
- RETURN TRUE;
- ELSE
- unit := unit.next;
- END;
- END;
- Exec.Permit(); (* impossible *)
- RETURN TRUE;
- END DispatchMsg;
-
-
- VAR
- newProc : Exec.PROC;
-
- args : STRUCT (as: Dos.ArgsStruct)
- deviceName: Exec.STRPTR;
- a: ARRAY 8 OF STRUCT
- t: UNTRACED POINTER TO LONGINT;
- u: UNTRACED POINTER TO LONGINT;
- END;
- help : LONGINT;
- END;
- RD : Dos.RDArgsPtr;
- jmp : JmpPtr;
- str : ARRAY 16 OF CHAR;
-
- unit : UnitPtr;
- timeout : LONGINT;
- flags : LONGSET;
- i : LONGINT;
-
- BEGIN
- IF Exec.SysBase.libNode.version < 37 THEN HALT(37) END;
- ExecBase := Exec.SysBase;
- sys.SETREG(0, sys.ADR(Version));
-
- MyTask := Exec.FindTask(NIL);
- mp := Exec.CreateMsgPort();
- IF mp = NIL THEN HALT(20) END;
-
- args.deviceName := sys.ADR("scsi.device");
- RD := Dos.ReadArgs (Template, args, NIL);
- IF (RD = NIL) OR (args.help # 0) THEN
- Dos.PrintF ("Template: %s\n\nHelp:\n\n%s\n", sys.ADR(Template), sys.ADR(Help));
- IF RD = NIL THEN HALT(20) ELSE HALT(0) END;
- END;
-
- timeout := DefTimeout;
- FOR i := 0 TO 7 DO
- IF args.a[i].t # NIL THEN
- timeout := args.a[i].t^;
- END;
- IF (timeout > 0) & (args.a[i].u # NIL) THEN
- TryUnit(args.deviceName^, args.a[i].u^, timeout);
- END;
- END;
- IF (timeout > 0) & (unitlist = NIL) THEN
- FOR i := 0 TO 6 DO
- TryUnit(args.deviceName^, i, timeout);
- END;
- END;
- IF (unitlist = NIL) OR (scsiBase = NIL) THEN HALT(10) END;
-
- Dos.FreeArgs(RD);
-
- Conversions.IntToStringLeft(MyTask(Dos.Process).taskNum, str);
- IF Dos.SetVar("NoiseSaver", str, Strings.Length(str), LONGSET{Dos.globalOnly}) THEN END;
-
- CallBack := CallBackProc;
- jmp := sys.VAL(JmpPtr, Exec.AllocMem(SIZE(jmp^), LONGSET{Exec.public, Exec.reverse}));
- IF jmp = NIL THEN HALT(20) END;
- jmp.jmp := JMP;
- jmp.proc := MyProc;
- OrigProc := Exec.SetFunction(scsiBase, Exec.beginIO, sys.VAL(Exec.PROC, jmp));
-
- REPEAT
- flags := Exec.Wait(LONGSET{mp.sigBit,Dos.ctrlC,Dos.ctrlE,Dos.ctrlF});
- IF Dos.ctrlF IN flags THEN
- unit := unitlist;
- WHILE unit # NIL DO
- unit.StartStop(TRUE);
- unit := unit.next;
- END;
- ELSIF Dos.ctrlE IN flags THEN
- unit := unitlist;
- WHILE unit # NIL DO
- unit.StartStop(FALSE);
- unit := unit.next;
- END;
- END;
- IF mp.sigBit IN flags THEN
- WHILE DispatchMsg() DO END;
- END;
- UNTIL Dos.ctrlC IN flags;
-
- IF Dos.DeleteVar("NoiseSaver",LONGSET{Dos.globalOnly}) THEN END;
-
- jmp.proc := OrigProc;
- Exec.Forbid();
- newProc := Exec.SetFunction(scsiBase, Exec.beginIO, OrigProc);
- IF newProc # sys.VAL(Exec.PROC, jmp) THEN
- newProc := Exec.SetFunction(scsiBase, Exec.beginIO, newProc);
- END;
- Exec.Permit();
-
- CLOSE
- unit := unitlist;
- WHILE unit # NIL DO
- lastunit := unit.next;
- unit.Close();
- DISPOSE(unit);
- unit := lastunit;
- END;
- IF mp # NIL THEN Exec.DeleteMsgPort(mp) END;
- END NoiseSaver.
-