1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - libraries
3   File:     mb_child.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2009-02-04#$
14   $Rev: 9966 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 
18 #include "mb_private.h"
19 
20 
21 // ----------------------------------------------------------------------------
22 // Definitions
23 
24 #define MY_ROUND(n, a)      (((u32) (n) + (a) - 1) & ~((a) - 1))
25 
26 // --- For child
27 static int MBi_CommRequestFile(u8 file_no, u32 ggid);
28 static void MBi_CommChangeChildState(int state, void *arg);
29 static void MBi_CommChangeChildStateCallbackOnly(int state, void *arg);
30 static void MBi_CommChildRecvData(void *arg);
31 static int MBi_CommChildSendData(void);
32 static void MBi_CommBeaconRecvCallback(MbBeaconMsg msg, MBGameInfoRecvList * gInfop, int index);
33 
34 // --- Miscellany
35 static BOOL checkRecvFlag(int x);
36 static void setRecvFlag(int x);
37 static u16 countRemainingblocks(void);
38 static u16 get_next_blockno(void);
39 static BOOL checkPollbmp(u16 pollbmp, u16 child_aid);
40 static void clearRecvRegion(void);
41 static void MBi_CommCallChildError(u16 errcode);
42 
43 
44 /* StartScanEx scan buffer */
45 static u8 scanBuf[WM_SIZE_SCAN_EX_BUF] ATTRIBUTE_ALIGN(32);
46 extern WMscanExParam mbiScanParam;
47 
48 
49 
50 /*  ============================================================================
51 
52     Child Functions
53 
54     ============================================================================*/
55 
56 /*---------------------------------------------------------------------------*
57   Name:         MB_CommDownloadRequest
58 
59   Description:  Sends a download request (a function that triggers the continuous operation: connect to the parent -> request file -> download).
60                 Packs the lower MB_CommDownloadRequest, and makes a connection request with the index number of the mbrs list.
61                 By remembering the index number, the parent device information can be cleared internally when the connection fails.
62 
63 
64 
65 
66   Arguments:    index: The MbBeaconRecvStatus list index number that is requested
67 
68   Returns:
69  *---------------------------------------------------------------------------*/
70 
MB_CommDownloadRequest(int index)71 int MB_CommDownloadRequest(int index)
72 {
73     const MbBeaconRecvStatus *mbrsp;   // Parent information receive status
74     const WMBssDesc *bssDescp;         // Pointer to the parent information of the connection destination
75     u8      fileNo;                    // File number to request of the connection destination
76     int     ret;
77     OSIntrMode enabled = OS_DisableInterrupts();        /* Interrupts disabled */
78 
79     mbrsp = MB_GetBeaconRecvStatus();  // Parent information receive status
80     bssDescp = &(mbrsp->list[index].bssDesc);
81     fileNo = mbrsp->list[index].gameInfo.fileNo;
82 
83     pCwork->connectTargetNo = index;   // Saves the list number of the parent to which to attempt a connection
84     pCwork->fileid = fileNo;           // Register the requested file ID in advance
85     pCwork->last_recv_seq_no = -1;     //Initialize the last received block sequence number
86 
87     // Copy bssDescription into working memory
88     MI_CpuCopy16(bssDescp, &pCwork->bssDescbuf, WM_BSS_DESC_SIZE);
89 
90     ret = MBi_CommConnectToParent((const WMBssDesc *)&pCwork->bssDescbuf);      // First, establish a connection
91     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling */
92 
93     return ret;
94 }
95 
96 /*---------------------------------------------------------------------------*
97   Name:         MBi_CommRequestFile
98 
99   Description:  Specifies a file number and issues a request.
100 
101   Arguments:    file_no
102 
103   Returns:
104  *---------------------------------------------------------------------------*/
105 
MBi_CommRequestFile(u8 file_no,u32 ggid)106 static int MBi_CommRequestFile(u8 file_no, u32 ggid)
107 {
108     int     errcode;
109     MBCommChildBlockHeader hd;
110     u8     *databuf;
111     MBCommRequestData req_data;
112 
113     /* Register the requested game's GGID, UserInfo and Version */
114     req_data.ggid = ggid;
115     MI_CpuCopy8(&pCwork->common.user, &req_data.userinfo, sizeof(MBUserInfo));
116     req_data.version = MB_IPL_VERSION;
117     req_data.fileid = file_no;
118 
119     hd.type = MB_COMM_TYPE_CHILD_FILEREQ;
120     // Copy data to the send buffer
121     hd.req_data.piece = MBi_SendRequestDataPiece(hd.req_data.data, &req_data);
122 
123     databuf = MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
124 
125     if (!databuf)
126     {
127         return MB_SENDFUNC_STATE_ERR;
128     }
129     errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, 0xFFFF, pCwork->common.sendbuf);
130     return errcode;
131 }
132 
133 /*---------------------------------------------------------------------------*
134   Name:         MB_CommSetChildStateCallback
135 
136   Description:  Child event callback settings.
137 
138   Arguments:
139 
140   Returns:
141  *---------------------------------------------------------------------------*/
142 
MB_CommSetChildStateCallback(MBCommCStateCallbackFunc callback)143 void MB_CommSetChildStateCallback(MBCommCStateCallbackFunc callback)
144 {
145     OSIntrMode enabled;
146 
147     SDK_ASSERT(pCwork != 0);
148 
149     enabled = OS_DisableInterrupts();  /* Interrupts disabled */
150 
151     pCwork->child_callback = callback;
152 
153     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling */
154 }
155 
156 /*---------------------------------------------------------------------------*
157   Name:         MB_CommGetChildState
158 
159   Description:  Gets the download state.
160 
161   Arguments:
162 
163   Returns:
164  *---------------------------------------------------------------------------*/
165 
MB_CommGetChildState(void)166 int MB_CommGetChildState(void)
167 {
168     if (pCwork)
169     {
170         return pCwork->c_comm_state;
171     }
172     return 0;
173 }
174 
175 /*---------------------------------------------------------------------------*
176   Name:         MB_GetChildProgressPercentage
177 
178   Description:  Gets the download progress percentage.
179 
180   Arguments:
181 
182   Returns:
183  *---------------------------------------------------------------------------*/
184 
MB_GetChildProgressPercentage(void)185 u16 MB_GetChildProgressPercentage(void)
186 {
187     OSIntrMode enabled;
188     u16     ret = 0;
189 
190     enabled = OS_DisableInterrupts();  /* Interrupts disabled */
191 
192     if (pCwork->total_block > 0)
193     {
194         ret = (u16)((u32)(pCwork->got_block * 100) / pCwork->total_block);
195     }
196 
197     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling */
198 
199     return ret;                        // Return 0% if the TotalBlock count is zero
200 }
201 
202 
203 /*---------------------------------------------------------------------------*
204   Name:         MB_CommStartDownload
205 
206   Description:  Starts a download.
207 
208   Arguments:
209 
210   Returns:
211  *---------------------------------------------------------------------------*/
212 
MB_CommStartDownload(void)213 BOOL MB_CommStartDownload(void)
214 {
215     OSIntrMode enabled;
216     BOOL    ret = FALSE;
217 
218     enabled = OS_DisableInterrupts();  /* Interrupts disabled */
219 
220     if (pCwork
221         && pCwork->c_comm_state == MB_COMM_CSTATE_DLINFO_ACCEPTED
222         && pCwork->user_req == MB_COMM_USER_REQ_NONE)
223     {
224 
225         pCwork->user_req = MB_COMM_USER_REQ_DL_START;
226 
227         ret = TRUE;
228     }
229 
230     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling */
231     return ret;
232 }
233 
234 
235 /*---------------------------------------------------------------------------*
236   Name:         MBi_CommChangeChildState
237 
238   Description:  Changes the child state and invokes a callback.
239 
240   Arguments:
241 
242   Returns:
243  *---------------------------------------------------------------------------*/
244 
MBi_CommChangeChildState(int state,void * arg)245 static void MBi_CommChangeChildState(int state, void *arg)
246 {
247     pCwork->c_comm_state = state;
248 
249     MBi_CommChangeChildStateCallbackOnly(state, arg);
250 
251 }
252 
253 /*---------------------------------------------------------------------------*
254   Name:         MBi_CommChangeChildStateCallbackOnly
255 
256   Description:  Perform child state notification with only a callback invocation.
257                 The internal state is not changed.
258 
259   Arguments:
260 
261   Returns:
262  *---------------------------------------------------------------------------*/
263 
MBi_CommChangeChildStateCallbackOnly(int state,void * arg)264 static void MBi_CommChangeChildStateCallbackOnly(int state, void *arg)
265 {
266     if (pCwork->child_callback)        // State-change callback
267     {
268         (*pCwork->child_callback) ((u32)state, arg);
269     }
270 
271 }
272 
273 /*---------------------------------------------------------------------------*
274   Name:         MBi_CommChildCallback
275 
276   Description:  Main body of the child callback.
277 
278   Arguments:    type:WM_TYPE event arg:callback argument
279 
280   Returns:      None.
281  *---------------------------------------------------------------------------*/
MBi_CommChildCallback(u16 type,void * arg)282 void MBi_CommChildCallback(u16 type, void *arg)
283 {
284     MB_COMM_WMEVENT_OUTPUT(type, arg);
285 
286     switch (type)
287     {
288     case MB_CALLBACK_INIT_COMPLETE:
289         /* Initialization complete */
290         MBi_CommChangeChildState(MB_COMM_CSTATE_INIT_COMPLETE, arg);
291 
292         // Specify the scan buffer when the child has finished initialization to reduce (dead strip) parent memory
293         mbiScanParam.scanBuf = (WMBssDesc*)scanBuf;
294         mbiScanParam.scanBufSize = WM_SIZE_SCAN_EX_BUF;
295         break;
296 
297     case MB_CALLBACK_PARENT_FOUND:
298         {
299             u16 *linkLevel = (u16 *)arg;
300             int     parent_no = MBi_GetLastFountParent();
301             WMBssDesc *bssDescp = MBi_GetParentBssDesc(parent_no);
302 
303             /* Discover parent devices */
304             /* Get parent game information via a beacon */
305             (void)MB_RecvGameInfoBeacon(MBi_CommBeaconRecvCallback, *linkLevel, bssDescp);
306 
307             MB_CountGameInfoLifetime(MBi_CommBeaconRecvCallback, TRUE);
308         }
309         break;
310     case MB_CALLBACK_PARENT_NOT_FOUND:
311         /* Lifetime count of parent game information */
312         MB_CountGameInfoLifetime(MBi_CommBeaconRecvCallback, FALSE);
313         break;
314 
315     case MB_CALLBACK_CONNECTED_TO_PARENT:
316         MBi_CommChangeChildState(MB_COMM_CSTATE_CONNECT, arg);
317         break;
318 
319     case MB_CALLBACK_MP_CHILD_RECV:
320         MBi_CommChildRecvData(arg);
321         break;
322 
323     case MB_CALLBACK_MP_SEND_ENABLE:
324         (void)MBi_CommChildSendData();
325         break;
326 
327     case MB_CALLBACK_END_COMPLETE:
328         /* End complete */
329 
330         /* If MBi_CommEnd() was called while in a state where a BOOT request was received */
331         if (pCwork->c_comm_state == MB_COMM_CSTATE_BOOTREQ_ACCEPTED && pCwork->boot_end_flag == 1)
332         {
333             // Set DownloadFileInfo and bssDesc in a fixed region -> use with loader
334             MI_CpuCopy16(&pCwork->dl_fileinfo,
335                          (void *)MB_DOWNLOAD_FILEINFO_ADDRESS, sizeof(MBDownloadFileInfo));
336             MI_CpuCopy16(&pCwork->bssDescbuf, (void *)MB_BSSDESC_ADDRESS, MB_BSSDESC_SIZE);
337             MBi_CommChangeChildState(MB_COMM_CSTATE_BOOT_READY, NULL);  // Boot preparation completed
338         }
339         /* In other cases (cancel) */
340         else
341         {
342             MBi_CommChangeChildState(MB_COMM_CSTATE_CANCELLED, NULL);   // Cancel
343 
344             /* Zero out PlayerNo */
345             pCwork->common.user.playerNo = 0;
346             clearRecvRegion();
347 
348             pCwork->c_comm_state = MB_COMM_CSTATE_NONE;
349         }
350 
351         break;
352 
353     case MB_CALLBACK_CONNECT_FAILED:
354         /* Connection failure */
355         /* Pass an arg of type WMstartConnectCallback in the callback arguments */
356         MBi_CommChangeChildState(MB_COMM_CSTATE_CONNECT_FAILED, arg);
357         MB_DeleteRecvGameInfo(pCwork->connectTargetNo); // Delete the game information of a parent that failed to connect
358         pCwork->connectTargetNo = 0;
359         (void)MBi_RestartScan();       // Resume scanning after callback notification
360         (void)MBi_CommEnd();
361 
362         break;
363 
364     case MB_CALLBACK_DISCONNECTED_FROM_PARENT:
365         /* Disconnect notification */
366         /* Pass an arg of type WMstartConnectCallback in the callback arguments */
367         MBi_CommChangeChildState(MB_COMM_CSTATE_DISCONNECTED_BY_PARENT, arg);
368         (void)MBi_RestartScan();       // Resume scanning after callback notification
369         (void)MBi_CommEnd();
370         break;
371 
372     case MB_CALLBACK_API_ERROR:
373         /* Error values returned when WM API was called in ARM9 */
374         {
375             u16     apiid, errcode;
376 
377             apiid = ((u16 *)arg)[0];
378             errcode = ((u16 *)arg)[1];
379 
380             switch (errcode)
381             {
382             case WM_ERRCODE_INVALID_PARAM:
383             case WM_ERRCODE_FAILED:
384             case WM_ERRCODE_WM_DISABLE:
385             case WM_ERRCODE_NO_DATASET:
386             case WM_ERRCODE_FIFO_ERROR:
387             case WM_ERRCODE_TIMEOUT:
388                 MBi_CommCallChildError(MB_ERRCODE_FATAL);
389                 break;
390             case WM_ERRCODE_OPERATING:
391             case WM_ERRCODE_ILLEGAL_STATE:
392             case WM_ERRCODE_NO_CHILD:
393             case WM_ERRCODE_OVER_MAX_ENTRY:
394             case WM_ERRCODE_NO_ENTRY:
395             case WM_ERRCODE_INVALID_POLLBITMAP:
396             case WM_ERRCODE_NO_DATA:
397             case WM_ERRCODE_SEND_QUEUE_FULL:
398             case WM_ERRCODE_SEND_FAILED:
399             default:
400                 MBi_CommCallChildError(MB_ERRCODE_WM_FAILURE);
401                 break;
402             }
403         }
404         break;
405     case MB_CALLBACK_ERROR:
406         {
407             /* Errors in callbacks returned after a WM API call */
408             WMCallback *pWmcb = (WMCallback *)arg;
409             switch (pWmcb->apiid)
410             {
411             case WM_APIID_INITIALIZE:
412             case WM_APIID_SET_LIFETIME:
413             case WM_APIID_SET_P_PARAM:
414             case WM_APIID_SET_BEACON_IND:
415             case WM_APIID_START_PARENT:
416             case WM_APIID_START_MP:
417             case WM_APIID_SET_MP_DATA:
418             case WM_APIID_START_DCF:
419             case WM_APIID_SET_DCF_DATA:
420             case WM_APIID_DISCONNECT:
421             case WM_APIID_START_KS:
422                 /* The above errors are important to WM initialization */
423                 MBi_CommCallChildError(MB_ERRCODE_FATAL);
424                 break;
425             case WM_APIID_RESET:
426             case WM_APIID_END:
427             default:
428                 /* Other errors are returned as callback errors */
429                 MBi_CommCallChildError(MB_ERRCODE_WM_FAILURE);
430                 break;
431             }
432         }
433         break;
434 
435     default:
436         break;
437     }
438 
439 #if ( CALLBACK_WM_STATE == 1 )
440     if (pCwork->child_callback)
441     {
442         (*pCwork->child_callback) ((u32)(MB_COMM_CSTATE_WM_EVENT | type), arg);
443     }
444 #endif
445 
446     if (type == MB_CALLBACK_END_COMPLETE)
447     {
448         // Release working memory
449         MI_CpuClear16(pCwork, sizeof(MB_CommCWork));
450         pCwork = NULL;
451     }
452 }
453 
454 
455 /*---------------------------------------------------------------------------*
456   Name:         MBi_CommChildRecvData
457 
458   Description:  Receives child data.
459 
460   Arguments:    arg: Pointer to callback argument
461 
462   Returns:      None.
463  *---------------------------------------------------------------------------*/
464 
MBi_CommChildRecvData(void * arg)465 static void MBi_CommChildRecvData(void *arg)
466 {
467     WMPortRecvCallback *bufp = (WMPortRecvCallback *)arg;
468     MB_CommCWork *const p_child = pCwork;
469     MBCommParentBlockHeader hd;
470     u8     *databuf;
471     u16     aid = MBi_GetAid();
472 
473     // Destroy the receive buffer cache
474 //  DC_InvalidateRange( bufp->data, MY_ROUND(bufp->length, 32) );
475 
476     databuf = MBi_SetRecvBufferFromParent(&hd, (u8 *)bufp->data);
477 
478     MB_DEBUG_OUTPUT("RECV ");
479     MB_COMM_TYPE_OUTPUT(hd.type);
480 
481     switch (hd.type)                   // State transition depending on receive block type
482     {
483     case MB_COMM_TYPE_PARENT_SENDSTART:
484         // Send start message from parent
485         if (p_child->c_comm_state == MB_COMM_CSTATE_CONNECT)
486         {
487             MB_DEBUG_OUTPUT("Allowed to request file from parent!\n");
488             MBi_CommChangeChildState(MB_COMM_CSTATE_REQ_ENABLE, NULL);
489         }
490         break;
491 
492     case MB_COMM_TYPE_PARENT_KICKREQ: // Kick message from parent
493         if (p_child->c_comm_state == MB_COMM_CSTATE_REQ_ENABLE)
494         {
495             MB_DEBUG_OUTPUT("Kicked from parent!\n");
496             MBi_CommChangeChildState(MB_COMM_CSTATE_REQ_REFUSED, NULL);
497         }
498         break;
499 
500     case MB_COMM_TYPE_PARENT_MEMBER_FULL:      // Message from parent regarding excessive number of members
501         if (p_child->c_comm_state == MB_COMM_CSTATE_REQ_ENABLE)
502         {
503             MB_DEBUG_OUTPUT("Member full!\n");
504             MBi_CommChangeChildState(MB_COMM_CSTATE_MEMBER_FULL, NULL);
505         }
506         break;
507 
508     case MB_COMM_TYPE_PARENT_DL_FILEINFO:
509         // Receive MbDownloadFileInfoHeader
510         if (p_child->c_comm_state == MB_COMM_CSTATE_REQ_ENABLE)
511         {
512 
513             // Stores MbDownloadFileInfoHeader in an exclusive buffer
514             MI_CpuCopy8(databuf, &p_child->dl_fileinfo, sizeof(MBDownloadFileInfo));
515 
516             MB_DEBUG_OUTPUT("Download File Info has received (Total block num = %d)\n",
517                             p_child->total_block);
518             if (!MBi_MakeBlockInfoTable(&p_child->blockinfo_table,
519                                         (MbDownloadFileInfoHeader *) & p_child->dl_fileinfo))
520             {
521                 /* The received DownloadFileInfo was invalid */
522                 MBi_CommCallChildError(MB_ERRCODE_INVALID_DLFILEINFO);
523                 OS_TWarning("The received DownloadFileInfo is illegal.\n");
524                 return;
525             }
526 
527             /* Assign PlayerNo */
528             p_child->common.user.playerNo = aid;
529 
530             // Store the total block count
531             p_child->total_block = MBi_get_blocknum(&p_child->blockinfo_table);
532 
533             /* Pass the received MbDownloadFileInfo as an argument */
534             MBi_CommChangeChildState(MB_COMM_CSTATE_DLINFO_ACCEPTED, (void *)&p_child->dl_fileinfo);
535         }
536 
537         break;
538 
539     case MB_COMM_TYPE_PARENT_DATA:
540         /* Receive block data */
541         if (p_child->c_comm_state == MB_COMM_CSTATE_DLINFO_ACCEPTED
542             && p_child->user_req == MB_COMM_USER_REQ_DL_START)
543         {
544             MBi_CommChangeChildState(MB_COMM_CSTATE_RECV_PROCEED, NULL);
545             p_child->user_req = MB_COMM_USER_REQ_NONE;
546             /* Once the state is changed, received data can be immediately obtained */
547         }
548 
549         if (p_child->c_comm_state == MB_COMM_CSTATE_RECV_PROCEED)
550         {
551             u16     block_num;
552             MB_BlockInfo bi;
553 
554             // Processing only when MB_COMM_TYPE_DATA
555             block_num = p_child->total_block;
556 
557             if (block_num == 0 || block_num >= MB_MAX_BLOCK)
558             {
559 
560                 MBi_CommCallChildError(MB_ERRCODE_INVALID_BLOCK_NUM);
561 
562                 OS_TWarning("Illegal Number of Block! [%d]\n", block_num);
563                 return;
564             }
565 
566             /* Evaluation relating to the block number */
567             if (hd.seqno < 0 ||
568                 hd.seqno >= block_num ||
569                 MBi_get_blockinfo(&bi, &p_child->blockinfo_table, hd.seqno,
570                                   &p_child->dl_fileinfo.header) == FALSE)
571             {
572                 /* Block number is invalid */
573                 MBi_CommCallChildError(MB_ERRCODE_INVALID_BLOCK_NO);
574                 OS_TWarning("The illegal block No.[%d] has been received! (maxnum %d)\n",
575                             hd.seqno, block_num);
576                 goto CheckRemainBlock;
577             }
578 
579             if (hd.fid != p_child->fileid)
580             {
581                 /* FileID is different from the requested one */
582                 MBi_CommCallChildError(MB_ERRCODE_INVALID_FILE);
583                 OS_TWarning("Received File ID [%d] differs from what was requested!\n", hd.fid);
584                 goto CheckRemainBlock;
585             }
586 
587             if (!MBi_IsAbleToRecv(bi.segment_no, bi.child_address, bi.size))
588             {
589                 /* Receive address is invalid */
590                 MBi_CommCallChildError(MB_ERRCODE_INVALID_RECV_ADDR);
591                 OS_TWarning("The receive address of Block No.%d is illegal. [%08x - %08x]\n",
592                             hd.seqno, bi.child_address, bi.child_address + bi.size);
593                 goto CheckRemainBlock;
594             }
595 
596             /* Copy to the specified address after checking the receive address */
597             if (checkRecvFlag(hd.seqno) == FALSE)
598             {
599                 MB_DEBUG_OUTPUT("DATA : BLOCK(%d)/REMAIN(%d), Recv address[%x] size[%x]\n",
600                                 hd.seqno, countRemainingblocks(), bi.child_address, bi.size);
601                 MI_CpuCopy8(databuf, (void *)bi.child_address, bi.size);
602                 p_child->got_block++;
603                 setRecvFlag(hd.seqno);
604             }
605 
606           CheckRemainBlock:
607             /* Have all blocks been received? */
608             if (0 == countRemainingblocks())
609             {
610                 MBi_CommChangeChildState(MB_COMM_CSTATE_RECV_COMPLETE, NULL);   // Receive complete
611             }
612         }
613         break;
614 
615     case MB_COMM_TYPE_PARENT_BOOTREQ:
616         if (p_child->c_comm_state == MB_COMM_CSTATE_RECV_COMPLETE)
617         {
618             MBi_CommChangeChildState(MB_COMM_CSTATE_BOOTREQ_ACCEPTED, NULL);
619         }
620         else if (p_child->c_comm_state == MB_COMM_CSTATE_BOOTREQ_ACCEPTED)
621         {
622             p_child->boot_end_flag = 1;
623             (void)MBi_CommEnd();       // End communication
624         }
625         break;
626     default:
627         break;
628     }
629     return;
630 }
631 
632 /*---------------------------------------------------------------------------*
633   Name:         MBi_CommChildSendData
634 
635   Description:  Sends child data.
636 
637   Arguments:    None.
638 
639   Returns:      None.
640  *---------------------------------------------------------------------------*/
641 
MBi_CommChildSendData(void)642 static int MBi_CommChildSendData(void)
643 {
644     u16     block_num = pCwork->total_block;
645     MBCommChildBlockHeader hd;
646     int     errcode = 0;
647     u16     pollbmp = 0xffff;
648 
649     switch (pCwork->c_comm_state)
650     {
651     default:
652         // Send DUMMY MP to establish MP communication
653         hd.type = MB_COMM_TYPE_DUMMY;
654         (void)MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
655         errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, pollbmp, pCwork->common.sendbuf);
656         break;
657 
658     case MB_COMM_CSTATE_REQ_ENABLE:
659         {
660             const MbBeaconRecvStatus *mbrsp = MB_GetBeaconRecvStatus();
661             // Send a FileRequest
662             errcode = MBi_CommRequestFile(pCwork->fileid,
663                                           mbrsp->list[pCwork->connectTargetNo].gameInfo.ggid);
664             MB_DEBUG_OUTPUT("Requested File (errcode:%d)\n", errcode);
665             // MP is set with RequestFile
666         }
667         break;
668 
669     case MB_COMM_CSTATE_DLINFO_ACCEPTED:
670         // DownloadInfo reception message
671         hd.type = MB_COMM_TYPE_CHILD_ACCEPT_FILEINFO;
672         (void)MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
673         errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, pollbmp, pCwork->common.sendbuf);
674         break;
675 
676     case MB_COMM_CSTATE_RECV_PROCEED:
677         // Block transfer continuation message
678         MI_CpuClear8(&hd, sizeof(MBCommChildBlockHeader));
679         hd.type = MB_COMM_TYPE_CHILD_CONTINUE;
680         hd.data.req = get_next_blockno();
681         hd.data.reserved[0] = (u8)(0x00ff & pCwork->got_block); // Lo
682         hd.data.reserved[1] = (u8)((0xff00 & pCwork->got_block) >> 8);  // Hi
683         (void)MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
684         errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, pollbmp, pCwork->common.sendbuf);
685         break;
686 
687     case MB_COMM_CSTATE_RECV_COMPLETE:
688         // Block transfer stop message (send continues until BOOTREQ comes from parent)
689         hd.type = MB_COMM_TYPE_CHILD_STOPREQ;
690         (void)MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
691         errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, pollbmp, pCwork->common.sendbuf);
692         break;
693 
694     case MB_COMM_CSTATE_BOOTREQ_ACCEPTED:
695         hd.type = MB_COMM_TYPE_CHILD_BOOTREQ_ACCEPTED;
696         (void)MBi_MakeChildSendBuffer(&hd, (u8 *)pCwork->common.sendbuf);
697         errcode = MBi_BlockHeaderEnd(MB_COMM_CHILD_HEADER_SIZE, pollbmp, pCwork->common.sendbuf);
698         break;
699     }
700 
701     return errcode;
702 }
703 
704 /*---------------------------------------------------------------------------*
705   Name:         MBi_CommBeaconRecvCallback
706 
707   Description:  Child beacon receive callback
708 
709   Arguments:    msg: Beacon receive message
710                 gInfop: Parent game information
711                 index: Beacon index
712 
713   Returns:      None.
714  *---------------------------------------------------------------------------*/
715 
MBi_CommBeaconRecvCallback(MbBeaconMsg msg,MBGameInfoRecvList * gInfop,int index)716 static void MBi_CommBeaconRecvCallback(MbBeaconMsg msg, MBGameInfoRecvList * gInfop, int index)
717 {
718 #pragma unused(index)
719     void* arg = (gInfop == NULL)? NULL : (void *)&gInfop->gameInfo;
720 
721     switch (msg)
722     {
723     case MB_BC_MSG_GINFO_VALIDATED:
724         MBi_CommChangeChildStateCallbackOnly(MB_COMM_CSTATE_GAMEINFO_VALIDATED,
725                                              arg);
726         MB_DEBUG_OUTPUT("Parent Info Enable\n");
727         break;
728     case MB_BC_MSG_GINFO_INVALIDATED:
729         MBi_CommChangeChildStateCallbackOnly(MB_COMM_CSTATE_GAMEINFO_INVALIDATED,
730                                              arg);
731         break;
732     case MB_BC_MSG_GINFO_LOST:
733         MBi_CommChangeChildStateCallbackOnly(MB_COMM_CSTATE_GAMEINFO_LOST,
734                                              arg);
735         break;
736     case MB_BC_MSG_GINFO_LIST_FULL:
737         MBi_CommChangeChildStateCallbackOnly(MB_COMM_CSTATE_GAMEINFO_LIST_FULL,
738                                              arg);
739         break;
740     }
741 }
742 
743 /*---------------------------------------------------------------------------*
744   Name:         MB_ReadMultiBootParentBssDesc
745 
746   Description:  Set up WMBssDesc structure information
747                 with MB_GetMultiBootParentBssDesc() data,
748                 in order to use by WM_StartConnect().
749 
750   Arguments:    p_desc:            Pointer to destination WMBssDesc
751                 parent_max_size:   Max packet length of parent in MP-protocol
752                                     (must be equal to parent's WMParentParam!)
753                 child_max_size:    Max packet length of child in MP-protocol
754                                     (must be equal to parent's WMParentParam!)
755                 ks_flag:           If use key-sharing mode, TRUE
756                                     (must be equal to parent's WMParentParam!)
757                 cs_flag:           If use continuous mode, TRUE
758                                     (must be equal to parent's WMParentParam!)
759 
760   Returns:      None.
761  *---------------------------------------------------------------------------*/
MB_ReadMultiBootParentBssDesc(WMBssDesc * p_desc,u16 parent_max_size,u16 child_max_size,BOOL ks_flag,BOOL cs_flag)762 void MB_ReadMultiBootParentBssDesc(WMBssDesc *p_desc,
763                                    u16 parent_max_size, u16 child_max_size, BOOL ks_flag,
764                                    BOOL cs_flag)
765 {
766     const MBParentBssDesc *parentInfo = MB_GetMultiBootParentBssDesc();
767     SDK_NULL_ASSERT(parentInfo);
768     MI_CpuCopy8(parentInfo, p_desc, sizeof(MBParentBssDesc));
769 
770     p_desc->gameInfoLength = 0x10;
771     p_desc->gameInfo.magicNumber = 0x0001;
772     p_desc->gameInfo.ver = 0;
773     p_desc->gameInfo.ggid =
774         (u32)(*(const u16 *)(&p_desc->ssid[0]) | (*(const u16 *)(&p_desc->ssid[2]) << 16));
775     p_desc->gameInfo.tgid = *(const u16 *)(&p_desc->ssid[4]);
776     p_desc->gameInfo.userGameInfoLength = 0;
777     p_desc->gameInfo.parentMaxSize = parent_max_size;
778     p_desc->gameInfo.childMaxSize = child_max_size;
779     MI_WriteByte(&p_desc->gameInfo.attribute,
780                  (u8)((ks_flag ? WM_ATTR_FLAG_KS : 0) |
781                       (cs_flag ? WM_ATTR_FLAG_CS : 0) | WM_ATTR_FLAG_ENTRY));
782 }
783 
784 
785 /*  ============================================================================
786 
787     Miscellaneous functions
788 
789     ============================================================================*/
790 
checkRecvFlag(int x)791 static BOOL checkRecvFlag(int x)
792 {
793     int     pos = (x >> 3);
794     int     bit = (x & 0x7);
795 
796     SDK_ASSERT(x < MB_MAX_BLOCK);
797 
798     if (pCwork->recvflag[pos] & (1 << bit))
799     {
800         return TRUE;
801     }
802     return FALSE;
803 }
804 
setRecvFlag(int x)805 static void setRecvFlag(int x)
806 {
807     int     pos = (x >> 3);
808     int     bit = (x & 0x7);
809 
810     SDK_ASSERT(x < MB_MAX_BLOCK);
811 
812     pCwork->recvflag[pos] |= (1 << bit);
813 
814     pCwork->last_recv_seq_no = x;
815 }
816 
817 
countRemainingblocks(void)818 static u16 countRemainingblocks(void)
819 {
820     return (u16)(pCwork->total_block - pCwork->got_block);
821 }
822 
get_next_blockno(void)823 static u16 get_next_blockno(void)
824 {
825     int     req;
826     int     search_count = 0;
827     req = pCwork->last_recv_seq_no;
828     req++;
829 
830     while (1)
831     {
832         if (req < 0 || req >= pCwork->total_block)
833         {
834             req = 0;
835         }
836         else if (checkRecvFlag(req))
837         {
838             req++;
839         }
840         else
841         {
842             return (u16)req;
843         }
844 
845         if (pCwork->last_recv_seq_no == req)
846         {
847             return (u16)(pCwork->total_block);
848         }
849         search_count++;
850 
851         if (search_count > 1000)
852         {
853             pCwork->last_recv_seq_no = req;
854             return (u16)req;
855         }
856     }
857 }
858 
859 // Check whether the child AID bit that was specified in pollbmp is enabled or not
checkPollbmp(u16 pollbmp,u16 child_aid)860 static BOOL checkPollbmp(u16 pollbmp, u16 child_aid)
861 {
862     if (pollbmp & (u16)(1 << child_aid))
863     {
864         return TRUE;
865     }
866     return FALSE;
867 }
868 
869 /* Clear the reception region */
clearRecvRegion(void)870 static void clearRecvRegion(void)
871 {
872     /* For anything other than FINALROM, the downloadable region is not cleared */
873 #ifdef SDK_FINALROM
874     /* Clear the ARM9 loadable region */
875     MI_CpuClearFast((void *)MB_LOAD_AREA_LO, MB_LOAD_MAX_SIZE);
876     /* Clear the ARM7 load buffer address region */
877     MI_CpuClearFast((void *)MB_ARM7_STATIC_RECV_BUFFER, MB_ARM7_STATIC_RECV_BUFFER_SIZE);
878     /* Clear the MBbssDesc and MBDownloadFileInfo regions */
879     MI_CpuClear16((void *)MB_BSSDESC_ADDRESS,
880                   MB_DOWNLOAD_FILEINFO_ADDRESS + MB_DOWNLOAD_FILEINFO_SIZE - MB_BSSDESC_ADDRESS);
881     /* Clear the ROM Header region */
882     MI_CpuClear16((void *)HW_ROM_HEADER_BUF, ROM_HEADER_SIZE_FULL);
883 #endif
884 
885 }
886 
887 
MBi_CommCallChildError(u16 errcode)888 static void MBi_CommCallChildError(u16 errcode)
889 {
890     MBErrorStatus e_stat;
891     e_stat.errcode = errcode;
892 
893     MBi_CommChangeChildStateCallbackOnly(MB_COMM_CSTATE_ERROR, &e_stat);
894 
895 }
896