/*
 *  Initial-Release V1.0:
 *   Mon Dec 26 00:20:04 1994 - R.Hess
 *   Mon Dec 26 12:19:45 1994 - R.Hess
 *
 *   V1.0: (31.12.94) Kleine Änderung in der Ausgabe.
 *         Sat Dec 31 17:29:12 1994 - R.Hess
 *
 *   V1.1: Forbid()/Permit() wenn in die KickTag-Feldern geschrieben
 *         wird. Danach die Caches leeren (mit CacheClearU()), damit
 *         nichts im Cache stecken bleibt.
 *         Sun Jan  8 06:18:32 1995 - R.Hess
 *
 *   V1.1: Copyright 1994/95 eingefügt.
 *         Thu Jan 26 23:45:53 1995 - R.Hess
 *         Neuübersetzung mit SAS/C 6.55.
 *         Mon Mar 20 13:48:38 1995 - R.Hess
 *
 *   Reference: M&T AMIGA-Magazin 10/88, Seite 51
 *
 *   Compiler- und Linkaufrufe (SAS/C 6.55): siehe smakefile
 */

#include <exec/types.h>
#include <exec/resident.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/execbase.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>

#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>

#include <string.h>

#include "A1200_HDPatch.h"

#define AUTOR		"Copyright (c) 1994/95 by Rainer Hess"

#define VSTRINGLEN	36	/* Länge des Strings in Name */
#define AUTORLEN	37	/* Länge des Strings in idString */

UBYTE *v = VERSTAG " " AUTOR;

extern struct ExecBase *SysBase;
extern struct DosLibrary *DOSBase;

/*
 * erweiterte MemList Struktur mit insgesamt 4 MemEntrys
 */

struct
  {
    struct MemList me_main;
    struct MemEntry me_added[3];
    UBYTE me_Name[VSTRINGLEN];
    UBYTE me_idString[AUTORLEN];
  }
 *Speicher;

struct Resident myProg =
{
  RTC_MATCHWORD,		/* Matchword $4afc, daran wir Res. Str. erkannt */
  NULL,				/* Zeiger auf sich selbst                       */
  NULL,				/* Zeiger auf Strukturende                      */
  RTF_COLDSTART,		/* Flags                                        */
  VERSION,			/* Version                                      */
  NT_UNKNOWN,			/* Type                                         */
  104,				/* Prioritaet (nach exec.library)               */
  NULL,				/* Zeiger auf Name                              */
  NULL,				/* und ID_String                                */
  NULL				/* Zeiger auf Code                              */
};

/*
 * Diese Funktion wird resetfest installiert.
 * ------------------------------------------
 * ACHTUNG! Keine weiteren Funktionen daraus aufrufen, es muss
 * alles innerhalb dieser Funktion sein, sonst gibt es GURU's,
 * da der Speicher sonst falsch initalisiert wird. Andernfalls
 * muß man wohl alle Funktionen einzeln vermerken...
 */

void __saveds
ResetProg (void)
{
  //char *cia = (char *) 0xbfe001;	/* Nur für Testzwecke! */
  long i;

  Forbid();

  /*
   * Achtung! Kein Optimize verwenden, da sonst diese
   * geniale Warte-Schleife in ein NICHTS eleminiert wird.
   * 350000 ist eben der ermittelte Wert auf einem A1200 mit
   * dem Blizzard Turbo-Memory-Board 1220/4. Auf schnelleren
   * Boards ist dieser Wert eben zu erhöhen.
   */

  //*cia |= (1 << 1);		/* PowerLed ausschalten (zum Test) */
  for(i=0; i<350000; i++);	/* Tolle Warte-Routine :-)         */
  //*cia &= ~(1 << 1);		/* PowerLed einschalten (zum Test) */

  Permit();
}

void
main(int argc, char *argv[])
{
  BYTE *Mem, *ResAdr;
  register BYTE *MemPoi, *i;
  int c;

  if (SysBase->LibNode.lib_Version < 36L)
    {
      Write (Output(), "Benötige Kickstart V36 oder höher! Abbruch...\n", 46L);
      Exit (RETURN_ERROR);
    }

  /*
   * Speicher fuer MemList Struktur anfordern (wird automatisch geloescht)
   */

  Speicher = AllocMem (sizeof (*Speicher), MEMF_PUBLIC | MEMF_CLEAR);
  Speicher->me_main.ml_Node.ln_Type = NT_MEMORY;	/* Nodetyp */
  Speicher->me_main.ml_NumEntries = 4;	/* 4 MemEntry Strukturen vorhanden */

  /*
   * Name und idString einkopieren.
   */

  strncpy (Speicher->me_Name, VSTRING, VSTRINGLEN);
  strncpy (Speicher->me_idString, AUTOR, AUTORLEN);

  myProg.rt_Name = Speicher->me_Name;
  myProg.rt_IdString = Speicher->me_idString;


  /*
   * Code in Speicherbereich kopieren
   */

  Mem = AllocMem ((ULONG) main - (ULONG) ResetProg, MEMF_PUBLIC);
  for (i = (BYTE *) ResetProg, MemPoi = Mem; i < (BYTE *) main; *MemPoi++ = *i++);
  myProg.rt_Init = (APTR) Mem;	/* jetzt Codeadresse in Resident Struktur eintragen */

  /* und Code-Speicher in MemList Struktur vermerken (Adresse, Laenge)
   *******************************************************************/

  Speicher->me_main.ml_ME[0].me_Addr = (APTR) Mem;
  Speicher->me_main.ml_ME[0].me_Length = (ULONG) main - (ULONG) ResetProg;

  /*
   * Jetzt Resident Struktur in Speicherbereich kopieren
   */

  Mem = AllocMem (sizeof (struct Resident), MEMF_PUBLIC);
  myProg.rt_MatchTag = (struct Resident *) Mem;	/* Zeiger auf sich selbst setzen */
  myProg.rt_EndSkip = (APTR) (Mem + sizeof (struct Resident));	/* Zeiger auf Ende */
  for (i = (BYTE *) & myProg, MemPoi = Mem, c = 0; c < sizeof (struct Resident); *MemPoi++ = *i++, c++);

  /*
   * Und Speicherbereich in MemList vermerken
   */

  Speicher->me_main.ml_ME[1].me_Addr = (APTR) Mem;
  Speicher->me_main.ml_ME[1].me_Length = sizeof (struct Resident);
  ResAdr = Mem;				/* merken */

  /*
   * Resident-Tabelle erstellen (2 Zeiger, zweiter Zeiger ist 0)
   */

  Mem = AllocMem (sizeof(struct MemChunk), MEMF_PUBLIC | MEMF_CLEAR);
  *((ULONG *) Mem) = (ULONG) ResAdr;		/* Adresse Resident Struktur eintragen */
  Speicher->me_main.ml_ME[2].me_Addr = (APTR) Mem;
  Speicher->me_main.ml_ME[2].me_Length = sizeof(struct MemChunk);

  /*
   * Jetzt MemList selbst auch noch in MemList vermerken
   * ACHTUNG! Bei KickMemPtr und KickTagPtr = wird jedes
   * andere resetfeste Programm gelöscht.
   */

  Speicher->me_main.ml_ME[3].me_Addr = (APTR) Speicher;
  Speicher->me_main.ml_ME[3].me_Length = sizeof (*Speicher);

  Forbid();
  SysBase->KickMemPtr = (APTR) Speicher;	/* MemList Adresse   in KichMemPtr (546) */
  SysBase->KickTagPtr = (APTR) Mem;		/* Resident Mem.Adr. in KickTagPtr (550) */
  SysBase->KickCheckSum = (APTR) SumKickData();	/* Neue KickCheckSum berechnen */
  Permit();

  CacheClearU();	/* Damit auch alles ins RAM geschrieben wird und nicht was im Cache stecken bleibt */

  if( argc != 0) Printf ("%s installiert...\n", VERS);	/* Kein WBStart */
  Exit (RETURN_OK);
}
