#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"

#define TD_READ CMD_READ
#define BLOCKSIZE TD_SECTOR
#define NUMCYLS 79
#define NUMHEADS 2

SHORT error;
struct MsgPort *diskport;
struct IOExtTD *diskreq;
APTR diskdata;
SHORT testval;
 
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();
 
ULONG diskChangeCount,*ModData;

char  kick_1_2[] =
{
  'e','x','e','c',' ','3','3','.','1','8','9',
  ' ','(','3','0',' ','S','e','p',' ','1','9',
  '8','6',')',0xd,0xa,0x0
};


char  kick_rom[] =
{
  'e','x','e','c',' ','3','3','.','1','9','2',
  ' ','(','8',' ','O','c','t',' ','1','9',
  '8','6',')',0xd,0xa,0x0
};

ReadCylSec(cyl, sec, hd)
SHORT cyl, sec, hd;
{
        LONG offset;
 
        diskreq->iotd_Req.io_Length = BLOCKSIZE;
        diskreq->iotd_Req.io_Data = 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)
SHORT cyl, sec, hd;
{
        LONG offset;
 
        diskreq->iotd_Req.io_Length = BLOCKSIZE;
        diskreq->iotd_Req.io_Data = 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()
{
        diskreq->iotd_Req.io_Length = 1;
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        DoIO(diskreq);
        return(0);
}
 
MotorOff()
{
        diskreq->iotd_Req.io_Length = 0;
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        DoIO(diskreq);
        return(0);
}

int CheckProStat();

CheckProStat()
{
        diskreq->iotd_Req.io_Length = 0;
        diskreq->iotd_Req.io_Command = TD_PROTSTATUS;
        DoIO(diskreq);
        return((int)diskreq->iotd_Req.io_Actual);
}

int UpDataTrack();

UpDateTrack()
{
        diskreq->iotd_Req.io_Length = 0;
        diskreq->iotd_Req.io_Command = ETD_UPDATE;
        DoIO(diskreq);
        return((int)diskreq->iotd_Req.io_Error);
}

CheckKick()
{
        ReadCylSec(0,0,0);
        if(diskreq->iotd_Req.io_Error !=0){
            printf("\n\n     Fehler beim Lesen von Sektor 0\n");
            return(0);
        }
        if(strcmp(diskdata,"KICK") !=0){
            *(diskdata+5) = 0;
            printf("\n\n     Keine Kickstart in df0:  Disktypenkennung ist  %s\n",diskdata);
            return(0);
        }
        ReadCylSec(0,1,0);
        if(diskreq->iotd_Req.io_Error !=0){
            printf("\n\n     Fehler beim Lesen von Sektor 1\n");
            return(0);
        }
        if(strcmp(diskdata+6,&kick_1_2[0]) == 0){
            printf("\n\n     Kickstart Version 1.2  33.189\n");
            return(1);
        }
        else if(strcmp(diskdata+6,&kick_rom[0]) == 0){
            printf("\n\n     Kickstart Version 'ROM'  33.192\n");
            return(2);
        }
        else{
            printf("\n\n");
            printf("     Das  Modifikationsprogramm  kann  nur  die  Version\n");
            printf("     1.2  Ver. 33.189   oder die Romversion  Ver. 33.192\n");
            printf("     anpassen.\n\n");
        }
        return(0);
}


OpenStuff()
{
        unsigned long i;

        diskdata = 0;
        i = 0x020000;
        do{
            diskdata = (APTR)AllocAbs(BLOCKSIZE,i);
            i += 0x0200;
            if(i > 0x080000){
               printf("Fataler Fehler bei der Speicheranforderung  Ende Programmm\n");
               exit(200);
            }
        }
        while(diskdata == 0);
        diskport = CreatePort(0,0);
        if(diskport == 0){
            printf("Fehler beim Öffnen des Diskports  Ende Programm\n");
            FreeMem(diskdata,BLOCKSIZE);
            exit(200);
        }
        diskreq = (struct IOExtTD *)CreateExtIO(diskport,sizeof(struct IOExtTD));
        if(diskreq == 0){
            FreeMem(diskdata,BLOCKSIZE);
            DeletePort(diskport);
            printf("Fehler beim Anlegen des Disk IO Blocks  EndeProgramm\n");
            exit(200);
        }
        if(OpenDevice(TD_NAME,0,diskreq,0)!=0){
            FreeMem(diskdata,BLOCKSIZE);
            DeletePort(diskport);
            DeleteExtIO(diskreq, sizeof(struct IOExtTD));
            printf("Fehler beim Öffnen des Diskettentreibers  EndeProgramm\n");
            exit(200);
        }
        diskreq->iotd_Req.io_Command = TD_CHANGENUM;
        DoIO(diskreq);
        diskChangeCount = diskreq->iotd_Req.io_Actual;
        return(0);
}

CloseStuff()
{
        MotorOff();
        CloseDevice(diskreq);
        FreeMem(diskdata,BLOCKSIZE);
        DeletePort(diskport);
        DeleteExtIO(diskreq, sizeof(struct IOExtTD));
        printf("\n     Bye Bye\n\n\n");
        return(0);
}


ModKick()
{
        if(CheckProStat() != 0){
            printf("\n     Bitte vor dem nächsten Aufruf Schreibschutz entfernen\n\n");
            return(0);
        }
        (APTR)ModData = (APTR)diskdata;
        ReadCylSec(0,1,0);
        *(ModData+0x0d) =0x022800e4;
        *(ModData+0x76) =0x00080000;
        *(ModData+0x77) =0x43f90010;
        *(ModData+0x7c) =0x00080000;
        *(ModData+0x7f) =0x00080000;
        WriteCylSec(0,1,0);
        ReadCylSec(0,2,0);
        *(ModData+0x03) =0x43f90008;
        WriteCylSec(0,2,0);
        if(UpDateTrack() != 0)
            printf("\n     Fehler beim Rückschreiben der Daten  Programmabbruch\n\n");
        else
            printf("\n     Kickstart erfolgreich modifiziert\n");
        return(0);
}


StartUp()
{
        printf("\n\n     Installationsprogramm zum Erzeugen einer an die\n");
        printf("     in KICKSTART 9/87 beschriebene Megaerweiterung\n");
        printf("     angepasste Bootdiskette <Kickstart>");
        printf("                                             (GC)");
        printf("\n\n     Bitte die zu modifizierende Kickstart in df0:\n");
        printf("     einlegen und  <RETURN> betätigen\n");
        getchar();
        return(0);
}


main()   
{
        StartUp();
        OpenStuff();
        MotorOn();
        if(CheckKick() == 0)
            CloseStuff();
        else{
            ModKick();
            CloseStuff();
        }
        return(0);
}
 
 
 
 
 
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);
}
