home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga Shareware Floppies / ma32.dms / ma32.adf / NoiseSaver / txt / NoiseSaver.mod < prev   
Text File  |  1994-11-02  |  9KB  |  343 lines

  1. (*
  2. (*
  3.  * $Id: NoiseSaver.mod,v 2.3 1994/11/02 14:52:34 mh Exp mh $
  4.  *
  5.  *)
  6.  *)
  7.  
  8. MODULE NoiseSaver; (* $JOIN NoiseSaver.o *)
  9.  
  10. IMPORT Conversions, Strings, SCSIDisk, Timer, Dos, Exec, sys: SYSTEM;
  11.  
  12. PROCEDURE MyProc{"MyProc"}();
  13.  
  14. VAR
  15.   OrigProc["OrigProc"]  : Exec.PROC;
  16.   CallBack["CallBack"]  : PROCEDURE(ior{9}:Exec.IOStdReqPtr);
  17.   MyTask["MyTask"]      : Exec.TaskPtr;
  18.   ExecBase["ExecBase"]    : Exec.ExecBasePtr;
  19.  
  20.  
  21. CONST
  22.   Template = "DEVICE/K,TIMEOUT/N,UNIT/N,"
  23.              "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,"
  24.              "-H=HELP/S";
  25.   Version = "$VER: NoiseSaver 2.1 (02.11.94)\n\o$";
  26.   Help = "\e[1mNoiseSaver\e[0m © 1994 by Martin Horneffer\n\n"
  27.          "\e[1mNoiseSaver\e[0m stops connected SCSI-Units, whenever they have been idle\n"
  28.          "for at certain time, and automagically switches them on again when needed.\n\n"
  29.          "You can specify up to 8 units with an optional timeout each.\n"
  30.          "Default DEVICE is 'scsi.device', default TIMEOUT is 300 seconds.\n"
  31.          "If no UNIT is specified, the units 0 to 6 are tried.\n\n"
  32.          "When \e[1mNoiseSaver\e[0m is running, use\n"
  33.      "  'BREAK $NoiseSaver e' to stop the drives,\n"
  34.          "  'BREAK $NoiseSaver f' to start them and\n"
  35.          "  'BREAK $NoiseSaver c' to quit \e[1mNoiseSaver\e[0m.\n";
  36.   DefTimeout = 300;
  37.   JMP = 4EF9H;
  38.  
  39.  
  40. TYPE
  41.   UnitPtr = POINTER TO Unit;
  42.   Unit = RECORD
  43.            next   : UnitPtr;
  44.            unit   : LONGINT;
  45.            sem    : Exec.SignalSemaphore;
  46.            timer  : Timer.TimeRequestPtr;
  47.            timeout: LONGINT;
  48.            ior      : Exec.IOStdReqPtr;
  49.            sc     : SCSIDisk.SCSICmd;
  50.            command: ARRAY 6 OF SHORTINT;
  51.            active : BOOLEAN;
  52.            stopped: BOOLEAN;
  53.            haveSem: BOOLEAN;
  54.          END;
  55.   JmpPtr = POINTER TO Jmp;
  56.   Jmp = STRUCT jmp: INTEGER; proc: Exec.PROC;  END;
  57.  
  58.  
  59. VAR
  60.   unitlist: UnitPtr;
  61.   lastunit: UnitPtr;
  62.   mp      : Exec.MsgPortPtr;
  63.   scsiBase: Exec.LibraryPtr;
  64.  
  65. PROCEDURE TryUnit(deviceName: ARRAY OF CHAR; unit, timeout: LONGINT);
  66.   (* $CopyArrays- *)
  67.   VAR n: UnitPtr;
  68.   BEGIN
  69.     NEW(n);
  70.     n.unit := unit;
  71.     Exec.InitSemaphore(n.sem);
  72.     n.timeout := timeout;
  73.  
  74.     n.ior := Exec.CreateIORequest(mp, SIZE(n.ior^));
  75.     IF n.ior # NIL THEN
  76.       IF Exec.OpenDevice(deviceName, unit, n.ior, LONGSET{}) = 0 THEN
  77.         scsiBase := n.ior.device;
  78.         n.timer := Exec.CreateIORequest(mp, SIZE(n.timer^));
  79.         IF n.timer # NIL THEN
  80.           IF Exec.OpenDevice( Timer.timerName, Timer.vBlank, n.timer, LONGSET{}) = 0 THEN
  81.             n.timer.node.error := Exec.aborted;
  82.             Exec.ReplyMsg(n.timer);
  83.             IF lastunit = NIL THEN
  84.               unitlist := n;
  85.             ELSE
  86.               lastunit.next := n;
  87.             END;
  88.             lastunit := n;
  89.             RETURN;
  90.           ELSE
  91.             Exec.DeleteIORequest(n.timer);
  92.           END;
  93.         END;
  94.       ELSE
  95.         Exec.DeleteIORequest(n.ior);
  96.       END;
  97.     END;
  98.  
  99.     DISPOSE(n);
  100.   END TryUnit;
  101.  
  102.  
  103. PROCEDURE (me:UnitPtr) StartStop(start: BOOLEAN);
  104.   BEGIN
  105.     IF me.active THEN  RETURN  END;
  106.     IF NOT start AND NOT me.haveSem THEN
  107.       Exec.ObtainSemaphore(me.sem);
  108.       me.haveSem := TRUE;
  109.     END;
  110.     me.command[0] := 1BH; (* start/stop unit *)
  111.     me.command[1] := 1;   (* Bit1: immediate *)
  112.     me.command[2] := 0;
  113.     me.command[3] := 0;
  114.     me.command[4] := 0;   (* Bit1: start *)
  115.     me.command[5] := 0;
  116.     IF start THEN
  117.       me.command[1] := 0;
  118.       me.command[4] := 1;
  119.     END;
  120.     me.sc.data     := NIL;
  121.     me.sc.length   := 0;
  122.     me.sc.command  := sys.ADR(me.command);
  123.     me.sc.cmdLength:= SHORT(LEN(me.command));
  124.     me.sc.flags    := SHORTSET{SCSIDisk.read};
  125.     IF start THEN
  126.       Dos.PrintF("starting unit %ld..\n", me.unit);
  127.     ELSE
  128.       Dos.PrintF("stopping unit %ld..\n", me.unit);
  129.     END;
  130.     me.ior.command := SCSIDisk.scsiCmd;
  131.     me.ior.data    := sys.ADR(me.sc);
  132.     me.ior.length  := SIZE(me.sc);
  133.  
  134.     Exec.SendIO(me.ior);
  135.     me.active := TRUE;
  136.     me.stopped := NOT start;
  137.   END StartStop;
  138.  
  139.  
  140. PROCEDURE (me:UnitPtr) Close();
  141.   BEGIN
  142.     IF me.active THEN  Exec.OldWaitIO(me.ior)  END;
  143.     IF me.stopped THEN
  144.       me.StartStop(TRUE);
  145.       Exec.OldWaitIO(me.ior);
  146.       IF me.haveSem THEN  Exec.ReleaseSemaphore(me.sem)  END;
  147.     END;
  148.     Exec.CloseDevice(me.ior);
  149.     Exec.DeleteIORequest(me.ior);
  150.  
  151.     Exec.AbortIO(me.timer);
  152.     Exec.OldWaitIO(me.timer);
  153.     Exec.CloseDevice(me.timer);
  154.     Exec.DeleteIORequest(me.timer);
  155.   END Close;
  156.  
  157.  
  158. PROCEDURE (me:UnitPtr) HandleIO();
  159.   BEGIN
  160.     me.active := FALSE;
  161.     Exec.Permit();
  162.     IF me.ior.error # 0 THEN
  163.       Dos.PrintF("unit %ld error: %ld, status: %ld\n",
  164.                  me.unit, me.ior.error, me.sc.status);
  165.     ELSE
  166.       Dos.PrintF("unit %ld ok.\n", me.unit);
  167.     END;
  168.     IF me.haveSem AND NOT me.stopped THEN
  169.       Exec.ReleaseSemaphore(me.sem);
  170.       me.haveSem := FALSE;
  171.       Exec.AbortIO(me.timer);
  172.     END;
  173.   END HandleIO;
  174.  
  175.  
  176. PROCEDURE (me:UnitPtr) HandleTimer();
  177.   VAR ok: BOOLEAN;
  178.   BEGIN
  179.     ok := me.timer.node.error = 0;
  180.     me.timer.node.command := Timer.addRequest;
  181.     me.timer.time.micro   := 0;
  182.     IF ok THEN
  183.       me.timer.time.secs  := 80000000H;
  184.     ELSE
  185.       me.timer.time.secs  := me.timeout;
  186.     END;
  187.     Exec.SendIO(me.timer);
  188.     Exec.Permit();
  189.     IF ok # me.stopped THEN
  190.       me.StartStop(me.stopped);
  191.     END;
  192.   END HandleTimer;
  193.  
  194.  
  195. PROCEDURE  CallBackProc(ior{9}:Exec.IOStdReqPtr); (* $SaveRegs+ *)
  196.   (* $Debug- $StackChk- $NilChk- $ClearVars- *)
  197.   VAR u: UnitPtr;
  198.   BEGIN
  199.     u := unitlist;
  200.     WHILE u # NIL DO
  201.       IF u.ior.unit = ior.unit THEN
  202.         Exec.AbortIO(u.timer);
  203.         Exec.ObtainSemaphoreShared(u.sem);
  204.         Exec.ReleaseSemaphore(u.sem);
  205.         RETURN;
  206.       END;
  207.       u := u.next;
  208.     END;
  209.   END CallBackProc;
  210.   (* $Debug= $StackChk= $NilChk= $ClearVars= *)
  211.  
  212.  
  213. PROCEDURE DispatchMsg(): BOOLEAN;
  214.   VAR msg: Exec.MessagePtr; unit: UnitPtr;
  215.   BEGIN
  216.     Exec.Forbid();
  217.     msg := Exec.GetMsg(mp);
  218.     IF msg = NIL THEN
  219.       Exec.Permit();
  220.       RETURN FALSE;
  221.     END;
  222.     unit := unitlist;
  223.     WHILE unit # NIL DO
  224.       IF unit.timer = msg THEN
  225.         unit.HandleTimer();
  226.         RETURN TRUE;
  227.       ELSIF unit.ior = msg THEN
  228.         unit.HandleIO();
  229.         RETURN TRUE;
  230.       ELSE
  231.         unit := unit.next;
  232.       END;
  233.     END;
  234.     Exec.Permit();  (* impossible *)
  235.     RETURN TRUE;
  236.   END DispatchMsg;
  237.  
  238.  
  239. VAR
  240.   newProc       : Exec.PROC;
  241.  
  242.   args        : STRUCT (as: Dos.ArgsStruct)
  243.                     deviceName: Exec.STRPTR;
  244.                     a: ARRAY 8 OF STRUCT 
  245.                                     t: UNTRACED POINTER TO LONGINT;
  246.                                     u: UNTRACED POINTER TO LONGINT;
  247.                                   END;
  248.                     help    : LONGINT;
  249.                   END;
  250.   RD        : Dos.RDArgsPtr;
  251.   jmp           : JmpPtr;
  252.   str           : ARRAY 16 OF CHAR;
  253.  
  254.   unit          : UnitPtr;
  255.   timeout       : LONGINT;
  256.   flags         : LONGSET;
  257.   i             : LONGINT;
  258.  
  259. BEGIN
  260.   IF Exec.SysBase.libNode.version < 37  THEN  HALT(37)  END;
  261.   ExecBase := Exec.SysBase;
  262.   sys.SETREG(0, sys.ADR(Version));
  263.  
  264.   MyTask := Exec.FindTask(NIL);
  265.   mp := Exec.CreateMsgPort();
  266.   IF mp = NIL THEN  HALT(20)  END;
  267.  
  268.   args.deviceName := sys.ADR("scsi.device");
  269.   RD := Dos.ReadArgs (Template, args, NIL);
  270.   IF (RD = NIL) OR (args.help # 0) THEN
  271.     Dos.PrintF ("Template: %s\n\nHelp:\n\n%s\n", sys.ADR(Template), sys.ADR(Help));
  272.     IF RD = NIL THEN  HALT(20)  ELSE  HALT(0)  END;
  273.   END;
  274.  
  275.   timeout := DefTimeout;
  276.   FOR i := 0 TO 7 DO
  277.     IF args.a[i].t # NIL THEN
  278.       timeout := args.a[i].t^;
  279.     END;
  280.     IF (timeout > 0) & (args.a[i].u # NIL) THEN
  281.       TryUnit(args.deviceName^, args.a[i].u^, timeout);
  282.     END;
  283.   END;
  284.   IF (timeout > 0) & (unitlist = NIL) THEN
  285.     FOR i := 0 TO 6 DO
  286.       TryUnit(args.deviceName^, i, timeout);
  287.     END;
  288.   END;
  289.   IF (unitlist = NIL) OR (scsiBase = NIL) THEN  HALT(10)  END;
  290.  
  291.   Dos.FreeArgs(RD);
  292.  
  293.   Conversions.IntToStringLeft(MyTask(Dos.Process).taskNum, str);
  294.   IF Dos.SetVar("NoiseSaver", str, Strings.Length(str), LONGSET{Dos.globalOnly}) THEN END;
  295.  
  296.   CallBack := CallBackProc;
  297.   jmp := sys.VAL(JmpPtr, Exec.AllocMem(SIZE(jmp^), LONGSET{Exec.public, Exec.reverse}));
  298.   IF jmp = NIL THEN  HALT(20)  END;
  299.   jmp.jmp  := JMP;
  300.   jmp.proc := MyProc;
  301.   OrigProc := Exec.SetFunction(scsiBase, Exec.beginIO, sys.VAL(Exec.PROC, jmp));
  302.  
  303.   REPEAT
  304.     flags := Exec.Wait(LONGSET{mp.sigBit,Dos.ctrlC,Dos.ctrlE,Dos.ctrlF});
  305.     IF Dos.ctrlF IN flags THEN
  306.       unit := unitlist;
  307.       WHILE unit # NIL DO
  308.         unit.StartStop(TRUE);
  309.         unit := unit.next;
  310.       END;
  311.     ELSIF Dos.ctrlE IN flags THEN
  312.       unit := unitlist;
  313.       WHILE unit # NIL DO
  314.         unit.StartStop(FALSE);
  315.         unit := unit.next;
  316.       END;
  317.     END;
  318.     IF mp.sigBit IN flags THEN
  319.       WHILE DispatchMsg() DO END;
  320.     END;
  321.   UNTIL Dos.ctrlC IN flags;
  322.  
  323.   IF Dos.DeleteVar("NoiseSaver",LONGSET{Dos.globalOnly}) THEN END;
  324.  
  325.   jmp.proc := OrigProc;
  326.   Exec.Forbid();
  327.   newProc := Exec.SetFunction(scsiBase, Exec.beginIO, OrigProc);
  328.   IF newProc # sys.VAL(Exec.PROC, jmp) THEN
  329.     newProc := Exec.SetFunction(scsiBase, Exec.beginIO, newProc);
  330.   END;
  331.   Exec.Permit();
  332.  
  333. CLOSE
  334.   unit := unitlist;
  335.   WHILE unit # NIL DO
  336.     lastunit := unit.next;
  337.     unit.Close();
  338.     DISPOSE(unit);
  339.     unit := lastunit;
  340.   END;
  341.   IF  mp # NIL THEN  Exec.DeleteMsgPort(mp)  END;
  342. END NoiseSaver.
  343.