/*---------------------------------------------------------------------------*
  Project:  NitroSDK - MB - libraries
  File:     tmp_lib_stub.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: tmp_lib_stub.c,v $
  Revision 1.59  2004/11/29 04:47:41  yosizaki
  allocate sendBuf. (avoid to share with SetMPData's buffer)

  Revision 1.58  2004/11/24 05:14:33  yosizaki
  rename MB_StartParentEx/MB_EndEx..

  Revision 1.57  2004/11/22 12:47:26  takano_makoto
  Separated the divided request send process as mb_block

  Revision 1.56  2004/11/18 07:28:46  takano_makoto
  Eliminated the argument for setting the child send size with MB_SetParentCommSize and MB_SetParentCommParam

  Revision 1.55  2004/11/11 11:46:56  yosizaki
  change WM_End/Ex to finish task-thread before WM_Reset.

  Revision 1.54  2004/11/10 07:40:03  takano_makoto
  Eliminated the MBw from mb_gameinfo.c, and clipped scan parameter

  Revision 1.53  2004/11/10 03:17:02  takano_makoto
  Added MBi_SetBeaconRecvStatusBufferDefault

  Revision 1.52  2004/11/09 12:02:23  yosizaki
  fix allocation of wmBuf.

  Revision 1.51  2004/11/09 01:05:39  seiki_masashi
  Implemented the timeout by Null response

  Revision 1.50  2004/10/26 08:09:54  takano_makoto
  Added MB_DisconnectChild

  Revision 1.49  2004/10/19 00:55:31  sato_masaki
  Corrected a part where the WM_API return value error was not returned with MB_CALLBACK_API_ERROR

  Revision 1.48  2004/10/18 11:44:36  yosizaki
  add MB_StartParentEx, MB_EndEx.

  Revision 1.47  2004/10/15 08:50:44  yosizaki
  add start_mp_busy.

  Revision 1.46  2004/10/08 10:32:49  takano_makoto
  Corrected a problem that the changes of nameLength were not reflected in the IPL startup screen

  Revision 1.45  2004/10/08 03:04:17  takano_makoto
  Made changes to check NUL characters in addition to the updates in 1.44

  Revision 1.44  2004/10/08 02:44:46  takano_makoto
  Made changes to see nameLength of MBUserInfo with MB_Init

  Revision 1.43  2004/10/05 09:45:29  terui
  Integrated MAC address with u8-type array.

  Revision 1.42  2004/10/04 13:40:25  terui
  Integrated game group ID with u32-type.

  Revision 1.41  2004/10/03 08:17:31  ooe
  Supported changes to StartMPEx specifications. ignoreFatalError.

  Revision 1.40  2004/09/28 08:55:30  sato_masaki
  - Changed so OS_Panic is issued  when WM_STATECODE_FIFO_ERROR comes out with Indication callback. 
  - Added a size range determination using MBi_IsCommSizeValid. 

  Revision 1.39  2004/09/25 05:51:47  sato_masaki
  Merged with NitroSDK_IPL_branch 1.27.2.7.

  Revision 1.38  2004/09/25 05:43:49  sato_masaki
  Added processing to disable interrupts during API execution that can be called in the main loop 

  Revision 1.37  2004/09/22 09:41:18  sato_masaki
  IPL_branch 1.27.2.5 and merge 
  (Added a MBw_GetWLVersion function to get the WirelessLibrary version.) 

  Revision 1.36  2004/09/22 02:50:31  yosizaki
  optimize for code-size around MBi_ChildCallback().

  Revision 1.35  2004/09/22 02:31:57  yosizaki
  optimize for code-size around MB_Init().

  Revision 1.34  2004/09/21 01:39:15  sato_masaki
  Integrated the error caused by WM into MB_ERRCODE_WM_FAILURE. Got rid of MB_ERRCODE_MP_SENT_FAILURE.

  Revision 1.33  2004/09/20 12:56:17  sato_masaki
  Added a decision as to whether initialization has completed or not into MB_Init(). 

  Revision 1.32  2004/09/18 09:16:26  sato_masaki
  If the p_mbi_param->endReq flag is active, made changes so that MB_End does nothing.

  Revision 1.31  2004/09/18 03:11:25  sato_masaki
  small fix

  Revision 1.30  2004/09/18 02:58:50  sato_masaki
  bug fix

  Revision 1.29  2004/09/17 11:36:30  sato_masaki
  - add function MBw_IsStarted()
  - change MP size check (it always returns 'TRUE')

  Revision 1.28  2004/09/16 12:48:35  sato_masaki
  - Changed the function defined as MBi_*** to MB_*** in mb.h.
  - Set so that the validity of the send / receive data size is evaluated.

  Revision 1.27  2004/09/15 06:51:59  sato_masaki
  Deleted the processes collected in the WBT definition.

  Revision 1.26  2004/09/15 06:17:47  sato_masaki
  add MBi_SetParentCommSize, MBi_GetTgid functions

  Revision 1.25  2004/09/14 12:07:15  terui
  Deleted the rand function, and swapped it with a feature that would spread out the beacon interval based on MAC address.

  Revision 1.24  2004/09/14 02:55:29  sato_masaki
  Revised comments 

  Revision 1.23  2004/09/14 02:41:38  sato_masaki
  Added mpBusy to MBiParam

  Revision 1.21  2004/09/13 13:08:26  sato_masaki
  - Added the MBi_ChildPortCallback().
  - When in WM_STATECODE_CHILD_CONNECTED, made changes so that MP is not set.

  Revision 1.20  2004/09/13 02:56:23  sato_masaki
  So that it is compatible with the old specifications, newly set the tgid to the MBi_Init() that held the argument.

  Revision 1.19  2004/09/11 12:49:06  yosiokat
  - Changed the scan time configuration inside MBi_StartCommon from a fixed value of 10 to MB_SCAN_TIME_NORMAL.

  Revision 1.18  2004/09/11 11:16:10  sato_masaki
  - Assessed the validity of the work size in SDK_STATIC_ASSERT for each parent and child.
  - Split up the MB_CommWork structure into MB_CommPWork, MB_CommCWork, and MB_CommCommonWork.

  Revision 1.17  2004/09/11 07:02:08  yosiokat
  - 	Stopped splitting up the parent / child code according to the SDK_SMALL_BUILD definition, and changed so that it can be built and split up normally.
 	Set MBi_StartCommon as the section that can be shared for the MBi_StartCore process, and moved everything else to MB_StartParent and MB_StartChild.
  	Changed the callback designation for when MODE_PARENT is in MBw_SendMP from MBi_ParentCallback to p_mbi_param->callback_ptr.

  Revision 1.16  2004/09/11 05:01:26  terui
  Restored the provisional measures for the send / receive buffer size calculation macro to their original settings.

  Revision 1.15  2004/09/11 04:00:21  sato_masaki
  Set the BOOL value that indicates key sharing usage inside the WM_Calc*******() macro to TRUE.
  (A temporary measure to avoid WM_StartMPEx() errors)

  Revision 1.14  2004/09/10 12:32:47  seiki_masashi
  Made changes so that that number of send bytes of the key sharing would be hidden in the library.

  Revision 1.13  2004/09/10 07:50:15  sato_masaki
  Made changes so that in the changeScanChannel() function, ScanChannel will be selected from among the
  usable channels obtained from WM_GetAllowedChannel().
  Also, if no scannable channels exist, made changes so that MBi_CommEnd() will be called.

  Revision 1.12  2004/09/10 02:32:23  sato_masaki
  Changed the scanParam.channel value when issuing WM_StartScan().

  Revision 1.11  2004/09/09 06:49:08  sato_masaki
  bug fix about changeScanChannel()

  Revision 1.10  2004/09/09 06:29:49  yosizaki
  change WM_SetMPData to use ToPort(WM_PORT_BT, WM_PRIORITY_LOW).

  Revision 1.9  2004/09/09 02:46:53  sato_masaki
  Returned CAM_LIFE_TIME to 40.

  Revision 1.8  2004/09/09 01:33:18  sato_masaki
  Returned FRAME_LIFE_TIME to 5, and set CAM_LIFE_TIME to 2*40.

  Revision 1.7  2004/09/09 00:50:03  sato_masaki
  Set FRAME_LIFE_TIME to 10.

  Revision 1.6  2004/09/08 13:10:09  sato_masaki
  Set so that also during WM_ERRCODE_INVALID_POLLBITMAP, the MB_CALLBACK_MP_CHILD_RECV callback will return.

  Revision 1.5  2004/09/08 10:58:54  sato_masaki
  - Set a limited LIFETIME.
  - Changed the seek channels to 1, 7, and 13 when scanning.
  - Changed WM_StartMP to Ex, and set to no resend mode.

  Revision 1.4  2004/09/06 12:05:24  sato_masaki
  Deleted the comments related to StartConnect.

  Revision 1.3  2004/09/06 11:43:21  sato_masaki
  Added the TGID to the argument of the MB_Init() function.
  Added the MBw_GetGgidLo(), MBw_GetGgidHi(), and MBw_GetTgid() functions.

  Revision 1.2  2004/09/04 09:29:03  yosiokat
  Made changes so that the code of the Parent Device mode would be deleted when defining SDK_SMALL_BUILD.

  Revision 1.1  2004/09/03 07:04:36  sato_masaki
  Divided up the files by device 

  Revision 1.25  2004/09/02 09:46:49  sato_masaki
  Added 0 clear for mbc->fileinfo

  Revision 1.24  2004/08/30 06:32:46  sato_masaki
  Changed the definition WMBT to WBT

  Revision 1.23  2004/08/26 10:08:57  sato_masaki
  Added a state check for when in BeaconRecv

  Revision 1.22  2004/08/26 09:54:59  sato_masaki
  small fix

  Revision 1.21  2004/08/24 12:20:06  sato_masaki
  SSID verification provisions (temporary fix)

  Revision 1.20  2004/08/23 04:45:17  ooe
  Support for the changes to the specification of WM_StartConnect

  Revision 1.19  2004/08/19 22:55:17  yosiokat
  Halted the setting of the multiboot flag and the GGID by MB_Init, and changed so that they are set by WM_SetGameInfo when sending the beacon.

  Revision 1.18  2004/08/19 16:00:09  miya
  modified WM_SetGameInfo function

  Revision 1.17  2004/08/19 15:11:47  yosiokat
  Added the comments from the previous revision. In MB_Init, changed to p_mbi_param->parentParam->multiBootFlag= 1.

  Revision 1.16  2004/08/19 15:07:37  yosiokat
  Made revisions so that only the definition of WM_GAMEINFO_TYPE_OLD  will be set to p_mbi_param->parentParam->userName and gameName.

  Revision 1.15  2004/08/19 12:27:20  sato_masaki
  Commented out the communications ending process in the beacon indicator 

  Revision 1.14  2004/08/19 08:00:53  ikedae
  Deleted #include <string.h> 

  Revision 1.13  2004/08/19 07:51:40  sato_masaki
  Added support for the WM specification changes

  Revision 1.12  2004/08/19 07:34:16  ooe
  randomization of the beaconPeriod (provisional, for testing)

  Revision 1.11  2004/08/19 02:42:36  yosizaki
  change type of MBUserInfo.

  Revision 1.10  2004/08/18 01:25:09  miya
  small fix

  Revision 1.9  2004/08/18 00:05:14  sato_masaki
  Updates in accordance with changes to the WM_StartMP argument. 

  Revision 1.8  2004/08/16 13:02:40  sato_masaki
  Added the MBw_GetSendBufSize function.

  Revision 1.7  2004/08/12 09:20:57  yosiokat
  - Added the MBw_RestartScan, MBw_SetMaxScanTime and MBw_GetScanChannel functions.
  - Made changes so that the callback will return to the MB_Comm layer even if PARENT_NOT_FOUND while scanning.

  Revision 1.6  2004/08/10 12:11:55  sato_masaki
  Added the MBw_GetAid function.

  Revision 1.5  2004/08/09 14:56:43  yosizaki
  format all the symbol for API

  $NoKeywords: $
 *---------------------------------------------------------------------------*/


/*
 * the management data of wmDEMOlib that is in the process of being broken up 
 */

#include "mb_private.h"

/*
 * for the randomization of the beaconPeriod (rand)
 */
//#include <stdlib.h>


/*
 *  determination of whether or not the capacity is correct with the size being requested.
 */
SDK_STATIC_ASSERT(32 + sizeof(MBiParam) + 32 + sizeof(MB_CommPWork) + 32 + WM_SYSTEM_BUF_SIZE <= MB_SYSTEM_BUF_SIZE);
SDK_STATIC_ASSERT(32 + sizeof(MBiParam) + 32 + sizeof(MB_CommCWork) + 32 + WM_SYSTEM_BUF_SIZE <= MB_CHILD_SYSTEM_BUF_SIZE);


/*
 *Parent / Child   send / receive  buffer  size  calculation  macro 
 *  receive  buffer   parentMaxSize + WLHeader(48B) + WMHeader(2B)
 *  send buffer (parentMaxSize + WMHeader(2B) + (only for KeySet(36B) KS) + 31) & 0xffffffe0 ( alignment revision)
 *  15 receive buffers (childMaxSize + WLHeader(8B) + WMHeader(2B) + (KeyData(2B)(only when KeySharing)) +  overall Header(8B) + 31) & 0xffffffe0 ( alignment revision)
 */
#define WL_HEADER_LENGTH_P  48      /* the WL header length when the Parent Device receives */
#define WM_HEADER_LENGTH    2       /* WMHeader length */
#define WL_HEADER_LENGTH_T  8       /* the overall WL header length */
#define WL_HEADER_LENGTH_C  8       /* the header length for each of their Child Device data */


// macro   Child Device  receive  buffer  size  calculation

#define WM_CalcChildSendBufSize(_pInfo_)        (u16)(WM_SIZE_MP_CHILD_SEND_BUFFER(((WMGameInfo *)(&(((WMBssDesc*)(_pInfo_))->gameInfo)))->childMaxSize, FALSE))
#define WM_CalcChildRecvBufSize(_pInfo_)        (u16)(WM_SIZE_MP_CHILD_RECEIVE_BUFFER(((WMGameInfo *)(&(((WMBssDesc*)(_pInfo_))->gameInfo)))->parentMaxSize, FALSE))

// macro   Parent Device  send / receive  buffer  size  calculation
#define WM_CalcParentSendBufSize(_libParam_)    (u16)(WM_SIZE_MP_PARENT_SEND_BUFFER(((MBiParam*)(_libParam_))->parentParam.parentMaxSize, FALSE))
#define WM_CalcParentRecvBufSize(_libParam_)    (u16)(WM_SIZE_MP_PARENT_RECEIVE_BUFFER(((MBiParam*)(_libParam_))->parentParam.childMaxSize, WM_NUM_MAX_CHILD, FALSE))


/*
 * Each type of configuration value determined by the MB library.
 * We want to be on the safe side and make these changeable.
 */

/* Beacon interval (ms) default value */
#define MB_BEACON_PERIOD_DEFAULT    (200)

/*
 * The LifeTime conversion debug  switch.
 * With the following additions, we feel that we want to go in a
 *  direction so that uniform management is possible without breaking up #ifdef NO_LIFETIME.
 */
#define  NO_LIFETIME    0
#if (NO_LIFETIME == 1)
#define FRAME_LIFE_TIME 0xFFFF
#define CAM_LIFE_TIME   0xFFFF
#define MP_LIFE_TIME    0xFFFF
#else
#define FRAME_LIFE_TIME 5
#define CAM_LIFE_TIME   40
#define MP_LIFE_TIME    40
#endif

#define TABLE_NO    0xFFFF


//===========================================================
// Function prototype declaration
//===========================================================
static void MBw_ScanLock( u8* macAddr ); // Function for setting scan lock
static void MBw_ScanUnlock( void );      // Function for releasing scan lock

/*
 * Check the WM result value. Call back if error.
 */
static void check_WMAPI_errcode( u16 apiid, int errcode );
static void MBi_ParentCallback( void *arg );



/******************************************************************************/
/*  variables  */

/*
 * The parameter structure for WM_lib
 * Everything is ultimately collected here.
 */
static MBiParam *p_mbi_param;
static u16  WM_DMA_NO;

/*
 * WM system buffer
 * Originally it was the MBiParam member, 
 * but made to be independent for MB_StartParentEx() 
 */
static u8   *wmBuf;


MB_CommCommonWork *mbc = NULL;


/*  the variables for the Child Device  */
static WMscanParam scanParam ATTRIBUTE_ALIGN(32);


/******************************************************************************/
/*  function  */


/* cycle through the ScanChannel and make changes */
static BOOL changeScanChannel(WMscanParam *p)
{
    u16 channel_bmp, channel, i;
    
    /* get the channel bitmap */
    channel_bmp = WM_GetAllowedChannel();
    
    /*  returns FALSE if there is no usable channel */
    if ( channel_bmp == 0 ) {
        OS_TWarning("No Available Scan channel\n");
        return FALSE;
    }
    
    /* If there is a usable channel. */
    for ( i = 0, channel = p->channel; 
          i < 16; 
          i++, channel = (u16)(( channel == 16 ) ? 1:channel+1) )
    {
        if ( ( channel_bmp & (1 << (channel - 1)) ) == 0 )
        {
            continue;
        }
        
       /* If the detected channel is the same
               as the previous item, a different channel 
               is looked for.
                */
        if ( p->channel != channel )
        {
            p->channel = channel;
            break;
        }
    }
    
    return TRUE;

}


/*
 * Returns the converted WM resulting value with processing in progress judged as a success 
 */
static inline int conv_errcode(int errcode)
{
    return (errcode == WM_ERRCODE_OPERATING) ? WM_ERRCODE_SUCCESS : errcode;
}


/*
 * MP sendable check 
   
   After SetMP and before the callback is returned, an mpBusy flag is added to the determination elements 
   that goes up during SetMP execution so MP is not set again.
 
 */
static BOOL MBi_IsSendEnabled(void)
{
    return ( p_mbi_param->mpStarted == 1 ) && 
           ( p_mbi_param->mpBusy == 0 )    && 
           ( p_mbi_param->endReq == 0 )    && 
           ( p_mbi_param->child_bitmap != 0 );
}

static void MBi_OnInitializeDone(void)
{
    int errcode;
    /* Issue API */
    errcode = WM_SetIndCallback( MBi_ParentCallback );
    check_WMAPI_errcode( WM_APIID_INDICATION, errcode );
    errcode = WM_SetLifeTime(
        MBi_ParentCallback,TABLE_NO,
        CAM_LIFE_TIME ,FRAME_LIFE_TIME, MP_LIFE_TIME );
    check_WMAPI_errcode( WM_APIID_SET_LIFETIME, errcode );
}

/*
 * Skeleton of the parent callback
 */
static void MBi_ParentCallback( void *arg )
{
    int errcode;
    WMCallback *buf = (WMCallback*)arg;
    
    switch( buf->apiid )
    {
    case WM_APIID_INITIALIZE:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            MBi_OnInitializeDone();
        }
        break;

    case WM_APIID_SET_LIFETIME:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {   
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
#ifdef WM_GAMEINFO_TYPE_OLD
            // Sets the user and game names
            MI_DmaCopy16(WM_DMA_NO, p_mbi_param->uname, p_mbi_param->parentParam.userName, WM_SIZE_USERNAME);
            MI_DmaCopy16(WM_DMA_NO, p_mbi_param->gname, p_mbi_param->parentParam.gameName, WM_SIZE_GAMENAME);
#endif
            // Issues API
            errcode = WM_SetParentParameter( MBi_ParentCallback, &p_mbi_param->parentParam );
            check_WMAPI_errcode( WM_APIID_SET_P_PARAM, errcode );
        }
        break;

    case WM_APIID_SET_P_PARAM:
        {
            p_mbi_param->callback( MB_CALLBACK_INIT_COMPLETE, arg );
            // Error codes do not return here. 
            errcode = WM_SetBeaconIndication( MBi_ParentCallback, 1 /* 1:ON, 0:OFF */ );
            check_WMAPI_errcode( WM_APIID_SET_BEACON_IND, errcode );
        }
        break;

        // Whether to generate a Beacon Send/Recv Indication
    case WM_APIID_SET_BEACON_IND:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
            errcode = WM_StartParent( MBi_ParentCallback );
            check_WMAPI_errcode( WM_APIID_START_PARENT, errcode );
        }
        break;

    case WM_APIID_START_PARENT:
        {
            WMstartParentCallback *callback = (WMstartParentCallback*)arg;
            
            if ( callback->errcode != WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }

            switch ( callback->state )
            {
            case WM_STATECODE_PARENT_START:
                p_mbi_param->child_bitmap = 0;
                p_mbi_param->mpStarted = 0;
                break;
            case WM_STATECODE_CHILD_CONNECTED:
                p_mbi_param->child_bitmap |= ( 0x1 << callback->aid );
                p_mbi_param->callback( MB_CALLBACK_CHILD_CONNECTED, arg );

                // Starts MP if it is before the start of MP
                if ( ( p_mbi_param->mpStarted == 0 ) &&
                     ( ! mbc->start_mp_busy ) )
                {
                    mbc->start_mp_busy = TRUE;
                    errcode = WM_StartMPEx( MBi_ParentCallback, 
                        (u16*)p_mbi_param->recvBuf, p_mbi_param->recvBufSize, 
                        (u16*)p_mbi_param->sendBuf, p_mbi_param->sendBufSize, 
                        (u16)(p_mbi_param->contSend ? 0 : 1),
                         0, /* defaultRetryCount */
                         FALSE,
                         FALSE,
                         1,  /* fixFreqMode */
                         TRUE  /* ignoreFatalError */
                         );
                    check_WMAPI_errcode( WM_APIID_START_MP, errcode );

                } else {
                    // MP send permission callback
                    if( MBi_IsSendEnabled() ) {
                        p_mbi_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
                    }
                }
                break;

            case WM_STATECODE_DISCONNECTED:
                p_mbi_param->child_bitmap &= ~( 0x1 << callback->aid );
                p_mbi_param->callback( MB_CALLBACK_CHILD_DISCONNECTED, arg );
                break;

            case WM_STATECODE_BEACON_SENT:
                  // Beacon send completion notification
                p_mbi_param->callback( MB_CALLBACK_BEACON_SENT, arg );
                break;

            default:
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                break;
            }
        }
        break;

    case WM_APIID_START_MP:
        {
            // Error code is not returned here.
            WMstartMPCallback   *callback = (WMstartMPCallback*)arg;
            mbc->start_mp_busy = FALSE;
            switch( callback->state )
            {
            case WM_STATECODE_MP_START:
                // Set the flag for MP started
                p_mbi_param->mpStarted = 1;
                {
                    // MP send permission callback
//                    if( MBi_IsSendEnabled() ) {
                            p_mbi_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
//                    }
                }
                break;

            case WM_STATECODE_MPEND_IND:
                // MP receive callback
                p_mbi_param->callback( MB_CALLBACK_MP_PARENT_RECV, (void*)(callback->recvBuf) );
                break;

            default:
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                break;
            }
            break;
        }
        break;

    case WM_APIID_SET_MP_DATA:
        {
            p_mbi_param->mpBusy = 0;
            if ( buf->errcode == WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->callback( MB_CALLBACK_MP_PARENT_SENT, arg );
                p_mbi_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL ); // Allows the next transmission
            }
            else if( buf->errcode == WM_ERRCODE_SEND_QUEUE_FULL )
            {
                p_mbi_param->callback( MB_CALLBACK_SEND_QUEUE_FULL_ERR, arg );
            }
            else
            {
                p_mbi_param->callback( MB_CALLBACK_MP_PARENT_SENT_ERR, arg );
                p_mbi_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL ); // Allows the next transmission
            }
        }
        break;

    case WM_APIID_RESET:
        if ( ! mbc->is_started_ex ) 
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->endReq = 0;
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            p_mbi_param->child_bitmap = 0;
            p_mbi_param->mpStarted    = 0;
            
            errcode = WM_End( MBi_ParentCallback );
            check_WMAPI_errcode( WM_APIID_END, errcode );
            break;
        }
        else 
        {
            (void)WM_SetPortCallback( WM_PORT_BT, NULL , NULL );
            /*
             * |
             * | Fall
             * V
             */
        }
        // don't break;
    case WM_APIID_END:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_mbi_param->endReq = 0;
                p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
            p_mbi_param->mbIsStarted = 0;
            mbc->isMbInitialized = 0;
            p_mbi_param->callback( MB_CALLBACK_END_COMPLETE, arg );
        }
        break;

    case WM_APIID_DISCONNECT:
        {
            WMDisconnectCallback *callback = (WMDisconnectCallback*)arg;
            
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                return;
            }
            
            // Update the child information
            p_mbi_param->child_bitmap &= ~(callback->disconnectedBitmap);
        }
        break;

    case WM_APIID_START_KS:
        {
            // MP transmission enabled callback
            if ( MBi_IsSendEnabled() )
            {
                p_mbi_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
            }
        }
        break;

    case WM_APIID_INDICATION:
        {
            WMindCallback*  cb = (WMindCallback*)arg;
            switch(cb->state) {
            case WM_STATECODE_BEACON_RECV:  // Beacon receiving indicate
                p_mbi_param->callback( MB_CALLBACK_BEACON_RECV , arg );
                break;
            case WM_STATECODE_DISASSOCIATE: // Indicates a disconnection
                p_mbi_param->callback( MB_CALLBACK_DISASSOCIATE , arg );
                break;
            case WM_STATECODE_REASSOCIATE:  // Indicates a reconnection
                p_mbi_param->callback( MB_CALLBACK_REASSOCIATE , arg );
                break;
            case WM_STATECODE_AUTHENTICATE: // Indicates authentication confirmation
                p_mbi_param->callback( MB_CALLBACK_AUTHENTICATE , arg );
                break;
                
            case WM_STATECODE_FIFO_ERROR:
                OS_TPanic("FIFO Error\n");
                break;
            }
        }
        break;

    default:
        p_mbi_param->callback( MB_CALLBACK_ERROR, arg );
        break;
    }
}

/*
 * A skeleton for the child callback 
 */

static void MBi_ChildPortCallback( void *arg )
{
    WMPortRecvCallback* cb = (WMPortRecvCallback*)arg;

    if ( cb->errcode != WM_ERRCODE_SUCCESS )
    {
        return;
    }

    switch ( cb->state )
    {
    case WM_STATECODE_PORT_RECV:
        // Notifies of data reception
        p_mbi_param->callback( MB_CALLBACK_MP_CHILD_RECV, (void*)(arg) );
        break;
    case WM_STATECODE_CONNECTED:
        // Connection notification
        break;
    case WM_STATECODE_DISCONNECTED:
        break;
    }
}


static void MBi_ChildCallback( void *arg )
{
    WMCallback *buf = (WMCallback*)arg;
    MBiParam    * const p_param = p_mbi_param;
    int errcode;

    switch ( buf->apiid )
    {
    //---------------------------------------------------------------
    case WM_APIID_INITIALIZE:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
            p_param->callback( MB_CALLBACK_INIT_COMPLETE, arg );
            
            // Issues API
            errcode = WM_SetLifeTime( MBi_ChildCallback, TABLE_NO, CAM_LIFE_TIME, FRAME_LIFE_TIME, MP_LIFE_TIME );
            check_WMAPI_errcode( WM_APIID_SET_LIFETIME, errcode );
        }
        break;

    case WM_APIID_SET_LIFETIME:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }

            // WM_StartScan() issuance
            scanParam.scanBuf = &p_param->parentInfoBuf;
            if( scanParam.channel == 0 )
                scanParam.channel = 1;
            if(scanParam.maxChannelTime == 0) {
                scanParam.maxChannelTime = 200;
            }
            scanParam.bssid[0] = 0xff;
            scanParam.bssid[1] = 0xff;
            scanParam.bssid[2] = 0xff;
            scanParam.bssid[3] = 0xff;
            scanParam.bssid[4] = 0xff;
            scanParam.bssid[5] = 0xff;
            p_param->scanning_flag = TRUE;
            p_param->scan_channel_flag = TRUE;
            errcode = WM_StartScan( MBi_ChildCallback, &scanParam );
            check_WMAPI_errcode( WM_APIID_START_SCAN, errcode );
        }
        break;

    case WM_APIID_START_SCAN:
    {
        WMstartScanCallback *callback = (WMstartScanCallback*)arg;

        if ( callback->errcode != WM_ERRCODE_SUCCESS )
        {
            p_param->callback( MB_CALLBACK_ERROR, arg );
            return;
        }
        
        switch ( callback->state )
        {
        case WM_STATECODE_SCAN_START:
            break;

        case WM_STATECODE_PARENT_FOUND:
        // Stores parent information obtained in the Scan
            {
                WMstartScanCallback *buf = (WMstartScanCallback*)arg;
                ParentInfo  *p = &p_param->parent_info[0];

                int i;
                for( i = 0 ;  i < p_param->found_parent_count ; ++i ) {

                    if ( WM_IsBssidEqual( buf->macAddress, p[i].scan_data.macAddress ) )
                    {
                        p[i].scan_data.gameInfoLength = buf->gameInfoLength;
                        p[i].scan_data.gameInfo   = buf->gameInfo;
                        DC_InvalidateRange(p_param->parent_info[i].parentInfo, WM_BSS_DESC_SIZE);
                        MI_DmaCopy16(WM_DMA_NO, &p_param->parentInfoBuf,
                        p_param->parent_info[i].parentInfo, WM_BSS_DESC_SIZE);
                        p_param->last_found_parent_no = i;
                        goto scan_end;
                    }
                }

                if( i < MB_NUM_PARENT_INFORMATIONS ) {
                    p_param->found_parent_count = (u16)(i+1);
                    // Stores data because this is a newly found parent
                    MI_CpuCopy16(buf, &p[i].scan_data, sizeof(p[i].scan_data));
                    DC_InvalidateRange( p_param->parent_info[i].parentInfo, WM_BSS_DESC_SIZE );
                    MI_DmaCopy16( WM_DMA_NO, &p_param->parentInfoBuf,
                    p_param->parent_info[i].parentInfo, WM_BSS_DESC_SIZE);
                    p_param->last_found_parent_no = i;
                }
            }
scan_end:
            p_param->callback( MB_CALLBACK_PARENT_FOUND, arg );
            if ( ! p_param->scanning_flag )
            {
                return;
            }
            
            if ( p_param->scan_channel_flag ) 
            {
                if ( FALSE == changeScanChannel(&scanParam) )
                {
                    (void)MBi_CommEnd();
                }
            }
            errcode = WM_StartScan( MBi_ChildCallback, &scanParam );
            check_WMAPI_errcode( WM_APIID_START_SCAN, errcode );
            break;

        case WM_STATECODE_PARENT_NOT_FOUND:
            p_param->callback( MB_CALLBACK_PARENT_NOT_FOUND, arg );             // This callback is to ParentInfoLifeTimeCount
            if ( ! p_param->scanning_flag )
            {
                return;
            }
            
            if ( p_param->scan_channel_flag ) 
            {
                if ( FALSE == changeScanChannel(&scanParam) )
                {
                    (void)MBi_CommEnd();
                }
            }
            errcode = WM_StartScan( MBi_ChildCallback, &scanParam );
            check_WMAPI_errcode( WM_APIID_START_SCAN, errcode );
            break;

        default:
            p_param->callback( MB_CALLBACK_ERROR, arg );
            break;
        }
    }
    break;

    case WM_APIID_END_SCAN:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
            errcode = WM_StartConnect( MBi_ChildCallback, p_param->pInfo, NULL );
            check_WMAPI_errcode( WM_APIID_START_CONNECT, errcode );
        }
    break;

    case WM_APIID_START_CONNECT:
        {
            WMstartConnectCallback *callback = (WMstartConnectCallback*)arg;

            if ( callback->errcode != WM_ERRCODE_SUCCESS )
            {
                /* Resets the number of parents */
                p_param->found_parent_count = 0;
                // Error notification with a callback 
                p_param->callback( MB_CALLBACK_CONNECT_FAILED, arg );
                return;
            }
            
            switch( callback->state )
            {
            case WM_STATECODE_CONNECT_START:
                p_param->child_bitmap = 0;
                p_param->mpStarted = 1;
                break;

            case WM_STATECODE_CONNECTED:
                p_param->my_aid = (u16)callback->aid;
                p_param->callback( MB_CALLBACK_CONNECTED_TO_PARENT, arg );
                p_param->child_bitmap = 1;
                
                errcode = WM_SetPortCallback( WM_PORT_BT, MBi_ChildPortCallback , NULL );
                
                if ( errcode != WM_ERRCODE_SUCCESS )
                {
                    break;
                }

                errcode = WM_StartMPEx( MBi_ChildCallback, 
                                        (u16*)p_param->recvBuf, p_param->recvBufSize, 
                                        (u16*)p_param->sendBuf, p_param->sendBufSize, 
                                        (u16)(p_param->contSend ? 0 : 1),
                                         0, /* defaultRetryCount */
                                         FALSE,
                                         FALSE,
                                         1,  /* fixFreqMode */
                                         TRUE  /* ignoreFatalError */
                                       );
                check_WMAPI_errcode( WM_APIID_START_MP, errcode );
                break;

            case WM_STATECODE_DISCONNECTED:
                p_param->callback( MB_CALLBACK_DISCONNECTED_FROM_PARENT, arg );
                p_param->child_bitmap = 0;
                p_param->mpStarted = 0;
                break;

            default:
                p_param->callback( MB_CALLBACK_ERROR, arg );
                break;
            }
        }
        break;

    case WM_APIID_START_MP:
        {
            WMstartMPCallback *callback = (WMstartMPCallback*)arg;

            switch ( callback->state )
            {
            case WM_STATECODE_MP_START:
                p_param->mpStarted = 1;     // Sets the MP started flag
                {
                    // MP transmission enabled callback
                    if ( MBi_IsSendEnabled() ) 
                    {
                        p_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
                    }
                }
                break;

            case WM_STATECODE_MP_IND:
                if ( callback->errcode == WM_ERRCODE_INVALID_POLLBITMAP )
                {
//                  p_param->callback( MB_CALLBACK_MP_CHILD_RECV, (void*)(callback->recvBuf) );
                } 
                else 
                {
//                    p_param->callback( MB_CALLBACK_MP_CHILD_RECV, (void*)(callback->recvBuf) );
                }
                break;

            case WM_STATECODE_MPACK_IND:
                {
                    //p_param->callback( MB_CALLBACK_MPACK_IND, NULL );
                }
                break;
            
            default:
                p_param->callback( MB_CALLBACK_ERROR, arg );
                break;
            }
        }
        break;

    case WM_APIID_SET_MP_DATA:
        {
            p_param->mpBusy = 0;
            if ( buf->errcode == WM_ERRCODE_SUCCESS )
            {
                p_param->callback( MB_CALLBACK_MP_CHILD_SENT, arg );
            }
            else if ( buf->errcode == WM_ERRCODE_TIMEOUT )
            {
                p_param->callback( MB_CALLBACK_MP_CHILD_SENT_TIMEOUT, arg );
            }
            else
            {
                p_param->callback( MB_CALLBACK_MP_CHILD_SENT_ERR, arg );
            }
            // Allows the next transmission 
            p_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
        }
        break;

    //---------------------------------------------------------------
    case WM_APIID_RESET:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_param->endReq = 0;
                p_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            p_mbi_param->child_bitmap = 0;
            p_mbi_param->mpStarted    = 0;
            
            errcode = WM_End( MBi_ChildCallback );
            check_WMAPI_errcode( WM_APIID_END, errcode );
        }
        break;

    //---------------------------------------------------------------
    case WM_APIID_END:
        {
            if ( buf->errcode != WM_ERRCODE_SUCCESS )
            {
                p_param->endReq = 0;
                p_param->callback( MB_CALLBACK_ERROR, arg );
                return;
            }
            
            p_param->mbIsStarted = 0;
            mbc->isMbInitialized = 0;
            p_param->callback( MB_CALLBACK_END_COMPLETE, arg );
        }
        break;

    //---------------------------------------------------------------
    case WM_APIID_START_KS:
        {
            // MP transmission enable callback
            if ( MBi_IsSendEnabled() )
            {
                p_param->callback( MB_CALLBACK_MP_SEND_ENABLE, NULL );
            }
        }
        break;

    //---------------------------------------------------------------        
    case WM_APIID_INDICATION:
        {
            WMindCallback*  cb = (WMindCallback*)arg;
            switch(cb->state) {
#if 0
            case WM_STATECODE_BEACON_RECV:  // Beacon receiving indicate
                {
                    static u16 flag = 0;    // Prevents double issuance of WM_lib_End if the flow comes here twice
                    WMBeaconRecvIndCallback *callback = (WMBeaconRecvIndCallback*)arg;
                    if( (p_param->currentTgid != 0 ) 
                        && (callback->tgid != p_param->currentTgid) 
                        && (callback->wmstate == WM_STATE_MP_CHILD) )
                    {
                        if( flag == 0 )
                        {
                            flag = 1;
//                          check_WMAPI_errcode( WM_APIID_END, MBi_CommEnd() );
                        }
                    }
                    else
                    {
                        flag = 0;
                    }
                    p_param->callback( MB_CALLBACK_BEACON_RECV , arg );
                }
                break;
            case WM_STATECODE_DISASSOCIATE: // Indicates a disconnection
                p_param->callback( MB_CALLBACK_DISASSOCIATE , arg );
                break;
            case WM_STATECODE_REASSOCIATE:  // Indicates a reconnection
                p_param->callback( MB_CALLBACK_REASSOCIATE , arg );
                break;
            case WM_STATECODE_AUTHENTICATE: // Indicates authentication confirmation
                p_param->callback( MB_CALLBACK_AUTHENTICATE , arg );
                break;
#endif
                
            case WM_STATECODE_FIFO_ERROR:
                OS_TPanic("FIFO Error\n");
                break;
            }
        }
        break;
    default:
        p_param->callback( MB_CALLBACK_ERROR, arg );
        break;
    }
}


/*---------------------------------------------------------------------------*
  Name:         MbGetBeaconPeriodDispersion

  Description:  Appropriately attaches to the irregular beacon interval for each device MAC address 
                Gets the value. 

  Arguments:    None.

  Returns:      u32 -   Appropriately returns an irregular value from 0 to 19 for each device. 
 *---------------------------------------------------------------------------*/
static u32
MbGetBeaconPeriodDispersion( void )
{
    u8      mac[ 6 ];
    u32     ret;
    s32     i;

    OS_GetMacAddress( mac );
    for ( i = 0, ret = 0 ; i < 6 ; i++ )
    {
        ret += mac[ i ];
    }
    ret += OS_GetVBlankCount();
    ret *= 7;
    return ( ret % 20 );
}


/******************************************************************************/
/* Dependent on wmDEMOlib, so this is a cut-away function */


/* Initialization */
int MB_Init( void *work, const MBUserInfo *user, u32 ggid, u16 tgid, u32 dma )
{

    SDK_ASSERT ( user != NULL );
    SDK_ASSERT ( work != NULL );
    SDK_ASSERT ( (dma < 4) );
    SDK_ASSERT ( user->nameLength <= MB_USER_NAME_LENGTH );

    if ( mbc && mbc->isMbInitialized ) 
    {
        return MB_ERRCODE_INVALID_STATE;
    }
    else
    {
        MBiParam    * const p_parm =
                (MBiParam*)( ( ((u32)work) + 0x1F ) & ~0x1F );
        MB_CommCommonWork   * const p_com =
                (MB_CommCommonWork*)( ( ((u32)p_parm) + sizeof(*p_parm) + 0x1F ) & ~0x1F );
        OSIntrMode enabled;
        enabled = OS_DisableInterrupts();

        /* Initializes the DMA channel and work region */
        WM_DMA_NO = (u16)dma;
        p_mbi_param = p_parm;
        mbc = p_com;
        MI_CpuClear32(p_parm, sizeof(*p_parm));
        MI_CpuClear16(p_com, sizeof(*p_com));

        {   /* Saves the user and game names */
            int i;
            static const u16 *game = L"multiboot";
            u16 *c;
            c = (u16*)p_parm->uname;
            for( i = 0 ; i < user->nameLength ; ++i ) {
                *c++ = user->name[i];
            }
            c = (u16*)p_parm->gname;
            for( i = 0 ; i < WM_SIZE_GAMENAME ; ++i ) {
                if( *game == 0 ) {
                    break;
                }
                *c++ = *game++;
            }
            MI_CpuCopy8(user, &p_com->user, sizeof(MBUserInfo));
            if ( user->nameLength < MB_USER_NAME_LENGTH ) {
                p_com->user.name[ user->nameLength ] = 0;
            }
        }

        {
            p_parm->p_sendlen = MB_COMM_P_SENDLEN_DEFAULT;
            p_parm->p_recvlen = MB_COMM_P_RECVLEN_DEFAULT;
            
            /* Sets the parent information (gotten by the child during scanning) */
            p_parm->sendBufSize    = 0;
            p_parm->recvBufSize    = 0;

            /* Not needed? */
            p_parm->contSend     = 1;

            p_parm->recvBuf = (WMmpRecvBuf*)p_com->recvbuf;

            {
                WMParentParam    * const p_parent = &p_parm->parentParam;
                p_parent->entryFlag = 1;
                p_parent->multiBootFlag = 0;            // Here, set the multiboot flag to OFF, and set it to ON with SetGameInfo of MbBeacon
                p_parent->CS_Flag   = 1;
                p_parent->KS_Flag   = 0;
                /* Sets GGID and TGID specific to the machine */
                p_parent->ggid      = ggid;
                p_parent->tgid      = tgid;
                p_parent->beaconPeriod  = (u16)(MB_BEACON_PERIOD_DEFAULT + MbGetBeaconPeriodDispersion());
                p_parent->maxEntry  = 15;
            }
        }
    
        p_parm->mpBusy = 0;
        p_parm->mbIsStarted = 0;
        p_com->isMbInitialized = 1;

        p_com->start_mp_busy = FALSE;

        (void)OS_RestoreInterrupts(enabled);
    }

    return  MB_ERRCODE_SUCCESS;
}

#define MP_USEC_TIME_LIMIT  (5600)

static BOOL MBi_IsCommSizeValid( u16 sendSize, u16 recvSize, u16 entry_num )
{
    int usec;
    
    SDK_ASSERT( entry_num > 0 && entry_num <= 15);
    
	/* If the sendSize is outside the prescribed range, determines if the size setting is invalid  */
    if ( sendSize > MB_COMM_P_SENDLEN_MAX || sendSize < MB_COMM_P_SENDLEN_MIN )
    {
        OS_TWarning("MB Parent send buffer size is out of the range.[%3d - %3d Bytes]\n", 
                    MB_COMM_P_SENDLEN_MIN, MB_COMM_P_SENDLEN_MAX);
        return FALSE;
    }
    
	/* If the recvSize is outside the prescribed range, determines if the size setting is invalid  */
    if ( recvSize > MB_COMM_P_RECVLEN_MAX || recvSize < MB_COMM_P_RECVLEN_MIN )
    {
        OS_TWarning("MB Parent receive buffer size per child is out of the range.[%3d - %3d Bytes]\n", 
                    MB_COMM_P_RECVLEN_MIN, MB_COMM_P_RECVLEN_MAX);
        return FALSE;
    }
    
	/* Evaluates the time for one MP communication  */
    usec = 330 + 4*(sendSize + 38) + entry_num*(112 + 4*(recvSize + 32));
    
	/* If the required time exceeds 5600 milliseconds, the size setting is determined to be invalid.  */
    if ( usec >= MP_USEC_TIME_LIMIT )
    {
        OS_TWarning("These send receive sizes require lower than %4dusec\n"
                    "it exceeds %4d usec\n", MP_USEC_TIME_LIMIT, usec);
        return FALSE;
    }
    
    return TRUE;
}


BOOL MB_SetParentCommParam( u16 sendSize, u16 maxChildren )
{
    OSIntrMode enabled = OS_DisableInterrupts();
    
	/* Cannot be changed if WM is started up  */
    if ( p_mbi_param->mbIsStarted )
    {
        OS_TWarning("MB has Already started\n");

        (void)OS_RestoreInterrupts(enabled);
        return FALSE;
    }
    
	/* Evaluates the appropriateness of the sending and receiving data size  */
    if ( FALSE == MBi_IsCommSizeValid( sendSize, MB_COMM_P_RECVLEN_DEFAULT, maxChildren ) )
    {
        OS_TWarning("MP data sizes have not changed\n");
        // 
        (void)OS_RestoreInterrupts(enabled);
        return FALSE;
    }
    
	/* Sets the maximum number of people that can be connected  */
    p_mbi_param->parentParam.maxEntry = maxChildren;
    
	/* Sets the sending and receiving data size  */
    p_mbi_param->p_sendlen = sendSize;
    p_mbi_param->p_recvlen = MB_COMM_P_RECVLEN_DEFAULT;

    (void)OS_RestoreInterrupts(enabled);
    
    return TRUE;
}


BOOL MB_SetParentCommSize( u16 sendSize )
{
    OSIntrMode enabled = OS_DisableInterrupts();
    BOOL ret;
    
	/* The maximum number of people that can be connected is inherited by the current setting  */
    ret = MB_SetParentCommParam( sendSize, p_mbi_param->parentParam.maxEntry );
    
    (void)OS_RestoreInterrupts(enabled);
    
    return ret;
}

u16 MB_GetTgid(void)
{
    return p_mbi_param->parentParam.tgid;
}

/* Initialization (parent and child shared portion)  */
static int MBi_StartCommon( void )
{
    int errcode;
    
    p_mbi_param->mpStarted = 0;
    p_mbi_param->child_bitmap = 0;
    p_mbi_param->endReq = 0;
    p_mbi_param->currentTgid    = 0;
    MBw_SetMaxScanTime( MB_SCAN_TIME_NORMAL );
    
    if ( ! mbc->is_started_ex ) 
    {
        do {
            errcode = WM_Initialize(
            wmBuf, p_mbi_param->callback_ptr, WM_DMA_NO);
        } while ( errcode == WM_ERRCODE_WM_DISABLE );
        if( errcode != WM_ERRCODE_OPERATING )
        {
            OS_TWarning("WM_Initialize failed!\n");
            return MB_ERRCODE_WM_FAILURE;
        }
        else
        {
            (void)WM_SetIndCallback(p_mbi_param->callback_ptr);
            p_mbi_param->mbIsStarted = 1;
            return MB_ERRCODE_SUCCESS;
        }
    } else {
        (void)WM_SetIndCallback(p_mbi_param->callback_ptr);
        p_mbi_param->mbIsStarted = 1;
        MBi_OnInitializeDone();
        return MB_ERRCODE_SUCCESS;
    }
}


/* Shared process to set and start the parent parameter  */
static int MBi_StartParentCore(int channel)

{
    int i, ret;
    MBCommPStateCallback cb_tmp;
    OSIntrMode enabled;

    enabled = OS_DisableInterrupts();
    
    p_mbi_param->parentParam.channel = (u16)channel;
    wmBuf = (u8*)((((u32)mbc) + sizeof(MB_CommPWork) + 31) & ~31);

    /* Temporarily backs away because a Callback was already set  */
    cb_tmp = pPwork->parent_callback;
    
    /* Clears the parent specific work region  */
    MI_CpuClear16( (void*)( (u32)pPwork + sizeof(MB_CommCommonWork) ), 
                    sizeof(MB_CommPWork) - sizeof(MB_CommCommonWork) );
    MB_CommSetParentStateCallback( cb_tmp );

    /* Calculates the parameter dependent on the sending and receiving size  */
    mbc->block_size_max = MB_COMM_CALC_BLOCK_SIZE( p_mbi_param->p_sendlen );
    
    MBi_SetChildMPMaxSize( p_mbi_param->p_recvlen );
    MBi_SetParentPieceBuffer( &pPwork->req_data_buf );
    
    for ( i = 0; i < MB_MAX_CHILD; i++ )
    {
        pPwork->p_comm_state[i] = MB_COMM_PSTATE_NONE;
        pPwork->fileid_of_child[i] = -1;    /* Initializes a request FileID from the child */
    }
    pPwork->file_num                    = 0;
    
    MI_CpuClear16( &pPwork->fileinfo[0], sizeof( pPwork->fileinfo ) );
    MI_CpuClear8( &pPwork->req2child[0], sizeof( pPwork->req2child ) );
    
    p_mbi_param->mode               = MB_MODE_PARENT;
    p_mbi_param->callback           = MBi_CommParentCallback;
    p_mbi_param->callback_ptr       = MBi_ParentCallback;
    
    /* The maximum parent transmission size in bytes  */
    p_mbi_param->parentParam.parentMaxSize = p_mbi_param->p_sendlen;
    p_mbi_param->sendBufSize        =  WM_CalcParentSendBufSize( p_mbi_param );
    /* The maximum child transmission size in bytes  */
    p_mbi_param->parentParam.childMaxSize = p_mbi_param->p_recvlen;
    p_mbi_param->recvBufSize        =  WM_CalcParentRecvBufSize( p_mbi_param );
    
    OS_TPrintf("Parent sendSize : %4d\n", p_mbi_param->parentParam.parentMaxSize);
    OS_TPrintf("Parent recvSize : %4d\n", p_mbi_param->parentParam.childMaxSize);
    OS_TPrintf("Parent sendBufSize : %4d\n", p_mbi_param->sendBufSize);
    OS_TPrintf("Parent recvBufSize : %4d\n", p_mbi_param->recvBufSize);
    
    MB_InitSendGameInfoStatus();
    
    ret = MBi_StartCommon();
    
    (void)OS_RestoreInterrupts(enabled);
    
    return ret;
}

/* Set and start the parent parameter (initialize inside WM) */
int MB_StartParent(int channel)
{
    mbc->is_started_ex = FALSE;
    return  MBi_StartParentCore(channel);
}

/* Set and start the parent parameter (outside of WM had already started) */
int MB_StartParentFromIdle(int channel)
{
    mbc->is_started_ex = TRUE;
    return  MBi_StartParentCore(channel);
}

/* Set and start the child parameter */
int MB_StartChild(void)
{
    int ret;
    MBCommCStateCallbackFunc cb_tmp;
    OSIntrMode enabled;

    enabled = OS_DisableInterrupts();
    
    mbc->is_started_ex = FALSE;

    wmBuf = (u8*)((((u32)mbc) + sizeof(MB_CommCWork) + 31) & ~31);

    /* Save in temporary in case the callback was already set */
    cb_tmp = pCwork->child_callback;
    
    /* Clears the child specific work region  */
    MI_CpuClear16(  (void*)( (u32)pCwork + sizeof(MB_CommCommonWork) ), 
                    sizeof(MB_CommCWork) - sizeof(MB_CommCommonWork));
    MB_CommSetChildStateCallback( cb_tmp );
    
    pCwork->c_comm_state            = MB_COMM_CSTATE_NONE;
    
    p_mbi_param->mode               = MB_MODE_CHILD;
    p_mbi_param->callback           = MBi_CommChildCallback;
    p_mbi_param->callback_ptr       = MBi_ChildCallback;
    
    p_mbi_param->scanning_flag      = FALSE;
    p_mbi_param->scan_channel_flag  = TRUE;
    p_mbi_param->last_found_parent_no = -1;
    
    MBi_SetBeaconRecvStatusBufferDefault();
    MBi_SetScanLockFunc( MBw_ScanLock, MBw_ScanUnlock );
    MB_InitRecvGameInfoStatus();
    
    ret = MBi_StartCommon();
    
    (void)OS_RestoreInterrupts(enabled);
    
    return ret;
}


/* Wireless termination process in case the task thread ended or if it did not start up from the beginning. */
static int  MBi_CallReset(void)
{
    int errcode;
    errcode = WM_Reset( p_mbi_param->callback_ptr );
    check_WMAPI_errcode( WM_APIID_RESET, errcode );
    return conv_errcode( errcode );
}

static void MBi_OnReset(MBiTaskInfo *p_task)
{
    (void)p_task;
    (void)MBi_CallReset();
}

/* Ends communication  */
int MBi_CommEnd(void)
{
    int ret = WM_ERRCODE_FAILED;
    OSIntrMode enabled = OS_DisableInterrupts();

    if ( p_mbi_param->endReq == 0 )
    {
        p_mbi_param->scanning_flag = FALSE;
        p_mbi_param->endReq = 1;
        /* If the task thread is running, stop it and perform reset. */
        if (MBi_IsTaskAvailable()) 
        {
            MBi_EndTaskThread(MBi_OnReset);
            ret = WM_ERRCODE_SUCCESS;
        }
        /* If not, perform reset here. */
        else 
        {
            ret = MBi_CallReset();
        }
    }

    (void)OS_RestoreInterrupts(enabled);
    
    return ret;
}

void    MB_End(void)
{
    OSIntrMode enabled = OS_DisableInterrupts();

    if(mbc->is_started_ex) {
        OS_TPanic("MB_End called after MB_StartParentFromIdle! (please call MB_EndToIdle)");
    }

    (void)MBi_CommEnd();

    (void)OS_RestoreInterrupts(enabled);
}

void    MB_EndToIdle(void)
{
    OSIntrMode enabled = OS_DisableInterrupts();

    if ( !mbc->is_started_ex ) 
    {
        OS_TPanic("MB_EndToIdle called after MB_StartParent! (please call MB_End)");
    }

    (void)MBi_CommEnd();

    (void)OS_RestoreInterrupts(enabled);
}

//-------------------------------------
// Disconnect a child
//-------------------------------------
void    MB_DisconnectChild( u16 aid )
{
    if ( WM_Disconnect( MBi_ParentCallback, aid ) != WM_ERRCODE_OPERATING )
    {
        OS_TWarning("MB_DisconnectChild failed disconnect child %d\n", aid );
    }

    if ( aid == 0 || aid >= 16 )
    {
       OS_TWarning("Disconnected Illegal AID No. ---> %2d\n", aid);
        return;
    }
    
    /*  Erase the child information
        (When disconnection occurred, erase the child information regarding that AID.) */
    pPwork->childversion[aid - 1] = 0;
    MI_CpuClear8( &pPwork->childggid[aid - 1], sizeof(u32) );
    MI_CpuClear8( &pPwork->childUser[aid - 1], sizeof(MBUserInfo) );
    
    /* Clear the receive buffer  */
    MBi_ClearParentPieceBuffer( aid );
    
    pPwork->req2child[aid - 1] = MB_COMM_USER_REQ_NONE;
    
    /* In case the requested FileID was set. Clears ID with -1.  */
    if ( pPwork->fileid_of_child[aid - 1] != -1 )
    {
        u8  fileID = pPwork->fileid_of_child[aid - 1];
        u16 nowChildFlag = pPwork->fileinfo[ fileID ].gameinfo_child_bmp;
        u16 child = aid;
        
        pPwork->fileinfo[ fileID ].gameinfo_child_bmp
                                 &= ~(MB_GAMEINFO_CHILD_FLAG( child ));
        pPwork->fileinfo[ fileID ].gameinfo_changed_bmp
                                 |= MB_GAMEINFO_CHILD_FLAG( child );
        pPwork->fileid_of_child[child - 1] = -1;
        pPwork->fileinfo[ fileID ].pollbmp &= ~(0x0001 << child);
        
        MB_DEBUG_OUTPUT("Update Member (AID:%2d)\n", child );
    }
    
    /* Clears the connection information. */
    if ( pPwork->child_entry_bmp & (0x0001 << aid) )
    {
        pPwork->child_num--;
        pPwork->child_entry_bmp &= ~(0x0001 << aid);
    }
    pPwork->p_comm_state[aid - 1] = MB_COMM_PSTATE_NONE;
}


/* Use only with MbGameInfo.c  ****************************************************/

int MBw_GetLastFountParent(void)
{
    return  p_mbi_param->last_found_parent_no;
}

WMBssDesc*  MBw_GetParentBssDesc(int id)
{
    return p_mbi_param->parent_info[id].parentInfo;
}

static void MBw_ScanLock( u8* macAddr )
{
    scanParam.maxChannelTime = MB_SCAN_TIME_LOCKING;
    p_mbi_param->scan_channel_flag = FALSE;
    WM_CopyBssid( macAddr, scanParam.bssid );
}

static void MBw_ScanUnlock( void )
{
    static const u8 bss_fill[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    
    scanParam.maxChannelTime = MB_SCAN_TIME_NORMAL;
    p_mbi_param->scan_channel_flag = TRUE;
    WM_CopyBssid( bss_fill, scanParam.bssid );
}


/* Use only with MbGameInfo.c  ****************************************************/

#if 0
u16 MBw_GetMaxScanTime(void)
{
    return  scanParam.maxChannelTime;
}

void    MBw_SetScanChannelSeek(BOOL e)
{
    p_mbi_param->scan_channel_flag = e;
}

void    MBw_SetScanBss(const u8 *bss)
{
    if(!bss) {
        static const u8    bss_fill[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } ;
        bss = bss_fill;
    }
    WM_CopyBssid( bss, scanParam.bssid );
}
#endif

/* Used only with mb_comm *********************************************************/

// Set the scan time
void MBw_SetMaxScanTime(u16 time)
{
    scanParam.maxChannelTime = time;
}

static int
MBi_SetMPData( WMCallbackFunc callback , const u16* sendData , u16 sendDataSize , u16 tmptt , u16 pollbmp )
{
#pragma unused( tmptt )
    int errcode;
    errcode = WM_SetMPDataToPort( callback, sendData, sendDataSize, pollbmp, WM_PORT_BT, WM_PRIORITY_LOW );
    check_WMAPI_errcode( WM_APIID_SET_MP_DATA, errcode );
    return errcode;
}


int MBw_SendMP(const void *buf, int len, int pollbmp)
{
    int errcode;

    u16 size = (u16)len;
    u16 pollbitmap = (u16)pollbmp;
 
    // MP data cannot be sent before the MP starts or after an end request has been issued 
    if ( (p_mbi_param->mpStarted == 0) || (p_mbi_param->endReq == 1) )
    {
        return WM_ERRCODE_FAILED;
    }
    
    switch( p_mbi_param->mode )
    {
    case MB_MODE_PARENT:
        errcode = MBi_SetMPData( p_mbi_param->callback_ptr, (u16*)buf, size,         // Note: Substitute with callback_ptr because ParentCallback is linked even with mb_child if MBi_ParentCallback was used.
            (u16)((!p_mbi_param->contSend ) ? 1000 : 0), pollbitmap );
        
        if ( errcode == WM_ERRCODE_OPERATING ) 
        {
            p_mbi_param->mpBusy = 1;
        }
        
        return conv_errcode (errcode);
        
    case MB_MODE_CHILD:
        errcode = MBi_SetMPData( MBi_ChildCallback, (u16*)buf, size, 0, pollbitmap );
        
        if ( errcode == WM_ERRCODE_OPERATING ) 
        {
            p_mbi_param->mpBusy = 1;
        }
        
        return conv_errcode (errcode);
        
    default:
        return WM_ERRCODE_FAILED;
    }
}

int MBw_GetSendBufSize(void)
{
    return (int)p_mbi_param->sendBufSize;  
}

int MBw_GetRecvBufSize(void)
{
    return (int)p_mbi_param->recvBufSize;  
}

int MBw_CommConnectToParent(const WMBssDesc *bssDescp)
{
    WMgameInfo *gameInfo;
    int errcode;
    SDK_ASSERT( bssDescp != 0);

    gameInfo = (WMgameInfo *)(&(bssDescp->gameInfo));
    p_mbi_param->p_sendlen = gameInfo->parentMaxSize;
    p_mbi_param->p_recvlen = gameInfo->childMaxSize;
	/* Calculates the parameter dependent on the sending and receiving size  */
    mbc->block_size_max = MB_COMM_CALC_BLOCK_SIZE( p_mbi_param->p_sendlen );
    
    MBi_SetChildMPMaxSize( p_mbi_param->p_recvlen );
    
    OS_TPrintf( "\trecv size : %d\n", p_mbi_param->p_sendlen );
    OS_TPrintf( "\tsend size : %d\n", p_mbi_param->p_recvlen );
    OS_TPrintf( "\tblock size: %d\n", mbc->block_size_max );

    p_mbi_param->recvBufSize = (u16)WM_CalcChildRecvBufSize( bssDescp );
    p_mbi_param->sendBufSize = (u16)WM_CalcChildSendBufSize( bssDescp );
    p_mbi_param->pInfo = bssDescp;
    p_mbi_param->currentTgid = ((WMGameInfo*)&(bssDescp->gameInfo))->tgid;
    p_mbi_param->scanning_flag = FALSE;
    
    errcode = WM_EndScan( p_mbi_param->callback_ptr );
    check_WMAPI_errcode( WM_APIID_END_SCAN, errcode );
    return conv_errcode ( errcode );
}

u32 MBw_GetGgid(void)
{
  return p_mbi_param->parentParam.ggid;
}

u16 MBw_GetGgidLo(void)
{
  return (u16)( p_mbi_param->parentParam.ggid & 0x0ffff );
}

u16 MBw_GetGgidHi(void)
{
  return (u16)( p_mbi_param->parentParam.ggid >> 16 );
}

u16 MBw_GetTgid(void)
{
  return (p_mbi_param->parentParam.tgid);
}

u8 MBw_GetAttribute(void)
{
  return ((u8)(
           ((p_mbi_param->parentParam.entryFlag)? WM_ATTR_FLAG_ENTRY : 0) |    // entryFlag the least significant bit
           ((p_mbi_param->parentParam.multiBootFlag)? WM_ATTR_FLAG_MB : 0) |  // multiBootFlag the second bit
           ((p_mbi_param->parentParam.KS_Flag)? WM_ATTR_FLAG_KS : 0) |        // KS_Flag the third bit
           ((p_mbi_param->parentParam.CS_Flag)? WM_ATTR_FLAG_CS : 0)          // CS_Flag the fourth bit
           ));
}


// Restarts the scan 
int MBw_RestartScan(void)
{
    int errcode;
    
    p_mbi_param->scanning_flag = TRUE;
    
    if ( p_mbi_param->scan_channel_flag ) 
    {
        if ( FALSE == changeScanChannel(&scanParam) )
        {
            (void)MBi_CommEnd();
        }
    }
    
    errcode = WM_StartScan( MBi_ChildCallback, &scanParam );
    check_WMAPI_errcode( WM_APIID_START_SCAN, errcode );
    return conv_errcode ( errcode );
}


// Gets the scan channel
int MBw_GetScanChannel(void)
{
    return scanParam.channel;
}

// Gets its own AID 
u16 MBw_GetAid(void)
{
  return p_mbi_param->my_aid;
}

int MBw_GetParentSendlen(void)
{
    return p_mbi_param->p_sendlen;
}

int MBw_GetParentRecvlen(void)
{
    return p_mbi_param->p_recvlen;
}

BOOL MBw_IsStarted(void)
{
    return ( p_mbi_param->mbIsStarted == 1 ) ? TRUE:FALSE;
}

// Checks the WM_API return value 
static void check_WMAPI_errcode( u16 apiid, int errcode )
{
    u16 arg[2];
    
    if( errcode != WM_ERRCODE_OPERATING &&
        errcode != WM_ERRCODE_SUCCESS )
    {
        arg[0] = apiid;
        arg[1] = (u16)errcode;
        p_mbi_param->callback( MB_CALLBACK_API_ERROR, arg );
    }
}

u8 MBw_GetMaxEntry( void )
{
    return (u8)p_mbi_param->parentParam.maxEntry;
}

