/*---------------------------------------------------------------------------*
  Project:  NitroSDK - CTRDG
  File:     ctrdg.c

  Copyright 2003,2004 Nintendo.  All rights reserved.

  These coded instructions, statements, and computer programs contain
  proprietary information of Nintendo of America Inc. and/or Nintendo
  Company Ltd., and are protected by Federal copyright law.  They may
  not be disclosed to third parties or copied or duplicated in any form,
  in whole or in part, without the prior written consent of Nintendo.

  $Log: ctrdg_proc.c,v $
  Revision 1.11  2004/11/24 04:38:18  yada
  just fix typo

  Revision 1.10  2004/09/28 05:06:15  yada
  fix a little

  Revision 1.9  2004/09/27 13:46:42  yada
  only arrange comments

  Revision 1.8  2004/09/17 00:07:27  yada
  avoid warning by overriding pxi callback

  Revision 1.7  2004/09/16 04:15:24  yada
  fix a little

  Revision 1.6  2004/09/15 09:50:12  yada
  on default, pulling out cartridge doesn't cause terminate.

  Revision 1.5  2004/09/15 05:55:46  yada
  change include

  Revision 1.4  2004/09/14 13:07:26  yada
  fix small bug

  Revision 1.3  2004/09/14 13:01:50  yada
  CallbackForPulledOut->PulledOutCallback

  Revision 1.2  2004/09/14 10:52:30  yada
  fix address data sent to ARM7 via PXI

  Revision 1.1  2004/09/14 09:58:21  yada
  initial release

  $NoKeywords: $
 *---------------------------------------------------------------------------*/
#include <nitro.h>
#include <../include/ctrdg_work.h>

extern void CTRDGi_InitCommon( void );
extern void CTRDGi_SendtoPxi( u32 data );

//---- pxi callbacks
static void CTRDGi_CallbackForInitModuleInfo( PXIFifoTag tag, u32 data, BOOL err );
static void CTRDGi_PulledOutCallback( PXIFifoTag tag, u32 data, BOOL err );

extern CTRDGWork  CTRDGi_Work;


//---- user callback
CTRDGPulledOutCallback    CTRDG_UserCallback = NULL;

//================================================================================
//            INIT
//================================================================================
/*---------------------------------------------------------------------------*
  Name:         CTRDG_Init

  Description:  initialize cartridge functions

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
void CTRDG_Init( void )
{
    static BOOL isInitialized;

    if ( isInitialized ){ return; }
    isInitialized = TRUE;

    CTRDGi_InitCommon();

#ifndef SDK_SMALL_BUILD
    //---- setting PXI
    PXI_Init();
    while( ! PXI_IsCallbackReady( PXI_FIFO_TAG_CTRDG, PXI_PROC_ARM7 ) ) {}
    PXI_SetFifoRecvCallback( PXI_FIFO_TAG_CTRDG, CTRDGi_CallbackForInitModuleInfo );

    CTRDGi_InitModuleInfo();

    PXI_SetFifoRecvCallback( PXI_FIFO_TAG_CTRDG, NULL ); // to avoid warning by overriding
    PXI_SetFifoRecvCallback( PXI_FIFO_TAG_CTRDG, CTRDGi_PulledOutCallback );

    //---- init user callback
    CTRDG_UserCallback = NULL;

#endif  // SDK_SMALL_BUILD
}

/*---------------------------------------------------------------------------*
  Name:         CTRDGi_InitModuleInfo

  Description:  initialize the information of peripheral device around cartridge

                Because try lock cartridge, in case another processor had locked,
                wait till its was released.

                To avoid other bus master interrupts,
                DMA0 is used for accessing cartridge.
                This is a compatibility in future.

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
static CTRDGHeader headerBuf ATTRIBUTE_ALIGN(32);

void CTRDGi_InitModuleInfo( void )
{
#ifndef SDK_SMALL_BUILD

    static BOOL      isInitialized;
    CTRDGLockByProc  lockInfo;
    OSIrqMask        lastIE;
    BOOL             lastIME;
    int              i;
    
    CTRDGModuleInfo *cip = CTRDGi_GetModuleInfoAddr();
    
    if ( isInitialized ){ return; }
    isInitialized = TRUE;
    
    if ( ! (reg_OS_PAUSE & REG_OS_PAUSE_CHK_MASK) ){ return; }
    
    lastIE = OS_SetIrqMask( OS_IE_SPFIFO_RECV );
    lastIME = OS_EnableIrq();
    
    //---- get privilege for accessing cartridge
    CTRDGi_LockByProcessor( CTRDGi_Work.lockID, &lockInfo );
    
    //---- read information of peripheral devices
    {   MIProcessor proc = MI_GetMainMemoryPriority();
        CTRDGRomCycle rc;
        
        // set the latest access cycle
        CTRDGi_ChangeLatestAccessCycle( &rc );
        
        // set main memory priority for avoiding DMA stole by ARM7 access
        MI_SetMainMemoryPriority( MI_PROCESSOR_ARM9 );

        // 16bit access in order to have much enough access interval
        MI_DmaCopy16( 0, (void *)(HW_CTRDG_ROM+0x80),
                      &((u8 *)&headerBuf)[0x80], sizeof(headerBuf)-0x80 );

        MI_SetMainMemoryPriority( proc );
        
        //---- restore access cycle
        CTRDGi_RestoreAccessCycle( &rc );
    }
    
    //---- release privilege for accessing cartridge
    CTRDGi_UnlockByProcessor( CTRDGi_Work.lockID, &lockInfo );
    
    //---- copy the information of peripheral devices to system area
    {
        CTRDGHeader *chb = &headerBuf;

        cip->moduleID.raw = chb->moduleID;
        for( i=0; i<3; i++ ) 
        {
            cip->exLsiID[i] = chb->exLsiID[i];
        }
        cip->makerCode = chb->makerCode;
        cip->gameCode = chb->gameCode;
    }

    //---- copy NINTENDO logo data in the ARM9 system ROM to main memory
    MI_CpuCopy32( (void *)CTRDG_SYSROM9_NINLOGO_ADR, &headerBuf.nintendoLogo,
                  sizeof( headerBuf.nintendoLogo ) );
    DC_FlushAll();

    //---- send message to ARM7
    CTRDGi_SendtoPxi( CTRDG_PXI_COMMAND_INIT_MODULE_INFO |
                      (((u32)&headerBuf - HW_MAIN_MEM)>>5) <<CTRDG_PXI_COMMAND_PARAM_SHIFT );

    //---- wait till ARM7 finish initialize
    while ( CTRDGi_Work.subpInitialized != TRUE )
    {
        SVC_WaitByLoop( 1 );
    }

    (void)OS_RestoreIrq( lastIME );
    (void)OS_SetIrqMask( lastIE );

#endif  // SDK_SMALL_BUILD
}

/*---------------------------------------------------------------------------*
  Name:         CTRDGi_CallbackForInitModuleInfo

  Description:  callback to receive data from PXI

  Arguments:    tag  : tag from PXI (unused)
                data : data from PXI
                err  : error bit (unused)

  Returns:      None
 *---------------------------------------------------------------------------*/
static void CTRDGi_CallbackForInitModuleInfo( PXIFifoTag tag, u32 data, BOOL err )
{
#pragma unused( tag, err )

  if ( (data & CTRDG_PXI_COMMAND_MASK) == CTRDG_PXI_COMMAND_INIT_MODULE_INFO )
  {
      CTRDGi_Work.subpInitialized = TRUE;
  }
  else
  {
#ifndef SDK_FINALROM
      OS_Panic( "illegal Cartridge pxi command." );
#else
      OS_Panic( "" );
#endif
  }
}

//================================================================================
//            PULLOUT PROCS
//================================================================================
/*---------------------------------------------------------------------------*
  Name:         CTRDGi_PulledOutCallback

  Description:  callback to receive data from PXI

  Arguments:    tag  : tag from PXI (unused)
                data : data from PXI
                err  : error bit (unused)

  Returns:      None
 *---------------------------------------------------------------------------*/
static void CTRDGi_PulledOutCallback( PXIFifoTag tag, u32 data, BOOL err )
{
#pragma unused( tag, err )

  //---- receive message 'pulled out'
  if ( (data & CTRDG_PXI_COMMAND_MASK) == CTRDG_PXI_COMMAND_PULLED_OUT )
  {
      BOOL isTerminateImm = FALSE;

      //---- call user callback
      if ( CTRDG_UserCallback ){ isTerminateImm = CTRDG_UserCallback(); }

      //---- terminate
      if ( isTerminateImm ){ CTRDG_TerminateForPulledOut(); }
  }
  else
  {
#ifndef SDK_FINALROM
      OS_Panic( "illegal Cartridge pxi command." );
#else
      OS_Panic( "" );
#endif
  }
}

/*---------------------------------------------------------------------------*
  Name:         CTRDG_SetPulledOutCallback

  Description:  set user callback for being pulled out cartridge

  Arguments:    callback : callback

  Returns:      None
 *---------------------------------------------------------------------------*/
void CTRDG_SetPulledOutCallback( CTRDGPulledOutCallback callback )
{
  CTRDG_UserCallback = callback;
}

/*---------------------------------------------------------------------------*
  Name:         CTRDG_TerminateForPulledOut

  Description:  terminate for pulling out cartridge.
                send message to do termination to ARM7

  Arguments:    None

  Returns:      None
 *---------------------------------------------------------------------------*/
void CTRDG_TerminateForPulledOut( void )
{
  //---- send 'TERMINATE' command to ARM7, and terminate itself immediately
  CTRDGi_SendtoPxi( CTRDG_PXI_COMMAND_TERMINATE );

  OS_Terminate();
}

