#include STDIO.h

#include <exec/types.h>          
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/io.h>
#include <exec/libraries.h>
#include <devices/trackdisk.h>

#define PUFFER (512*1)  /*    512 * XXX      */
#define F_L 126         /* Patch-Code-Länge  */

extern struct MsgPort *CreatePort(); 
struct IOExtTD *request;
struct MsgPort *port;

BYTE  *buffer;
LONG offset=512*1;       /*  offset=  512 * XXX  */

main( argc,argv )      /* HAUPTPROGRAMM */
int argc;
char *argv[];
{       
 unsigned char adress[3], length[3], i;   
  /* Feld für Patch-Code */
static unsigned char patch[]=
{0,0,3,243,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,22,0,0,0,0,0,0,0,1,0,0,3,233,
0,0,0,22,78,85,255,252,43,124,0,191,236,1,255,252,32,109,255,252,12,16,0,127,
102,6,78,186,0,56,96,4,78,186,0,6,78,93,78,117,72,231,224,194,44,120,0,4,32,60,
0,8,0,0,34,60,0,1,0,5,116,0,32,124,0,8,0,0,147,201,78,174,253,150,76,223,67,7,
78,249,0,252,223,24,78,249,0,252,223,24};

  putchar(12);             /* CLS                     */
  argument(argc, argv);
  speicherreservieren();
  opendev( **(argv+1)-'0' );         /* Trackdisk-Device öffnen */
  diskda( **(argv+1) );              /* Disk in drive ??         */
  schutz();       /* Disk schreibgeschützt?? */
  motoron();      /* Motor einschalten       */

/* -------------------------------------------------------------------------- */
 if ( !(argc==5 && (strcmp(argv[4],"-ncp")==0 || strcmp(argv[4],"-NCP")==0)) )
 {
  offset=1*512;
  rblock();
  *(buffer+487)=8;    /* OS so patchen, daß nur 512KB CHIP-RAM erkannt werden */  
  wblock();
 }
/* -------------------------------------------------------------------------- */

 offset=624*512;
 rblock();
 *(buffer+187)=255;    /* OS so patchen, daß der Addmem-Patch aufgerufen wird */  
 *(buffer+188)=247;
 *(buffer+189)=0; 
 wblock();

/* -------------------------------------------------------------------------- */
  
 valhex( argv[2], adress );   /* Umwandlung Hex-Zeichen -> Dez-Zahlen */
 valhex( argv[3], length );
 
 for (i=0; i<3; i++)  
   patch[87+i]=length[i];     /* Patch-Code mit Adr und Länge 'patchen' */

 for (i=0; i<3; i++)
   patch[101+i]=adress[i];

/* ------------------------------------------------------------------------- */

  offset=1020*512;
  rblock(); 
  for (i=0; i<F_L; i++)      
    *(buffer+256+i)=*(patch+i);

  wblock();      /* Patch-Code ins OS schreiben, (da wo noch Platz ist)  */
  ende();
  
  printf("\n \033[33mready!!!\033[0m\n\n");
  printf(" O.K. Your OS2.04 is patched!\n");
  printf("Don't use ADDMEM in the startup-sequence any longer.\n\n");
  printf("Now you must correct the KICKSTART-checksum with another programm!\n\n\n");
} /* main() */

/* ------------------------------------------------------------------------- */

 valhex(s,feld)
 char *s, *feld;
 {
  char i, e, l;
 
  l=strlen(s); 
  l=l-6;
  for(i=0; i<3; i++)
  {
   feld[i]=0;
   for (e=0; e<2; e++)
    {  
     switch( s[l+e] )
     {
      case '0': case '1': case '2': case '3': case '4': 
      case '5': case '6': case '7': case '8': case '9': 
          feld[i]= feld[i]*16 + ( s[l+e]-'0' );
          break;
      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
          feld[i]= feld[i]*16 + ( s[l+e]-'a'+10 );
          break;
      case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
          feld[i]= feld[i]*16 + ( s[l+e]-'A'+10 );
          break;
      default:
          text();
          exit();
           break;       
     } 
    }
    l+=2;
   }
 }

/* ------------------------------------------------------------------------- */

argument(anz, para)   /* Anz. der Argumente O.K. ? */
int anz;
char *para[];
{
                                        
                          /* if ( strcmp(para[1],"?")==0 ) */
  if ( (anz!=4 && anz!=5) || ((**(para+1)-'0')<0 ||  (**(para+1)-'0')>3)
       || (strlen(para[2])!=8 && strlen(para[2])!=6) || (strlen(para[3])!=8
          && strlen(para[3])!=6) )
    {
     text();
     exit();
    }
}

/* ------------------------------------------------------------------------- */

speicherreservieren()
{
  buffer     = (BYTE *)AllocMem(PUFFER,MEMF_CLEAR|MEMF_CHIP); 
  if ( buffer==NULL )
   { printf("Not enough memory!\n"); exit(); }
}

/* ------------------------------------------------------------------------- */

opendev(unit) /* Routine zum öffnen des Trackdisk-Device */
char unit;
{
  struct IORequest *io;

  port = CreatePort(0,0);     /* ReplyPort erstellen */
  if (port == 0) 
   { 
      printf("Can't create ReplyPort!\n"); 
      FreeMem(buffer,PUFFER);       
      exit();
   }

  io = (struct IORequest *)     /* Requester initialisieren */
                       AllocMem(sizeof(struct IOExtTD),MEMF_CLEAR|MEMF_PUBLIC);
  io->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  io->io_Message.mn_Length       = sizeof(struct IOExtTD);
  io->io_Message.mn_ReplyPort    = port;

  request = (struct IOExtTD *) io;

  OpenDevice(TD_NAME,unit,request,0); 
}

/* ------------------------------------------------------------------------- */

motoron()  /* Motor des Laufwerks einschalten */
{
  request->iotd_Req.io_Length = 1;  /* Motor ein */
  request->iotd_Req.io_Command = TD_MOTOR; /* Motor-Befehl */
  DoIO(request);                    /* Befehl ausführen */
}

/* ------------------------------------------------------------------------- */

motoroff() /* Motor des Laufwerks ausschalten */
{
  request->iotd_Req.io_Length = 0;  /* Motor aus */
  request->iotd_Req.io_Command = TD_MOTOR; /* Motor-Befehl */
  DoIO(request);                    /* Befehl ausführen */
}

/* ------------------------------------------------------------------------- */


wblock()  /* Blöcke schreiben */
{
  request->iotd_Req.io_Length  = PUFFER;     /* Puffer-Länge */
  request->iotd_Req.io_Data    = (APTR)buffer;  /* Zeiger auf Datenpuffer */
  request->iotd_Req.io_Offset  = offset;     /* Sektoroffset */

  request->iotd_Req.io_Command = CMD_WRITE; /* Daten in Puffer */
  DoIO(request);                            /* schreiben       */
}

/* ------------------------------------------------------------------------- */

rblock()  /* Blöcke lesen */
{
  request->iotd_Req.io_Length  = PUFFER;    /*  Puffer-Länge*/
  request->iotd_Req.io_Data    = (APTR)buffer; /* Zeiger auf Datenpuffer */
  request->iotd_Req.io_Offset  = offset;    /* Sektoroffset */

  request->iotd_Req.io_Command = CMD_READ; /* Daten in Puffer */
  DoIO(request);                           /* schreiben       */
 }

/* ------------------------------------------------------------------------- */

diskda(unit)     /*  Disk in drive ?? */
char unit;
{
  if ( unit > '3' ) { text(); ende(); exit(); }
  request->iotd_Req.io_Command = TD_CHANGESTATE;    /* Prüfen, ob Disk */
  DoIO(request);              			    /* im Laufwerk     */                        

  if(request->iotd_Req.io_Actual != 0)
    {
      printf("\n No disk in DF%c: !!\n", unit);
      printf(" => Place Disk in drive DF%c: and start the programm again!!\n\n", unit);
      ende();
      exit();
    }
}

/* ------------------------------------------------------------------------- */

schutz()     /*  Disk schreibgeschützt?? */
{
  request->iotd_Req.io_Command = TD_PROTSTATUS; /*Prüfen, ob Disk*/
  DoIO(request);                         /* schreibgeschützt */

  if(request->iotd_Req.io_Actual != 0)
    {
      printf("\n Disk is write protected!\n");
      printf(" => Remove write protection and start the program again!!\n\n");
      ende();
      exit();
    }
}

/* ------------------------------------------------------------------------- */
text()
{
    printf("\n \033[33mPatchK2\033[0m\n");
    printf("\033[1mby Andreas Schäfer, GERMANY, Duisburg, 1992\033[0m\n");
    printf("\033[33mThis programm is useful, if you have a 512KB WOM expansion for your A1000.\033[0m\n");
    printf("\nPatchK2 patches a 2.04-KICKSTART-disk (block 1->1024).\n");
    printf("If the patch is done, the Amiga recognize only 512KB as chip-ram\n");
    printf("and your not-autoconfig-ram-expansion will automaticly recognize.\n");
    printf("The last point can be prevent by pressing SPACE after a reset,\n");
    printf("exactly: after the CAPS-LOCK-LED flashes on.\n\n");
    printf("synthax: PatchK2 <drive unit No.> <memory-start-adress> <memory-length> -ncp\n\n");
    printf("Memory-start-adress and memory-length are expected as hex values.\n");
    printf("The last argument is optional and meens 'no chip patch'.\n");
    printf("The AMIGA still recognize the first 2MB as CHIP ram.\n\n");
    printf("Example: PatchK2 0 00080000 00080000\n");
}

/* ------------------------------------------------------------------------- */

ende()
{
  request->iotd_Req.io_Command = CMD_UPDATE;  /* Daten auf Disk */
  DoIO(request);                              /* schreiben */
 
  motoroff(); /* Motor ausschalten */

  CloseDevice(request);        /* Trackdisk-Device schließen */

  FreeMem(buffer,PUFFER);       
}

/* ------------------------------------------------------------------------- */



