/********************************************************
* (c) Merlin Computer GMBH                              *
* KICKSTART JULI 1988				        *
* GETKICK						*
********************************************************/

#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"
#include "exec/devices.h"
#include "devices/trackdisk.h"
#include "stdio.h"
#include "functions.h"
#include "libraries/dos.h"

#define TD_READ CMD_READ
#define BLOCKSIZE TD_SECTOR
#define MAXSECTOR 512
#define KICKSIZE 0x40200L

SHORT error;
struct MsgPort *diskport;
struct IOExtTD *diskreq;
char *diskdata;
SHORT testval;
char *kickdata;
LONG openerror;
struct DosBase *DosBase; 
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();

struct FileHandle *clidos;
 
ULONG diskChangeCount,*ModData;


ReadCylSec(cyl, sec, hd)

/* diese Funktion liest den durch cyl,sec und hd  *
 * bestimmten Sektor in den Lesepuffer ein        */

SHORT cyl, sec, hd;
{
        LONG offset;
 
        diskreq->iotd_Req.io_Length = BLOCKSIZE;
        diskreq->iotd_Req.io_Data = (APTR)diskdata;
        diskreq->iotd_Req.io_Command = ETD_READ;
        diskreq->iotd_Count = diskChangeCount;
        offset = TD_SECTOR * (sec + NUMSECS * hd + NUMSECS * NUMHEADS * cyl);
        diskreq->iotd_Req.io_Offset = offset;
        DoIO(diskreq);
        return(0);
}


WriteCylSec(cyl, sec, hd)

/* diese Funktion schreibt den durch cyl, sec und hd *
 * bestimmten Sektor auf Diskette. ACHTUNG der       *
 * zuletzt geschriebene Sektor wird erst bei einem   *
 * Spurwechsel auf Diskette übertragen.              */
 
SHORT cyl, sec, hd;
{
        LONG offset;
 
        diskreq->iotd_Req.io_Length = BLOCKSIZE;
        diskreq->iotd_Req.io_Data = (APTR)diskdata;
        diskreq->iotd_Req.io_Command = ETD_WRITE;
        diskreq->iotd_Count = diskChangeCount;
        offset = TD_SECTOR * (sec + NUMSECS * hd + NUMSECS * NUMHEADS * cyl);
        diskreq->iotd_Req.io_Offset = offset;
        DoIO(diskreq);
        return(0);
}
  
MotorOn()

/* diese Funktion schaltet den Motor des im *
 * diskreq angegebenen Laufwerks ein        */
 
{
        diskreq->iotd_Req.io_Length = 1;
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        DoIO(diskreq);
        return(0);
}
 
MotorOff()

/* dies Funktion schaltet den Motor aus     */

{
        diskreq->iotd_Req.io_Length = 0;
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        DoIO(diskreq);
        return(0);
}

OpenStuff()

/* alle benötigten Systemresourcen werden   *
 * hier geöffnet bzw. reserviert            */
 
{
	if(!(DosBase=(struct DosBase *)OpenLibrary((UBYTE *)"dos.library",0L)))CloseStuff();
        if(!(clidos = Open("con:0/10/640/200/GETKICK",MODE_NEWFILE)))CloseStuff();
        if(!(diskdata=(char *)AllocMem(BLOCKSIZE,MEMF_CHIP|MEMF_CLEAR)))CloseStuff();
	if(!(kickdata=(char *)AllocMem(KICKSIZE,MEMF_PUBLIC)))CloseStuff();
        if(!(diskport=CreatePort(0L,0L)))CloseStuff();
        if(!(diskreq=(struct IOExtTD *)CreateExtIO(diskport,(LONG)sizeof(struct IOExtTD))))CloseStuff();
        if(openerror=OpenDevice(TD_NAME,0L,diskreq,0L))CloseStuff();
        diskreq->iotd_Req.io_Command = TD_CHANGENUM;
        DoIO(diskreq);
        diskChangeCount = diskreq->iotd_Req.io_Actual;
        return(0);
}

CloseStuff()

/* dies Funktion beendet das Programm *
 * ordnungsgemäß                      */
 
{
        if(!openerror)
	{
		MotorOff();
		CloseDevice(diskreq);
	}
        if(DosBase)CloseLibrary(DosBase);
	if(diskdata)FreeMem(diskdata,BLOCKSIZE);
	if(kickdata)FreeMem(kickdata,KICKSIZE);
        if(diskport)DeletePort(diskport);
        if(diskreq)DeleteExtIO(diskreq,(LONG)sizeof(struct IOExtTD));
        fprintf(clidos,"\n     Bye Bye\n\n");
	if(clidos)Close(clidos);
        exit();
}

StartUp()

/* Ausgabe der Einschaltmeldung */

{
        fprintf(clidos,"\n    Legen Sie eine Kickstart Diskette in das\n");
        fprintf(clidos,"    interne Laufwerk df0: und betätigen Sie\n");
        fprintf(clidos,"    <RETURN>\n");
        getchar();
        return(0);
}
   
Schreibe()

/* die Funktion Schreibe entfernt die KICK *
 * Kennung am Anfang der gelesenen Daten   *
 * und teilt die 256 KByte in zwei 128     *
 * KByte große Teile, die nach geraden und *
 * ungeraden Adressen getrennt in seperaten*
 * Dateien abgelegt werden                 */
 
{
	char *schreibepuffer,*konvertpuffer;
	struct FileHandle *datei;
	LONG error,i;
	
	konvertpuffer=kickdata;
	if(!(schreibepuffer=AllocMem(0x10000L,MEMF_PUBLIC)))
	{
		puts("puffer fehler");
		return();
	}
	konvertpuffer+=512L;  /* sector 0 ausblenden */
	for(i=0;i<0x10000;i++)
	{
		*(schreibepuffer+i)=*(konvertpuffer+(i<<1));
	}
	datei=Open((char *)"KICK1.EVEN",MODE_NEWFILE);
	error=Write(datei,schreibepuffer,0x10000L);
	if(error==-1L)puts("Fehler Schreiben");
	Close(datei);
	for(i=0;i<0x10000;i++)
	{
		*(schreibepuffer+i)=*(konvertpuffer+1+(i<<1));
	}
	datei=Open((char *)"KICK1.ODD",MODE_NEWFILE);
	error=Write(datei,schreibepuffer,0x10000L);
	if(error==-1L)puts("Fehler Schreiben");
	Close(datei);
	konvertpuffer+=0x20000;  /* zweite bank */
	for(i=0;i<0x10000;i++)
	{
		*(schreibepuffer+i)=*(konvertpuffer+(i<<1));
	}
	datei=Open((char *)"KICK2.EVEN",MODE_NEWFILE);
	error=Write(datei,schreibepuffer,0x10000L);
	if(error==-1L)puts("Fehler Schreiben");
	Close(datei);
	for(i=0;i<0x10000;i++)
	{
		*(schreibepuffer+i)=*(konvertpuffer+1+(i<<1));
	}
	datei=Open((char *)"KICK2.ODD",MODE_NEWFILE);
	error=Write(datei,schreibepuffer,0x10000L);
	if(error==-1L)puts("Fehler Schreiben");
	Close(datei);
	FreeMem(schreibepuffer,0x10000L);
	return();
}
   
main()   

/* die Funktion main überprüft das Vorhanden *
 * sein einer Kickstart Diskette und liest   *
 * diese ein. Bei Erfolg wird die Funktion   *
 * Schreibe aufgerufen                       */
 
{
        int track,head,sektor,i;
	char *lesepointer;

        OpenStuff();
	lesepointer=kickdata;
        StartUp();
        MotorOn();
	Delay(60L);

	ReadCylSec((SHORT)0,(SHORT)0,(SHORT)0);
	if(strcmp(diskdata,(char *)"KICK")!=0)
	{
		puts("keine Kickstart Diskette !\n");
		CloseStuff();
	}
        for(track=0;track<80;track++){
           for(head=0;head<2;head++){
              for(sektor=0;sektor<11;sektor++){
                  ReadCylSec(track,sektor,head);  
                  if(diskreq->iotd_Req.io_Error != 0)
		  {
                     printf("Fehler bei Track %d Sektor %d Seite %d\n"
                                  ,track,sektor,head);
                     CloseStuff();
                  }
                  for(i=0;i<512;i+=1)
		  {
                     *(lesepointer++)=*(diskdata+i);
                  }
                  if((lesepointer-kickdata) >= KICKSIZE)
		  {
		  	Schreibe();
			CloseStuff();
		  } 
              }
           }
        } 
        CloseStuff();
        return(0);
}
 
 
 
/* 
 
Älter Compilerversionen benötigen dies beiden 
Funktionen, da sie noch nicht in den Libraries
verfügbar waren.
 
struct IORequest *CreateExtIO(ioReplyPort,size)
    struct MsgPort *ioReplyPort;
    LONG size;
{
    struct IORequest *ioReq;

    if (ioReplyPort == 0)
        return ((struct IORequest   *) 0);
    ioReq = (struct IORequest *)AllocMem (size, MEMF_CLEAR | MEMF_PUBLIC);
    if (ioReq == 0)
        return ((struct IORequest   *) 0);
 
    ioReq -> io_Message.mn_Node.ln_Type = NT_MESSAGE;
    ioReq -> io_Message.mn_Node.ln_Pri = 0;
    ioReq -> io_Message.mn_ReplyPort = ioReplyPort;
 
    return (ioReq);
}
  
  
DeleteExtIO(ioExt,size)
    struct IORequest *ioExt;
    LONG size;
{
    ioExt -> io_Message.mn_Node.ln_Type = 0xff;
    ioExt -> io_Device = (struct Device *) -1;
    ioExt -> io_Unit = (struct Unit *) -1;
 
    FreeMem (ioExt, size);
    return(0);
}

*/
