/*
** Install2.c - give preference to MEMF_CHIP and deactivate external drives
** Copyright (C) 1987 Ralph Babel, Falkenweg 3, D-6204 Taunusstein
** all rights reserved - alle Rechte vorbehalten
**
** 23-May-1987 created Install1.c
** 07-Aug-1987 changed for new boot code
** 30-Mar-1988 cleanup
*/
/*** included files ***/
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <devices/bootblock.h>
#include <devices/trackdisk.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

/*** external function references ***/
APTR AllocMem(ULONG, ULONG);
VOID FreeMem(APTR, ULONG);
struct IOStdReq *CreateStdIO(struct MsgPort *);
VOID DeleteStdIO(struct IOStdReq *);
BYTE OpenDevice(char *, LONG, struct IORequest *, ULONG);
VOID CloseDevice(struct IORequest *);
BYTE DoIO(struct IORequest *);
struct Task *FindTask(char *);
VOID CopyMem(APTR, APTR, ULONG);
VOID printf(char *, );
LONG toupper(LONG);
/*** constants ***/
#define ROOT 880 /* default AmigaDOS root block (3.5 inch) */
/*** structures ***/
struct BootSectors
 {
 struct BootBlock bs_BootBlock;
 UBYTE bs_Data[BOOTSECTS * TD_SECTOR - sizeof(struct BootBlock)];
 };
/*** the boot code ***/
UWORD BootCode[] =
 {
 0x2F02, 0x4EAE, 0xFF7C, 0x226E, 0x0142, 0x6020,
 0x0829, 0x0001, 0x000F, 0x6716, 0x2F09, 0x4EAE,
 0xFF04, 0x225F, 0x137C, 0x000A, 0x0009, 0x41EE,
 0x0142, 0x4EAE, 0xFEF2, 0x2242, 0x2411, 0x66DC,
 0x4EAE, 0xFF76, 0x241F, 0x43FA, 0x0032, 0x4EAE,
 0xFE0E, 0x4A80, 0x6724, 0x2040, 0x41E8, 0x0034,
 0x70FF, 0x20C0, 0x20C0, 0x2080, 0x43FA, 0x0026,
 0x4EAE, 0xFFA0, 0x4A80, 0x670A, 0x2040, 0x2068,
 0x0016, 0x7000, 0x4E75, 0x70FF, 0x4E75, 0x6469,
 0x736B, 0x2E72, 0x6573, 0x6F75, 0x7263, 0x6500,
 0x646F, 0x732E, 0x6C69, 0x6272, 0x6172, 0x7900
 };
/*** entry point ***/
LONG main(argc, argv)
LONG argc;
char *argv[];
 {
 struct BootSectors *bs;
 struct IOStdReq *iosr;
 struct Process *pr;
 ULONG checksum, precsum;
 UWORD i;
 LONG result;
 result = RETURN_WARN; /* user error */
 if(argc == 2
 && toupper(argv[1][0]) == 'D'
 && toupper(argv[1][1]) == 'F'
 && argv[1][2] >= '0' && argv[1][2] <= '3'
 && argv[1][3] == ':'
 && argv[1][4] == '\0')
  {
  result = RETURN_FAIL; /* no resources */

  if((bs = (struct BootSectors *)
   AllocMem(sizeof(struct BootSectors), MEMF_CHIP | MEMF_CLEAR)) != NULL)
   {
   pr = (struct Process *)FindTask(NULL);
   if((iosr = CreateStdIO(&pr->pr_MsgPort)) != NULL)
    {
    result = RETURN_ERROR; /* disk error */
    if(OpenDevice(TD_NAME, argv[1][2] - '0', (struct IORequest *)iosr, 0) == 0)
     {
     *(ULONG *)bs->bs_BootBlock.bb_id = BBNAME_DOS;
     bs->bs_BootBlock.bb_dosblock = ROOT;
     CopyMem((APTR)BootCode, (APTR)bs->bs_Data, sizeof(BootCode));
     checksum = 0;
     for(i = 0; i < 256; ++i)
      {
      precsum = checksum;
      if((checksum += ((ULONG *)bs)[i]) < precsum)
       ++checksum;
      }
     bs->bs_BootBlock.bb_chksum = 0xffffffff - checksum;
     iosr->io_Command = CMD_WRITE;
     iosr->io_Length  = sizeof(struct BootSectors);
     iosr->io_Data    = (APTR)bs;
     iosr->io_Offset  = 0;
     if(DoIO((struct IORequest *)iosr) == 0)
      {
      iosr->io_Command = CMD_UPDATE;
      (void)DoIO((struct IORequest *)iosr);
      }
     if(iosr->io_Error != 0)
      {
      printf("%s failed, trackdisk error %ld\n", argv[0], iosr->io_Error);
      }
     else
      {
      result = RETURN_OK; /* everything fine */
      }
     iosr->io_Command = TD_MOTOR;
     iosr->io_Length  = 0;
     (void)DoIO((struct IORequest *)iosr);
     CloseDevice((struct IORequest *)iosr);
     }
    else
     {
     printf("Unable to open trackdisk device, error %ld\n", iosr->io_Error);
     }
    DeleteStdIO(iosr);
    }
   else
    {
    printf("Unable to create IO request\n");
    }
   }
  else
   {
   printf("Insufficient free store\n");
   }
  }
 else
  {
  printf("Usage: %s {DF0:|DF1:|DF2:|DF3:}\n", argv[0]);
  }
 return result;
 }
