/* Source code of RomDump - tool for dumping PCI boards ROMs to a file      */
/* It demonstrates use of prometheus.library.                               */

#define	__USE_SYSBASE

#include	<dos/dos.h>
#include	<dos/dosextens.h>
#include <exec/memory.h>
#include	<exec/types.h>
#include	<intuition/intuitionbase.h>
#include	<libraries/asl.h>
#include	<libraries/prometheus.h>

#include	<proto/asl.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include	<proto/intuition.h>
#include <proto/prometheus.h>

struct Library *PrometheusBase = NULL;

const char *VString = "$VER: RomDump 1.2 (26.7.2001) © 2001 Matay";

#define NOCARD (-1)

WORD SelectCard(WORD max)
 {
  WORD number;
  BPTR stdin = Input(), stdout = Output();

  for(;;)
   {
    Printf("Input board number: ");

    Flush(stdout);
    Flush(stdin);

    number = FGetC(stdin);

    if((number == -1) || (number == '\n')) return (NOCARD);
    else if(( number > '0') && (number <= ('0' + max))) return((WORD)(number - '1'));
    else
     {
      Printf("\rWrong card number! Card number must be %s%ld.\nTry again or press enter to break.\n",
       (( max > 1) ? "between 1 to " : ""), max);
     }
   }
 }

#define BUFFERSIZE 2048

VOID WriteRom(APTR address, ULONG size)
 {
  STRPTR	filename = "RAM:dump";
  BPTR dumpfh;

  if (dumpfh = Open(filename, MODE_NEWFILE))
   {
    UBYTE *buffer;

    if (buffer = AllocMem(BUFFERSIZE, MEMF_ANY))
     {
      UBYTE *bufptr;
      ULONG i;
      ULONG	bytes	= 0;

      for (bufptr = (UBYTE*)address; bufptr < ((UBYTE*)address + size); bufptr += BUFFERSIZE)
       {
        for(i = 0; i < BUFFERSIZE; i++)
         {
          buffer[i] = bufptr[i];
          CacheClearU();
          buffer[i] = bufptr[i];
         }
        FWrite(dumpfh, buffer, BUFFERSIZE, 1);
        bytes += BUFFERSIZE;
        Printf("%ld kB done...     \r", (bytes >> 10));
       }
      FreeMem(buffer, BUFFERSIZE);
     }
    else Printf( "Out of memory!\n" );
    Close( dumpfh );
   }
  else
  Printf( "Can't open file!\n" );
 }

#ifndef INTUITIONNAME
#define INTUITIONNAME "intuition.library"
#endif /* INTUITIONNAME */

#define MAXCARDS 4

int main(int argc, int *argv[])
 {
  int	result = RETURN_FAIL;

  Printf("%s\n", (ULONG)&VString[6]);
  Printf("PCI cards with ROMs:\n-------------------------------------------------\n");

  if (!(PrometheusBase = OpenLibrary(PROMETHEUSNAME, PROMETHEUSMINVERSION)))
   Printf("Could not open \"%s\" V%ld!\n", (ULONG)PROMETHEUSNAME, 0);

  if(PrometheusBase)
   {
    APTR board	= NULL;
    ULONG vendor, device, romaddr, romsize;
    APTR addresses[MAXCARDS] = {0};
    ULONG sizes[MAXCARDS] = {0};
    WORD card, cards	= 0;

    while (board = Prm_FindBoardTags(board, TAG_END))
     {
      Prm_GetBoardAttrsTags( board,
       PRM_Vendor,       (ULONG)&vendor,
       PRM_Device,       (ULONG)&device,
       PRM_ROM_Address,  (ULONG)&romaddr,
       PRM_ROM_Size,     (ULONG)&romsize,
       TAG_END);

      if (romaddr && romsize)
       {
        addresses[cards] = (APTR)romaddr;
        sizes[cards] = (ULONG)romsize;

        Printf("%ld. Vendor %04lx, device %04lx, %ld kB of ROM at $%08lx.\n",
         cards + 1, vendor, device, (romsize >> 10), romaddr);

        if (cards >= MAXCARDS)
         {
          Printf( "Invalid PCI cards number! Prometheus has only %ld PCI slots.\n", MAXCARDS);
          break;
         }
        cards++;
       }
     }

    if (cards > 0)
     {
      Printf("\n");
      while ((card = SelectCard(cards)) != NOCARD)
       {
        Printf("Selected card %ld with %ld kB of ROM at %08lx.\n",
         card + 1, (sizes[card] >> 10), (ULONG)addresses[card]);
        WriteRom(addresses[card], sizes[card]);
       }
      result = RETURN_OK;
     }
    else Printf( "Sorry, your PCI cards have no ROM!\n" );
   }
  if (PrometheusBase) CloseLibrary(PrometheusBase);
  return(result);
 }
