/*
** ppc.library emulation
** (c)1998-99 Frank Wille <frank@phoenix.owl.de>
**
** PowerPC task init and exit functions
**
** V0.7  (11.12.1999) phx
**       Set current directory and PROGDIR for the M68k partner task of an
**       asynchronous PPC task to PROGDIR of M68k parent. Asynchronous
**       PPC tasks will get a completely new M68k partner task under WarpOS,
**       which don't know any paths.
** V0.6e (14.05.1999) phx
**       PowerUp task priority is converted into a WarpOS nice-value,
**       by using the simple formula: NICE = -PRI
** V0.6  (10.04.1999) phx
**       Delete the PPC MsgPort, if required.
** V0.5d (04.04.1999) phx
**       Created.
*/

#include "ppclibemu.h"
#include "msgsystem.h"
#include "taskobject.h"
#include "mpsema_protos.h"
#include "warpos_protos.h"

#ifdef KERNEL_DEBUG
#define KDB(x) x
#else
#define KDB(x)
#endif

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



void __saveds PPCTaskInit(struct PPCLibBase *ppcbase,
                          struct TaskObject *to,BYTE sigbit)
/* This function is called before launching a new PPC task. */
{
  struct PPCArgs pa;
  struct PPCBase *wosbase = ppcbase->PowerPCBase;
  struct PPCMessage *m;
  struct Task *task68k;
  ULONG dirlock;

  __set_r2(ppcbase->WOSLinkerDB);
  KDB(DPrintf(ppcbase,"Kernel: PPCTaskInit(): TaskObject=0x%08lx "
              "SigBit=%ld\n",to,(LONG)sigbit));

  obtainMPSemaphorePPC(ppcbase,&to->mpSema);

  if (dirlock = (ULONG)to->progdirLock) {
    /* set PROGDIR: and current directory for asynchronous PPC tasks */
    _memset(&pa,sizeof(struct PPCArgs),0);
    pa.PP_Code = (APTR)ppcbase->DOSBase;
    pa.PP_Offset = -126;  /* _LVOCurrentDir */
    pa.PP_Regs[PPREG_D1] = dirlock;
    pa.PP_Regs[PPREG_A6] = (ULONG)ppcbase->DOSBase;
    __Run68K(wosbase,&pa);

    _memset(&pa,sizeof(struct PPCArgs),0);
    pa.PP_Code = (APTR)ppcbase->DOSBase;
    pa.PP_Offset = -594;  /* _LVOSetProgramDir */
    pa.PP_Regs[PPREG_D1] = dirlock;
    pa.PP_Regs[PPREG_A6] = (ULONG)ppcbase->DOSBase;
    __Run68K(wosbase,&pa);
    KDB(DPrintf(ppcbase,"\tset PROGDIR to lock 0x%08lx\n",dirlock));
  }

  if (to->flags & TskObjF_MsgPort) {
    /* create a MsgPort */
    to->ppc_port = createPPCMsgPort(ppcbase,NULL,NULL);
    KDB(DPrintf(ppcbase,"\tcreated PPCMsgPort at 0x%08lx\n",to->ppc_port));
  }

  if (m = to->startup) {
    /* init startup message */
    KDB(DPrintf(ppcbase,"\tinitializing startup message\n"));
    m->data = to->msg_data;
    m->datasize = to->msg_length;
    m->msgid = to->msg_id;
  }

  /* convert priority into a nice value */
  __SetNiceValue(wosbase,to->this,-(LONG)to->n.ln_Pri);

  task68k = to->m68kParent;
  KDB(DPrintf(ppcbase,"\t68k parent task = 0x%08lx\n",task68k));
  releaseMPSemaphorePPC(ppcbase,&to->mpSema);

  if (sigbit >= 0) {
    /* notify M68k parent process, that PPC task startup has completed */
    _memset(&pa,sizeof(struct PPCArgs),0);
    pa.PP_Code = (APTR)ppcbase->SysBase;
    pa.PP_Offset = -324;  /* _LVOSignal */
    pa.PP_Regs[PPREG_A1] = (ULONG)task68k;
    pa.PP_Regs[PPREG_D0] = 1L<<(ULONG)sigbit;
    pa.PP_Regs[PPREG_A6] = (ULONG)ppcbase->SysBase;
    KDB(DPrintf(ppcbase,"\tnotifying m68k parent: SigMask = 0x%08lx\n",
                1L<<(ULONG)sigbit));
    __Run68K(wosbase,&pa);
  }
  KDB(DPrintf(ppcbase,"\tPPC task startup completed\n"));
}


void __saveds PPCTaskExit(struct PPCLibBase *ppcbase,struct TaskObject *to)
/* This function is called when a PPC task terminates. */
{
  struct PPCMessage *m;

  __set_r2(ppcbase->WOSLinkerDB);
  KDB(DPrintf(ppcbase,"Kernel: PPCTaskExit()\n"));
  obtainMPSemaphorePPC(ppcbase,&to->mpSema);
  if (m = to->startup) {
    KDB(DPrintf(ppcbase,"\treplying startup message 0x%08lx\n",m));
    replyPPCMessage(ppcbase,m);  /* reply startup message */
  }
  if (to->ppc_port)
    while (!deletePPCMsgPort(ppcbase,to->ppc_port));
  releaseMPSemaphorePPC(ppcbase,&to->mpSema);
}


BOOL kernel_deletetask(struct PPCLibBase *ppcbase,
                                struct TaskObject *to)
/* kill a running task, used by PPCDeleteTask() (68k) */
{
  KDB(DPrintf(ppcbase,"Kernel: kernel_deletetask(): PPC task = 0x%08lx\n",
              to->this));
  __DeleteTaskPPC(ppcbase->PowerPCBase,to->this);
  return (TRUE);
}
