struct MemHeader;
struct Device;
struct IORequest;
struct SemaphoreMessage;
struct SignalSemaphore;
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/resident.h>
#include <exec/libraries.h>
#include <dos/dos.h> 
#include <emul/emulinterface.h>
#include <emul/emulregs.h>
#include <proto/exec.h>
#include "a2ixlibrary.h"

#ifdef DEBUG
void dprintf(const char *,...);
#define DB(x) x
#else
#define DB(x)
#endif

#define __a4_offset (-4 - 4 * LIBRARY_ID)

struct MyBase {
    struct Library lib;
    UWORD flags;
    ULONG cookie;
    BPTR seglist;
    ULONG id;
};

int (*funcTable[])();
extern int (*ppcFuncTable[])();
struct ExecBase *SysBase;

struct MyBase* _initRoutine(struct MyBase *base,
			    BPTR seglist,
			    struct ExecBase *sysbase);

struct MyBase *lib_open(struct MyBase *);
void __LibCloseInstance(void);
int __LibRelocateInstance(char *stext, ULONG *tf, ULONG *td,
			  char *sdata, ULONG *df, ULONG *dd,
			  ULONG *libdata);
void __LibSetVarsInstance(int argc, void *ixbase,
			  int *errnoptr, char *ctype, void **sf,
			  void **stk_limit);

struct LibInitStruct {
  ULONG LibSize;
  void  *FuncTable;
  void  *DataTable;
  void  (*InitFunc)(void);
};

struct LibInitStruct Init={
  sizeof(struct MyBase),
  funcTable,
  NULL,
  (void (*)(void)) &_initRoutine
};

int libReserved(void) {
  return 0;
}

const struct Resident initDDescrip={
  RTC_MATCHWORD,
  (APTR)&initDDescrip,
  (APTR)&initDDescrip + 1,
  RTF_PPC | RTF_AUTOINIT,
  VERSION,
  NT_LIBRARY,
  0,
  FULLNAME,
  IDSTRING "\r\n",
  &Init
};

/*
 * To tell the loader that this is a new emulppc elf and not
 * one for the ppc.library.
 * ** IMPORTANT **
 */
ULONG   __amigappc__=1;



/* RTF_PPC flag set, so the initialization routine is called
 * as a normal PPC SysV4 ABI */
struct MyBase *_initRoutine(struct MyBase *base,
			    BPTR seglist,
			    struct ExecBase *sysbase) {
  DB(dprintf("init(%lx)\n", base);)
  base->seglist = seglist;
  base->cookie = 0x4a4a5600;
  base->id = __a4_offset;
  SysBase = sysbase;
  return base;
}


struct MyBase *libOpen(void) {
  struct MyBase *base = (struct MyBase *) REG_A6;

  DB(dprintf("libOpen(%lx)\n", base);)
  ++base->lib.lib_OpenCnt;
  base->lib.lib_Flags &= ~LIBF_DELEXP;
  if (!lib_open(base))
  {
    --base->lib.lib_OpenCnt;
    base = NULL;
  }
  return base;
}

ULONG libExpungeFunc(struct MyBase *base) {
  ULONG seg;

  DB(dprintf("libExpunge(%lx)\n", base);)

  /* assume we can't expunge */
  seg = 0;
  base->lib.lib_Flags |= LIBF_DELEXP;

  if (base->lib.lib_OpenCnt == 0)
    {
      Remove(&base->lib.lib_Node);

      FreeMem((char *)base - base->lib.lib_NegSize,
	      base->lib.lib_NegSize + base->lib.lib_PosSize);

      seg = base->seglist;
    }

  return seg;
}

ULONG libExpunge(void) {
  struct MyBase *base = (struct MyBase *) REG_A6;
  return libExpungeFunc(base);
}

ULONG libClose(void) {
  struct MyBase *base = (struct MyBase *) REG_A6;

  DB(dprintf("libClose(%lx)\n", base);)
  if (--base->lib.lib_OpenCnt == 0 &&
      base->lib.lib_Flags & LIBF_DELEXP)
    return libExpungeFunc(base);

  return 0;
}

asm("
	.globl 	__restore_r13
	.type	__restore_r13,@function
	.equ	__a4_offset,(-4 - 4 *"xstr(LIBRARY_ID)")
__restore_r13:
	lis	13,SysBase@ha
	lwz	13,SysBase@l(13)
	lwz	13,0x114(13)	/* ThisTask */
        lwz	13,0x2e(13)	/* TrapData */
	lwz	13,__a4_offset(13)
	blr
");

int (*funcTable[])() = {

  (int(*)())FUNCARRAY_32BIT_NATIVE,

  /* standard system routines */
  (int(*)())&libOpen,
  (int(*)())&libClose,
  (int(*)())&libExpunge,
  (int(*)())&libReserved,

  /* my libraries definitions */

  (int(*)())&__LibCloseInstance,
  (int(*)())&__LibRelocateInstance,
  (int(*)())&__LibSetVarsInstance,

  (int(*)())-1
};


