/*
	SetCPU V1.60
	by Dave Haynie, April 13, 1990
	Released to the Public Domain

	DISKIO.C MODULE

	This module is responsible for fetching ROM images from various
	kinds of disks and files.
*/

#include "setcpu.h"

/* This function allocates a ROM image from a KickStart disk for KICKROM. */

#define ColorShift(x)	(LONG)((((x)&0xf)+1)%15)

struct systag *AllocKSImage(name)
char *name;
{
   struct systag *tag = NULL;
   ULONG *buf = NULL, blocks;
   char *ptr;
   LONG unit, i, r = 0x0004L, g = 0x0008L, b = 0x000cL,start;
   struct MsgPort *port = NULL;
   struct IOStdReq *req = NULL;
   struct Window *hand = NULL;
   BOOL devok = FALSE;
   
 /* Then we expect it to be a kickstart disk, so we check out the device,
    the disk, etc.  If all goes well, we'll be in business. */

   if ((unit = CheckTDDev(name)) == -1L) {
      LoadErr = 16;
      goto fail;
   }
   
  /* This is the stuff that need opening... */
   port = (struct MsgPort *) CreatePort("diskreq.port",0L);   
   if (port) req = CreateStdIO(port,0L);
   if (req) devok = !OpenDevice("trackdisk.device",unit,(struct IORequest *)req,0L);
   if (devok) buf = (ULONG *)AllocMem(512L,MEMF_CHIP);
   if (!port || !req || !devok || !buf) goto fail;

  /* Make sure we're a kick disk. */
   hand = CoolHand();
   while ((ReadBuf((char *)buf,0L,req) != READOK) || 
          !strniequ("KICK",(char *)buf,4))
      Delay(150L);
      
  /* Check the size of this kickstart. */

   if (!(tag = AllocMem(SizeOf(struct systag),0L))) goto fail;
   start = 0;
   do {
      if (ReadBuf((char *)buf,++start,req) != READOK) goto fail;
      ptr = (char *)SizeROM(tag,buf,TRUE);
   } while (ptr == NULL && start < 32L);

   if (!ptr) goto fail;

   blocks = tag->romsize/512L;
         
  /* Looks like we're in shape to get the actual system. */

   SetRGB4(&(hand->WScreen->ViewPort),2L,r,g,b);
   for (i = 1; i <= blocks; ++i) {
      if (ReadBuf((char *)buf,i,req) != READOK) break;
      MemCopy((char *)buf,ptr,512L);
      ptr += 512L;
      r = ColorShift(r);
      g = ColorShift(g);
      b = ColorShift(b);

      SetRGB4(&(hand->WScreen->ViewPort),2L,r,g,b);
   }
   LoadErr = 0;
   
done:
   if (buf) FreeMem((char *)buf,512L);
   if (devok) {
      MotorOff(req);
      CloseDevice((struct IORequest *)req);
   }
   if (req)  DeleteStdIO(req);
   if (port) DeletePort(port);
   return tag;
   
fail:
   if (tag) {
      FreeMem(tag,SizeOf(struct systag));
      tag = NULL;
   }
   goto done;
}

/* This function allocates a ROM image from an AmigaDOS file for either
   KICKROM or FASTROM. */

struct systag *AllocFILEImage(name)
char *name;
{
   struct systag *tag = NULL;
   ULONG *rom = NULL, space[2], check;
   BPTR file = NULL;
   struct FileInfoBlock *fib;
   
  /* First off, let's check out this here file. */
  
   if (!(fib = AllocMem(SizeOf(struct FileInfoBlock),0L))) goto fail;
   if (!(file = Lock(name,ACCESS_READ))) {
      LoadErr = 24;
      goto fail;
   }
   Examine(file,fib);
   UnLock(file);
   file = NULL;   
   if (fib->fib_DirEntryType > 0L || !(file = Open(name,MODE_OLDFILE))) {
      LoadErr = 24;
      goto fail;
   }
   
  /* Try to find a sensible ROM header, either its a plain ROM, or the one
     with the extra sizing info at the head. */

   Read(file,(char *)space,8L);
   if (space[0])
      Seek(file,0L,OFFSET_BEGINNING);
   else {
      check = space[1];
      Read(file,(char *)space,8L);
      Seek(file,8L,OFFSET_BEGINNING);
   }

  /* Let's allocate the space I need.  KICKROMs don't use a disk image
     directly, so they don't need an MMU table and don't care about any special
     alignment.  FASTROMs read from disk do care, so I will align this image. */
  
   SmartlyGetRange();
   if (!(tag = AllocAligned(SizeOf(struct systag),8L))) goto fail;

   if (!(rom = SizeROM(tag,space,TRUE))) {
      LoadErr == 22;
      goto fail;
   }
   if (tag->romsize != Read(file,(char *)rom,tag->romsize)) {
      LoadErr = 23;
      goto fail;
   }
   Close(file);
   FreeMem(fib,SizeOf(struct FileInfoBlock));
   return tag;

fail:
   if (file) Close(file);
   if (fib) FreeMem(fib,SizeOf(struct FileInfoBlock));   
   if (rom) FreeMem(rom,tag->romsize);
   if (tag) FreeMem(tag,SizeOf(struct systag));
   return NULL;   
}

/* This function gets a ROM image from disk; in temporary unaligned memory
   for a KICKROM image, permanent aligned memory for a FASTROM image. */

struct systag *AllocDISKImage(type,name)
UWORD type;
char *name;
{
   struct systag *tag;
   ULONG *table;

  /* Reset the error code. */
   LoadErr = 0;

  /* Let's check out this here file.  It's easy to tell; we want a FILE
     image if we aren't passed a KICK_ROM request with a device name. */
  
   if (type == ROM_FAST || name[strlen(name)-1] != ':') {
      tag = AllocFILEImage(name);
      if ((tag->romtype = type) == ROM_FAST) {
         FindWrap(tag);
         if (!(table = AllocAligned(tag->tablesize+4,TABROUND))) return NULL;
         tag->maintable = table;
         FillBasicTable(tag,FALSE);
      }
      return tag;
   } 
     
   return AllocKSImage(name);
}
