/*
** ppc.library emulation
** (c)1998-99 Frank Wille <frank@phoenix.owl.de>
**
** PowerUp kernel startup/cleanup
**
** V0.5d (28.03.1999) phx
**       Created.
**       kernel_init() and kernel_cleanup() were moved from kerntasks.c.
**       Initialize PortList.
**       CPU-specific semaphores were replaced by MPSemaphore LibMPS.
**
** Copied history from kerntasks.c:
** V0.5a (26.01.1999) phx
**       Initialize semaphore for accessing the PPC-part of the library.
** V0.4c (20.01.1999) phx
**       Initialize ElfLibrary list and semaphore.
**       Renamed kernel_exit into kernel_cleanup.
*/

#include "ppclibemu.h"
#include "timerobject.h"
#include "warpos_protos.h"


static char *dbentry = "%s\n";
static char *dbleave = "%s successful!\n";
static void (*TimerObjectServerPtr)() = TimerObjectServer;


extern const char *TimerObjSrvName;
extern void DPrintf(struct PPCLibBase *,char *,...);



static struct TaskPPC *launchTask(struct PPCLibBase *ppcbase,ULONG entry,
                                  const char *name,int pri,ULONG stksize)
/* Launch a PPC task and wait until it signals that the initialization */
/* has finished. */
{
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct TagItem ti[9];
  struct TaskPPC *tsk;
  LONG sig = __AllocSignalPPC(wosbase,-1);

  ti[0].ti_Tag = TASKATTR_CODE;
  ti[0].ti_Data = entry;
  ti[1].ti_Tag = TASKATTR_NAME;
  ti[1].ti_Data = (ULONG)name;
  ti[2].ti_Tag = TASKATTR_PRI;
  ti[2].ti_Data = (ULONG)pri;
  ti[3].ti_Tag = TASKATTR_STACKSIZE;
  ti[3].ti_Data = stksize;
  ti[4].ti_Tag = TASKATTR_R2;
  ti[4].ti_Data = (ULONG)__get_r2();
  ti[5].ti_Tag = TASKATTR_R3;
  ti[5].ti_Data = (ULONG)ppcbase;
  ti[6].ti_Tag = TASKATTR_R4;
  ti[6].ti_Data = (ULONG)__FindTaskPPC(wosbase,NULL);
  ti[7].ti_Tag = TASKATTR_R5;
  ti[7].ti_Data = (ULONG)(1 << sig);
  ti[8].ti_Tag = TAG_END;

  if (tsk = __CreateTaskPPC(wosbase,ti)) {
    /* give the new task 3s to finish initialization */
    if (!__WaitTime(wosbase,1<<sig,3000000))
      tsk = NULL;
  }

  __FreeSignalPPC(wosbase,sig);
  return (tsk);
}


BOOL kernel_init(struct PPCLibBase *ppcbase)
/* initialize PowerUp kernel emulation, start emulation support tasks */
{
  static char *dname = "PPC kernel_init()";
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct TagItem ti[4];

  __set_r2(ppcbase->WOSLinkerDB);
  DPrintf(ppcbase,dbentry,dname);

  /* determine PVR, bus clock and cpu clock */
  ti[0].ti_Tag = GETINFO_PVR;
  ti[1].ti_Tag = GETINFO_BUSCLOCK;
  ti[2].ti_Tag = GETINFO_CPUCLOCK;
  ti[3].ti_Tag = TAG_END;
  __GetInfo(wosbase,ti);
  ppcbase->ppc_PVR = ti[0].ti_Data;
  ppcbase->ppc_BusClock = ti[1].ti_Data;
  ppcbase->ppc_CPUClock = ti[2].ti_Data;
  DPrintf(ppcbase,"%s: PVR=0x%08lx BusClk=%ld CpuClk=%ld\n",
          dname,ti[0].ti_Data,ti[1].ti_Data,ti[2].ti_Data);

  /* launch TimerObject server task */
  if (!(ppcbase->TimerObjSrv = launchTask(ppcbase,(ULONG)TimerObjectServerPtr,
                                          TimerObjSrvName,-1,16384)))
    return (FALSE);

  _newlist(&ppcbase->ElfLibraries);
  _newlist(&ppcbase->PortList);

  DPrintf(ppcbase,dbleave,dname);
  return (TRUE);
}


void kernel_cleanup(struct PPCLibBase *ppcbase)
/* kernel emulation cleanup - kill all support tasks */
{
  static char *dname = "PPC kernel_cleanup()";
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct MsgPortPPC *rp,*mp;

  __set_r2(ppcbase->WOSLinkerDB);
  DPrintf(ppcbase,dbentry,dname);

  /* stop TimerObject server task, if running */
  if (mp = __FindPortPPC(wosbase,(STRPTR)TimerObjSrvName)) {
    struct TimObjSrvMsg tomsg;

    rp = InitTOMsg(wosbase,&tomsg,NULL,TOCMD_EXIT);
    /* send termination message */
    __PutMsgPPC(wosbase,mp,(struct Message *)&tomsg);
    if (rp)
      while (tomsg.to_Msg.mn_Node.ln_Type != NT_REPLYMSG)
        __WaitPortPPC(wosbase,rp);
    __DeleteMsgPortPPC(wosbase,rp);
  }

  DPrintf(ppcbase,dbleave,dname);
}
