1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - libraries
3   File:     mb_parent.c
4 
5   Copyright 2007-2009 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-06-11#$
14   $Rev: 10742 $
15   $Author: yosizaki $
16  *---------------------------------------------------------------------------*/
17 
18 #include "mb_private.h"
19 
20 // ----------------------------------------------------------------------------
21 // Definitions
22 
23 #define MB_SEND_THRESHOLD                       2       // Send up to 2 blocks ahead during a send
24 
25 // ----------------------------------------------------------------------------
26 // Variables
27 
28 /* Bit set indicating the file ID for which a transfer request was received from the child device in the latest MP */
29 static int any_recv_bitmap = 0;
30 
31 // ----------------------------------------------------------------------------
32 // Static Function Prototypes
33 
34 // --- For parent
35 static void MBi_CommChangeParentState(u16 child, int state, void *arg);
36 static void MBi_CommChangeParentStateCallbackOnly(u16 child, int state, void *arg);
37 static void MBi_CommParentRecvDataPerChild(void *arg, u16 child);
38 static void MBi_CommParentRecvData(void *arg);
39 static int MBi_CommParentSendMsg(u8 type, u16 pollbmp);
40 static int MBi_CommParentSendDLFileInfo(void);
41 static int MBi_CommParentSendBlock(void);
42 static int MBi_CommParentSendData(void);
43 static void MBi_calc_sendblock(u8 file_id);
44 static u16 MBi_calc_nextsendblock(u16 next_block, u16 next_block_req);
45 
46 // --- Miscellany
47 static inline u16 max(u16 a, u16 b);
48 static BOOL IsChildAidValid(u16 child_aid);
49 static void MBi_CommCallParentError(u16 aid, u16 errcode);
50 
51 /* ============================================================================
52 
53     Parent Functions
54 
55     ============================================================================*/
56 
57 /*---------------------------------------------------------------------------*
58   Name:         MB_CommSetParentStateCallback
59 
60   Description:  Sets the parent event callback.
61 
62   Arguments:    callback: Callback function to specify
63 
64   Returns:      None.
65  *---------------------------------------------------------------------------*/
66 
MB_CommSetParentStateCallback(MBCommPStateCallback callback)67 void MB_CommSetParentStateCallback(MBCommPStateCallback callback)
68 {
69     OSIntrMode enabled;
70 
71     SDK_ASSERT(pPwork != 0);
72 
73     enabled = OS_DisableInterrupts();  /* Interrupts prohibited */
74 
75     pPwork->parent_callback = callback;
76 
77     (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
78 }
79 
80 /*---------------------------------------------------------------------------*
81   Name:         MB_CommGetParentState
82 
83   Description:  Gets the parent device state for each child device.
84 
85   Arguments:    child_aid (handled between 1 and 15 to match the WM AID expression format)
86 
87   Returns:
88  *---------------------------------------------------------------------------*/
89 
MB_CommGetParentState(u16 child_aid)90 int MB_CommGetParentState(u16 child_aid)
91 {
92 
93     if (pPwork && IsChildAidValid(child_aid))
94     {
95         return pPwork->p_comm_state[child_aid - 1];
96     }
97     return 0;
98 }
99 
100 
101 /*---------------------------------------------------------------------------*
102   Name:         MB_CommGetChildUser
103 
104   Description:  Gets the user information for a connected child device.
105 
106   Arguments:    child (handled between 1 and 15 to match the WM AID expression format)
107 
108   Returns:      MbUser structure.
109  *---------------------------------------------------------------------------*/
110 
MB_CommGetChildUser(u16 child_aid)111 const MBUserInfo *MB_CommGetChildUser(u16 child_aid)
112 {
113     OSIntrMode enabled = OS_DisableInterrupts();        /* Interrupts prohibited */
114 
115     if (pPwork && IsChildAidValid(child_aid))
116     {
117         MI_CpuCopy8(&pPwork->childUser[child_aid - 1], &pPwork->childUserBuf, sizeof(MBUserInfo));
118         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
119         return &pPwork->childUserBuf;
120     }
121     (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
122     return NULL;
123 }
124 
125 /*---------------------------------------------------------------------------*
126   Name:         MB_CommGetChildrenNumber
127 
128   Description:  Gets the number of connected children.
129 
130   Arguments:
131 
132   Returns:      Number of children.
133  *---------------------------------------------------------------------------*/
134 
MB_CommGetChildrenNumber(void)135 u8 MB_CommGetChildrenNumber(void)
136 {
137     if (pPwork)
138     {
139         return pPwork->child_num;
140     }
141     return 0;
142 }
143 
144 /*---------------------------------------------------------------------------*
145   Name:         MB_GetGameEntryBitmap
146 
147   Description:  Gets the AID bitmap entered for the GameRegistry being distributed.
148 
149 
150   Arguments:    game_req: Pointer to the target GameRegistry
151 
152   Returns:      Bitmap of AIDs entered in the specified GameRegistry
153                 (Parent AID: 0, Child AID: 1-15)
154                 If a game is not in distribution, the return value is 0.
155                 (If a game is being distributed, parent AID:0 is always included in the entry members.)
156 
157  *---------------------------------------------------------------------------*/
158 
MB_GetGameEntryBitmap(const MBGameRegistry * game_reg)159 u16 MB_GetGameEntryBitmap(const MBGameRegistry *game_reg)
160 {
161     int     i;
162     for (i = 0; i < MB_MAX_FILE; i++)
163     {
164         if ((pPwork->fileinfo[i].active) && ((u32)pPwork->fileinfo[i].game_reg == (u32)game_reg))
165         {
166             return pPwork->fileinfo[i].gameinfo_child_bmp;
167         }
168     }
169     return 0;
170 }
171 
172 
173 /*---------------------------------------------------------------------------*
174   Name:         MB_CommIsBootable
175 
176   Description:  Determines whether a boot is possible.
177 
178   Arguments:    child_aid: AID of target child
179 
180   Returns:      Yes: TRUE; no: FALSE.
181  *---------------------------------------------------------------------------*/
182 
MB_CommIsBootable(u16 child_aid)183 BOOL MB_CommIsBootable(u16 child_aid)
184 {
185     SDK_ASSERT(pPwork != NULL);
186 
187     if (pPwork && IsChildAidValid(child_aid))
188     {
189         /* Return TRUE for a child that has completed transmission */
190         if (pPwork->p_comm_state[child_aid - 1] == MB_COMM_PSTATE_SEND_COMPLETE)
191         {
192             return TRUE;
193         }
194     }
195     return FALSE;
196 }
197 
198 
199 /*---------------------------------------------------------------------------*
200   Name:         MB_CommResponseRequest
201 
202   Description:  Specifies a response to a connect request from a child.
203 
204   Arguments:    None.
205 
206   Returns:      Success = TRUE, failure = FALSE.
207  *---------------------------------------------------------------------------*/
208 
MB_CommResponseRequest(u16 child_aid,MBCommResponseRequestType ack)209 BOOL MB_CommResponseRequest(u16 child_aid, MBCommResponseRequestType ack)
210 {
211     u16     req;
212     int     state;
213     OSIntrMode enabled;
214 
215     SDK_ASSERT(pPwork != NULL);
216 
217     enabled = OS_DisableInterrupts();  /* Interrupts prohibited */
218 
219     switch (ack)
220     {
221     case MB_COMM_RESPONSE_REQUEST_KICK:
222         state = MB_COMM_PSTATE_REQUESTED;
223         req = MB_COMM_USER_REQ_KICK;
224         break;
225     case MB_COMM_RESPONSE_REQUEST_ACCEPT:
226         state = MB_COMM_PSTATE_REQUESTED;
227         req = MB_COMM_USER_REQ_ACCEPT;
228         break;
229 
230     case MB_COMM_RESPONSE_REQUEST_DOWNLOAD:
231         state = MB_COMM_PSTATE_WAIT_TO_SEND;
232         req = MB_COMM_USER_REQ_SEND_START;
233         break;
234 
235     case MB_COMM_RESPONSE_REQUEST_BOOT:
236         state = MB_COMM_PSTATE_SEND_COMPLETE;
237         req = MB_COMM_USER_REQ_BOOT;
238         break;
239     default:
240         (void)OS_RestoreInterrupts(enabled);    /* Remove interrupt prohibition */
241         return FALSE;
242     }
243 
244     if (pPwork && IsChildAidValid(child_aid))
245     {
246         if (pPwork->p_comm_state[child_aid - 1] == state)
247         {
248             pPwork->req2child[child_aid - 1] = req;
249             (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
250             return TRUE;
251         }
252     }
253 
254     (void)OS_RestoreInterrupts(enabled);        /* Remove interrupt prohibition */
255 
256     return FALSE;
257 }
258 
259 
260 /*---------------------------------------------------------------------------*
261   Name:         MBi_CommChangeParentState
262 
263   Description:  Changes the parent device state.
264 
265   Arguments:    child (handled between 1 and 15 to match the WM AID expression format; 0 indicates the parent device)
266                 state
267 
268   Returns:
269  *---------------------------------------------------------------------------*/
270 
MBi_CommChangeParentState(u16 child,int state,void * arg)271 static void MBi_CommChangeParentState(u16 child, int state, void *arg)
272 {
273     SDK_ASSERT(pPwork && child >= 0 && child <= WM_NUM_MAX_CHILD);
274 
275     /* If the child's number is specified, change its state */
276     if (IsChildAidValid(child))
277     {
278         pPwork->p_comm_state[child - 1] = state;
279     }
280 
281     MBi_CommChangeParentStateCallbackOnly(child, state, arg);
282 
283 }
284 
285 /*---------------------------------------------------------------------------*
286   Name:         MBi_CommChangeParentStateCallbackOnly
287 
288   Description:  Perform child state notification with only a callback invocation.
289                 The internal state is not changed.
290 
291   Arguments:
292 
293   Returns:
294  *---------------------------------------------------------------------------*/
295 
MBi_CommChangeParentStateCallbackOnly(u16 child,int state,void * arg)296 static void MBi_CommChangeParentStateCallbackOnly(u16 child, int state, void *arg)
297 {
298     if (pPwork->parent_callback)       // State-change callback
299     {
300         (*pPwork->parent_callback) (child, (u32)state, arg);
301     }
302 }
303 
304 /*---------------------------------------------------------------------------*
305   Name:         MBi_CommParentCallback
306 
307   Description:  Main body of the parent callback.
308 
309   Arguments:    type: WM_TYPE event arg:callback argument
310 
311   Returns:      None.
312  *---------------------------------------------------------------------------*/
313 
MBi_CommParentCallback(u16 type,void * arg)314 void MBi_CommParentCallback(u16 type, void *arg)
315 {
316     MB_COMM_WMEVENT_OUTPUT(type, arg);
317 
318     switch (type)
319     {
320     case MB_CALLBACK_INIT_COMPLETE:
321         /* Initialization complete */
322         /* Pass an arg of type WMStartParentCallback to the callback's arguments */
323         MBi_CommChangeParentState(0, MB_COMM_PSTATE_INIT_COMPLETE, arg);
324         break;
325 
326     case MB_CALLBACK_END_COMPLETE:
327         /* End complete */
328         // Execute at the end of the function
329 
330         break;
331 
332     case MB_CALLBACK_CHILD_CONNECTED:
333         {
334             WMstartParentCallback *sparg = (WMstartParentCallback *)arg;
335 
336             /* Ignore if the AID is 0 (parent device) */
337             if (sparg->aid == 0)
338                 break;
339 
340             if (sparg->aid >= 16)
341             {
342                 OS_TWarning("Connected Illegal AID No. ---> %2d\n", sparg->aid);
343                 break;
344             }
345 
346             MB_DEBUG_OUTPUT("child %d connected to get bootimage!\n", sparg->aid);
347 
348             /* Pass an arg of type WMStartParentCallback to the callback's arguments */
349             MBi_CommChangeParentState(sparg->aid, MB_COMM_PSTATE_CONNECTED, arg);
350         }
351         break;
352 
353     case MB_CALLBACK_CHILD_DISCONNECTED:
354         {
355             WMstartParentCallback *sparg = (WMstartParentCallback *)arg;
356 
357             /* Ignore if the AID is 0 (parent device) */
358             if (sparg->aid == 0)
359                 break;
360 
361             if (sparg->aid >= 16)
362             {
363                 OS_TWarning("Disconnected Illegal AID No. ---> %2d\n", sparg->aid);
364                 break;
365             }
366 
367             MB_DEBUG_OUTPUT("child %d disconnected \n", sparg->aid);
368 
369             /* Delete child information.
370                (If disconnected, delete child information relating to that AID) */
371             pPwork->childversion[sparg->aid - 1] = 0;
372             MI_CpuClear8(&pPwork->childggid[sparg->aid - 1], sizeof(u32));
373             MI_CpuClear8(&pPwork->childUser[sparg->aid - 1], sizeof(MBUserInfo));
374 
375             /* Clear the receive buffer */
376             MBi_ClearParentPieceBuffer(sparg->aid);
377 
378             pPwork->req2child[sparg->aid - 1] = MB_COMM_USER_REQ_NONE;
379 
380             /* When the requested FileID has been set. Clear the ID to -1 */
381             if (pPwork->fileid_of_child[sparg->aid - 1] != -1)
382             {
383                 u8      fileID = (u8)pPwork->fileid_of_child[sparg->aid - 1];
384                 u16     nowChildFlag = pPwork->fileinfo[fileID].gameinfo_child_bmp;
385                 u16     child = sparg->aid;
386 
387                 pPwork->fileinfo[fileID].gameinfo_child_bmp &= ~(MB_GAMEINFO_CHILD_FLAG(child));
388                 pPwork->fileinfo[fileID].gameinfo_changed_bmp |= MB_GAMEINFO_CHILD_FLAG(child);
389                 pPwork->fileid_of_child[child - 1] = -1;
390                 pPwork->fileinfo[fileID].pollbmp &= ~(0x0001 << (child));
391 
392                 MB_DEBUG_OUTPUT("Update Member (AID:%2d)\n", child);
393             }
394 
395             /* Clear the connection information */
396             if (pPwork->child_entry_bmp & (0x0001 << (sparg->aid)))
397             {
398                 pPwork->child_num--;
399                 pPwork->child_entry_bmp &= ~(0x0001 << (sparg->aid));
400             }
401 
402             /* If disconnected at MB_COMM_PSTATE_BOOT_REQUEST, it is assumed that communication ended because a boot was in progress. A notification of the MB_COMM_PSTATE_BOOT_STARTABLE status is sent
403                 */
404             if (pPwork->p_comm_state[sparg->aid - 1] == MB_COMM_PSTATE_BOOT_REQUEST)
405             {
406                 MBi_CommChangeParentState(sparg->aid, MB_COMM_PSTATE_BOOT_STARTABLE, NULL);
407             }
408 
409             /* Return an arg of type WMStartParentCallback to the callback's arguments */
410             MBi_CommChangeParentState(sparg->aid, MB_COMM_PSTATE_DISCONNECTED, arg);
411             pPwork->p_comm_state[sparg->aid - 1] = MB_COMM_PSTATE_NONE;
412         }
413         break;
414 
415     case MB_CALLBACK_MP_PARENT_RECV:
416         MBi_CommParentRecvData(arg);
417         break;
418 
419     case MB_CALLBACK_MP_SEND_ENABLE:
420         (void)MBi_CommParentSendData();
421         break;
422 
423     case MB_CALLBACK_BEACON_SENT:
424         {
425             u8      i;
426             /* For each game, update the GameInfo member information */
427             for (i = 0; i < MB_MAX_FILE; i++)
428             {
429                 /* When the registered file is active, and the change flags of the game's entry members are set, update the GameInfo member information
430 
431                     */
432                 if (pPwork->fileinfo[i].active && pPwork->fileinfo[i].gameinfo_changed_bmp)
433                 {
434                     MB_UpdateGameInfoMember(&pPwork->fileinfo[i].game_info,
435                                             &pPwork->childUser[0],
436                                             pPwork->fileinfo[i].gameinfo_child_bmp,
437                                             pPwork->fileinfo[i].gameinfo_changed_bmp);
438                     /* After the update, clear the part of the bmp that changed */
439                     pPwork->fileinfo[i].gameinfo_changed_bmp = 0;
440                 }
441             }
442         }
443         /* Place GameInfo in a beacon and send */
444         MB_SendGameInfoBeacon(MBi_GetGgid(), MBi_GetTgid(), MBi_GetAttribute());
445         break;
446 
447     case MB_CALLBACK_API_ERROR:
448         /* Error values returned when WM API was called in ARM9 */
449         {
450             u16     apiid, errcode;
451 
452             apiid = ((u16 *)arg)[0];
453             errcode = ((u16 *)arg)[1];
454 
455             switch (errcode)
456             {
457             case WM_ERRCODE_INVALID_PARAM:
458             case WM_ERRCODE_FAILED:
459             case WM_ERRCODE_WM_DISABLE:
460             case WM_ERRCODE_NO_DATASET:
461             case WM_ERRCODE_FIFO_ERROR:
462             case WM_ERRCODE_TIMEOUT:
463                 MBi_CommCallParentError(0, MB_ERRCODE_FATAL);
464                 break;
465             case WM_ERRCODE_OPERATING:
466             case WM_ERRCODE_ILLEGAL_STATE:
467             case WM_ERRCODE_NO_CHILD:
468             case WM_ERRCODE_OVER_MAX_ENTRY:
469             case WM_ERRCODE_NO_ENTRY:
470             case WM_ERRCODE_INVALID_POLLBITMAP:
471             case WM_ERRCODE_NO_DATA:
472             case WM_ERRCODE_SEND_QUEUE_FULL:
473             case WM_ERRCODE_SEND_FAILED:
474             default:
475                 MBi_CommCallParentError(0, MB_ERRCODE_WM_FAILURE);
476                 break;
477             }
478         }
479         break;
480     case MB_CALLBACK_ERROR:
481         {
482             /* Errors in callbacks returned after a WM API call */
483             WMCallback *pWmcb = (WMCallback *)arg;
484             switch (pWmcb->apiid)
485             {
486             case WM_APIID_INITIALIZE:
487             case WM_APIID_SET_LIFETIME:
488             case WM_APIID_SET_P_PARAM:
489             case WM_APIID_SET_BEACON_IND:
490             case WM_APIID_START_PARENT:
491             case WM_APIID_START_MP:
492             case WM_APIID_SET_MP_DATA:
493             case WM_APIID_START_DCF:
494             case WM_APIID_SET_DCF_DATA:
495             case WM_APIID_DISCONNECT:
496             case WM_APIID_START_KS:
497                 /* The above errors are important to WM initialization */
498                 MBi_CommCallParentError(0, MB_ERRCODE_FATAL);
499                 break;
500             case WM_APIID_RESET:
501             case WM_APIID_END:
502             default:
503                 /* Other errors are returned as callback errors */
504                 MBi_CommCallParentError(0, MB_ERRCODE_WM_FAILURE);
505                 break;
506             }
507         }
508         break;
509 
510     }
511 
512 
513 #if ( CALLBACK_WM_STATE == 1 )
514     MBi_CommChangeParentState(0, (u32)(MB_COMM_PSTATE_WM_EVENT | type), arg);
515 #endif
516 
517     if (type == MB_CALLBACK_END_COMPLETE)
518     {
519         MBCommPStateCallback tmpCb = pPwork->parent_callback;
520 
521         /* Deallocate working memory */
522         MI_CpuClearFast(pPwork, sizeof(MB_CommPWork));
523         pPwork = NULL;
524         if (tmpCb)                     // State-change callback
525         {
526             (*tmpCb) (0, MB_COMM_PSTATE_END, NULL);
527         }
528     }
529 }
530 
531 
532 /*---------------------------------------------------------------------------*
533   Name:         MBi_CommParentRecvDataPerChild
534 
535   Description:  Processes the received data for each child.
536 
537   Arguments:    arg: pointer to callback argument, child: child AID
538 
539   Returns:      None.
540  *---------------------------------------------------------------------------*/
541 
MBi_CommParentRecvDataPerChild(void * arg,u16 child)542 static void MBi_CommParentRecvDataPerChild(void *arg, u16 child)
543 {
544     MBCommChildBlockHeader hd;
545     int     state;
546     u8     *p_data;
547 
548     // The range of a child is from 1 to 15
549     if (child == 0 || child > WM_NUM_MAX_CHILD)
550     {
551         return;
552     }
553 
554     p_data = MBi_SetRecvBufferFromChild((u8 *)&((WMMpRecvData *)arg)->cdata[0], &hd, child);
555 
556     state = pPwork->p_comm_state[child - 1];
557 
558     MB_DEBUG_OUTPUT("RECV (CHILD:%2d)", child);
559     MB_COMM_TYPE_OUTPUT(hd.type);
560 
561     switch (hd.type)                   // Processing for each data type
562     {
563     case MB_COMM_TYPE_CHILD_FILEREQ:
564 
565         if (p_data != NULL)
566         {
567             // Only accept when MB_COMM_PSTATE_CONNECTED
568             if (state == MB_COMM_PSTATE_CONNECTED)
569             {
570                 MBCommRequestData req_data;
571                 // Do not move to the next state until all of the child's request data is present
572                 MI_CpuCopy8(p_data, &req_data, MB_COMM_REQ_DATA_SIZE);
573                 pPwork->childggid[child - 1] = req_data.ggid;
574                 pPwork->childversion[child - 1] = req_data.version;
575                 MB_DEBUG_OUTPUT("Child [%2d] MB_IPL_VERSION : %04x\n", child, req_data.version);
576                 MI_CpuCopy8(&req_data.userinfo, &pPwork->childUser[child - 1], sizeof(MBUserInfo));
577                 pPwork->childUser[child - 1].playerNo = child;
578                 /* Pass the received MBCommRequestData to the callback arguments */
579                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_REQUESTED, &req_data.userinfo);
580             }
581 
582             if (state == MB_COMM_PSTATE_REQUESTED)
583             {
584                 u8      i, entry_num = 0;
585                 u8      fileid = ((MBCommRequestData *)p_data)->fileid;
586 
587                 /* Kick if an inactive fileNo is requested, the fileid is invalid, or the GGID of the fileNo does not match the requested GGID
588 
589                    */
590                 if (fileid >= MB_MAX_FILE
591                     || pPwork->fileinfo[fileid].active == 0
592                     || pPwork->childggid[child - 1] != pPwork->fileinfo[fileid].game_reg->ggid)
593                 {
594                     pPwork->req2child[child - 1] = MB_COMM_USER_REQ_KICK;
595                 }
596                 else
597                 {
598                     /* Kick if the set number of people was exceeded */
599                     for (i = 0; i < WM_NUM_MAX_CHILD + 1; i++)
600                     {
601                         if (pPwork->fileinfo[fileid].gameinfo_child_bmp & (0x0001 << i))
602                         {
603                             entry_num++;
604                         }
605                     }
606 
607                     if (entry_num >= pPwork->fileinfo[fileid].game_reg->maxPlayerNum)
608                     {
609                         MB_DEBUG_OUTPUT("Member full (AID:%2d)\n", child);
610                         /* Forcibly cancel the request */
611                         pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
612                         MBi_CommChangeParentState(child, MB_COMM_PSTATE_MEMBER_FULL, NULL);
613                         break;
614                     }
615                 }
616 
617                 switch (pPwork->req2child[child - 1])
618                 {
619                 case MB_COMM_USER_REQ_ACCEPT:
620                     {
621 
622                         if (0 == (pPwork->child_entry_bmp & (0x0001 << (child))))
623                         {
624                             pPwork->child_num++;
625                             pPwork->child_entry_bmp |= (0x0001 << (child));
626                             pPwork->fileid_of_child[child - 1] = (s8)fileid;
627 
628                             pPwork->fileinfo[fileid].gameinfo_child_bmp |=
629                                 MB_GAMEINFO_CHILD_FLAG(child);
630                             pPwork->fileinfo[fileid].gameinfo_changed_bmp |=
631                                 MB_GAMEINFO_CHILD_FLAG(child);
632                             MB_DEBUG_OUTPUT("Update Member (AID:%2d)\n", child);
633                             pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
634 
635                             MBi_CommChangeParentState(child, MB_COMM_PSTATE_REQ_ACCEPTED, NULL);
636                         }
637                     }
638                     break;
639 
640                 case MB_COMM_USER_REQ_KICK:
641                     MB_DEBUG_OUTPUT("Kick (AID:%2d)\n", child);
642                     pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
643                     MBi_CommChangeParentState(child, MB_COMM_PSTATE_KICKED, NULL);
644                     break;
645                 }
646             }
647         }
648         break;
649 
650     case MB_COMM_TYPE_CHILD_ACCEPT_FILEINFO:
651 
652         /* When MB_COMM_PSTATE_REQ_ACCEPTED, only transition to MB_COMM_PSTATE_WAIT_TO_SEND */
653         if (state == MB_COMM_PSTATE_REQ_ACCEPTED)
654         {
655             MBi_CommChangeParentState(child, MB_COMM_PSTATE_WAIT_TO_SEND, NULL);
656         }
657 
658         /* When MB_COMM_PSTATE_WAIT_TO_SEND, add to pollbitmap for the requested file and shift to MB_COMM_PSTATE_SEND_PROCEED
659 
660             */
661         else if (state == MB_COMM_PSTATE_WAIT_TO_SEND)
662         {
663             // If the SendStart trigger was on, transition to the block send state
664             if (pPwork->req2child[child - 1] == MB_COMM_USER_REQ_SEND_START)
665             {
666                 u8      fid = (u8)pPwork->fileid_of_child[child - 1];
667                 pPwork->fileinfo[fid].pollbmp |= (0x0001 << (child));
668                 pPwork->fileinfo[fid].currentb = 0;
669 
670                 pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
671                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_SEND_PROCEED, NULL);
672             }
673         }
674         break;
675 
676     case MB_COMM_TYPE_CHILD_CONTINUE:
677         if (state == MB_COMM_PSTATE_SEND_PROCEED)
678         {
679             u8      fileid = (u8)pPwork->fileid_of_child[child - 1];
680 
681             if (fileid == (u8)-1)
682                 break;
683 
684             // Of the nextSend's that come from multiple children, choose the largest one as the send target
685             SDK_ASSERT(fileid < MB_MAX_FILE);
686             SDK_ASSERT(pPwork->fileinfo[fileid].pollbmp);
687 
688             pPwork->fileinfo[fileid].nextb =
689                 MBi_calc_nextsendblock(pPwork->fileinfo[fileid].nextb, hd.data.req);
690             any_recv_bitmap |= (1 << fileid);
691         }
692         break;
693 
694     case MB_COMM_TYPE_CHILD_STOPREQ:
695         if (state == MB_COMM_PSTATE_SEND_PROCEED)
696         {
697             u8      fileid = (u8)pPwork->fileid_of_child[child - 1];
698 
699             if (fileid == (u8)-1)
700                 break;
701 
702             SDK_ASSERT(fileid < MB_MAX_FILE);
703 
704             pPwork->fileinfo[fileid].pollbmp &= ~(0x0001 << (child));
705 
706             MBi_CommChangeParentState(child, MB_COMM_PSTATE_SEND_COMPLETE, NULL);       // Send completed
707         }
708         else if (state == MB_COMM_PSTATE_SEND_COMPLETE)
709         {
710             if (pPwork->req2child[child - 1] == MB_COMM_USER_REQ_BOOT)
711             {
712                 pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
713                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_BOOT_REQUEST, NULL);
714                 break;
715             }
716         }
717         break;
718 
719     case MB_COMM_TYPE_CHILD_BOOTREQ_ACCEPTED:
720         if (state == MB_COMM_PSTATE_BOOT_REQUEST)
721         {
722             /* BOOTREQ_ACCEPTED from a child is not used for state transitions */
723             break;
724         }
725 
726         break;
727 
728     default:
729         break;
730     }
731 
732 }
733 
734 /*---------------------------------------------------------------------------*
735   Name:         MBi_CommParentRecvData
736 
737   Description:  Receives parent data.
738 
739   Arguments:    arg: Pointer to callback argument
740 
741   Returns:      None.
742  *---------------------------------------------------------------------------*/
743 
MBi_CommParentRecvData(void * arg)744 static void MBi_CommParentRecvData(void *arg)
745 {
746     // The argument arg contains a pointer to the receive buffer
747     WMmpRecvHeader *mpHeader = (WMmpRecvHeader *)arg;
748 
749     u16     i;
750     WMmpRecvData *datap;
751 
752     // Initialize at this point in order to evaluate the total with MBi_CommParentRecvDataPerChild
753     for (i = 0; i < MB_MAX_FILE; i++)
754     {
755         if (pPwork->fileinfo[i].active)
756             pPwork->fileinfo[i].nextb = 0;
757     }
758     any_recv_bitmap = 0;
759 
760     // Display the data received from each child
761     for (i = 1; i <= WM_NUM_MAX_CHILD; ++i)
762     {
763         // Get the starting address of the data for the child with AID==i
764         datap = WM_ReadMPData(mpHeader, (u16)i);
765         // If data exists for the child with AID==i
766         if (datap != NULL)
767         {
768             // Display the received data
769             if (datap->length == 0xffff)
770             {
771             }
772             else if (datap->length != 0)
773             {
774                 // Processing for each child's data
775                 MBi_CommParentRecvDataPerChild(datap, i);
776             }
777         }
778     }
779 }
780 
781 
782 /*---------------------------------------------------------------------------*
783   Name:         MBi_CommParentSendMsg
784 
785   Description:  Sends a message from the parent.
786 
787   Arguments:    pollbmp
788 
789   Returns:      None.
790  *---------------------------------------------------------------------------*/
791 
MBi_CommParentSendMsg(u8 type,u16 pollbmp)792 static int MBi_CommParentSendMsg(u8 type, u16 pollbmp)
793 {
794     MBCommParentBlockHeader hd;
795 
796     /* Notify that transmission has begun (without arguments) */
797     hd.type = type;
798 
799     (void)MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
800     return MBi_BlockHeaderEnd(MB_COMM_PARENT_HEADER_SIZE, pollbmp, pPwork->common.sendbuf);
801 }
802 
803 /*---------------------------------------------------------------------------*
804   Name:         MBi_CommParentSendDLFileInfo
805 
806   Description:  Sends DownloadFileInfo from the parent.
807 
808   Arguments:    None.
809 
810   Returns:      None.
811  *---------------------------------------------------------------------------*/
812 
MBi_CommParentSendDLFileInfo(void)813 static int MBi_CommParentSendDLFileInfo(void)
814 {
815     MBCommParentBlockHeader hd;
816     u8     *databuf = ((u8 *)pPwork->common.sendbuf) + MB_COMM_PARENT_HEADER_SIZE;
817     u16     child;
818     u8      i, fid;
819     s8      send_candidate_fid = -1;
820     static s8 prev_fid = -1;
821     u8      file_req_num[MB_MAX_FILE];
822     u16     pollbmp = 0;
823 
824     MI_CpuClear8(&file_req_num[0], sizeof(u8) * MB_MAX_FILE);
825 
826     // Aggregate the FileID's that children are requesting
827     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
828     {
829         if (pPwork->p_comm_state[child - 1] == MB_COMM_PSTATE_REQ_ACCEPTED)
830         {
831             // Count only children that are MB_COMM_PSTATE_REQ_ACCEPTED targets
832             ++(file_req_num[pPwork->fileid_of_child[child - 1]]);
833         }
834     }
835 
836     fid = (u8)prev_fid;
837 
838     for (i = 0; i < MB_MAX_FILE; i++)  // Determine the send file ID
839     {
840 #if 1
841         fid = (u8)((fid + 1) % MB_MAX_FILE);
842 
843         if (pPwork->fileinfo[fid].active && file_req_num[fid] > 0)
844         {
845             send_candidate_fid = (s8)fid;
846             break;
847         }
848 
849 #else
850         if (pPwork->fileinfo[i].active)
851         {
852             if (file_req_num[i] > 0)
853             {
854 
855                 /*
856                    Majority decision
857                    (In this case, when multiple child devices are waiting for different files to start downloading, the transmission of DownloadFileInfo becomes locked to the file with more devices.
858 
859                    Although there are no problems with multiboot operations, because the state of the child application will no longer advance from MB_COMM_CSTATE_REQ_ENABLE, after a download decision from the parent, entry processing for those children will continue (should this be dealt with?)
860 
861 
862 
863                  */
864 
865                 if (send_candidate_fid == -1 || file_req_num[i] > file_req_num[send_candidate_fid])
866                 {
867                     send_candidate_fid = i;
868                 }
869 
870             }
871         }
872 #endif
873 
874     }
875 
876     if (send_candidate_fid == -1)
877         return MB_SENDFUNC_STATE_ERR;
878 
879     prev_fid = send_candidate_fid;
880 
881     // Poll bitmap settings (only children that are requesting the same file number as the one to be sent)
882     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
883     {
884         if (pPwork->p_comm_state[child - 1] == MB_COMM_PSTATE_REQ_ACCEPTED
885             && pPwork->fileid_of_child[child - 1] == send_candidate_fid)
886         {
887             pollbmp |= (1 << child);
888         }
889     }
890 
891     MB_DEBUG_OUTPUT("DLinfo No %2d Pollbmp %04x\n", send_candidate_fid, pollbmp);
892 
893     // Send the FileInfo of the last child that received the request
894     hd.type = MB_COMM_TYPE_PARENT_DL_FILEINFO;
895     hd.fid = send_candidate_fid;
896 
897     databuf = MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
898     if (databuf)
899     {
900         // Copy data to the send buffer
901         MI_CpuCopy8(&pPwork->fileinfo[send_candidate_fid].dl_fileinfo,
902                     databuf, sizeof(MBDownloadFileInfo));
903     }
904 
905     return MBi_BlockHeaderEnd(sizeof(MBDownloadFileInfo) + MB_COMM_PARENT_HEADER_SIZE, pollbmp,
906                               pPwork->common.sendbuf);
907 }
908 
909 /*---------------------------------------------------------------------------*
910   Name:         MBi_ReloadCache
911 
912   Description:  Reload data in the destroyed cache that is specified.
913 
914   Arguments:    p_task: Task that stores MBiCacheInfo in param[0]
915 
916   Returns:      None.
917  *---------------------------------------------------------------------------*/
MBi_ReloadCache(MBiTaskInfo * p_task)918 static void MBi_ReloadCache(MBiTaskInfo * p_task)
919 {
920     MBiCacheInfo *const p_info = (MBiCacheInfo *) p_task->param[0];
921     MBiCacheList *const p_list = (MBiCacheList *) p_task->param[1];
922     FSFile  file[1];
923     FSArchive   *arc;
924     u32          length = p_info->len;
925     arc = FS_FindArchive(p_list->arc_name, (int)p_list->arc_name_len);
926     if (!arc)
927     {
928         arc = p_list->arc_pointer;
929     }
930 #ifdef SDK_TWL
931     // When running in TWL mode, avoid reading outside the ROM
932     if (OS_IsRunOnTwl() && (arc == FS_FindArchive("rom", 3)))
933     {
934         const CARDRomHeaderTWL *header = (const CARDRomHeaderTWL *)CARD_GetOwnRomHeaderTWL();
935         // Note that in some cases the distributed program may be maintained as a TWL-exclusive file
936         const u32   boundary_ntr = header->digest_area_ntr.offset + header->digest_area_ntr.length;
937         const u32   boundary_ltd = header->digest_area_ltd.offset + header->digest_area_ltd.length;
938         if ((p_info->src < boundary_ntr) && (p_info->src + length > boundary_ntr))
939         {
940             length = boundary_ntr - p_info->src;
941         }
942         else if ((p_info->src < boundary_ltd) && (p_info->src + length > boundary_ltd))
943         {
944             length = boundary_ltd - p_info->src;
945         }
946     }
947 #endif
948 
949     FS_InitFile(file);
950 
951     /* Specify the target archive for the MB_ReadSegment function */
952     if (FS_OpenFileDirect(file,
953                           arc,
954                           p_info->src, p_info->src + length, (u32)~0))
955     {
956         if (FS_ReadFile(file, p_info->ptr, (int)length) == length)
957         {
958             /* It is acceptable to set to READY here */
959             p_info->state = MB_CACHE_STATE_READY;
960         }
961         (void)FS_CloseFile(file);
962     }
963 
964     /* File loading failed, due to causes such as card removal */
965     if (p_info->state != MB_CACHE_STATE_READY)
966     {
967         /*
968          * Leaving this page in MB_CACHE_STATE_BUSY will result in a leak, decreasing the page count of the entire cache. Therefore, always keep this page in MB_CACHE_STATE_READY, with the same address settings as the ROM header (0x00000000-) at index[0].
969          *
970          *
971          *
972          * Even if indeterminate content is included in the buffer, this will ensure that the content will never be referenced, and will become the target of the next page fault.
973          *
974          * (However, in actuality, this should not be called twice when the card is removed)
975          */
976         p_info->src = 0;
977         p_info->state = MB_CACHE_STATE_READY;
978     }
979 }
980 
981 /*---------------------------------------------------------------------------*
982   Name:         MBi_CommParentSendBlock
983 
984   Description:  Sends Block data from the parent.
985 
986   Arguments:    None.
987 
988   Returns:      None.
989  *---------------------------------------------------------------------------*/
990 
MBi_CommParentSendBlock(void)991 static int MBi_CommParentSendBlock(void)
992 {
993     MBCommParentBlockHeader hd;
994     u8     *databuf;
995     u8      i;
996     MB_BlockInfo bi;
997 
998     // Determine the file number to send
999     if (pPwork->file_num == 0)
1000         return MB_SENDFUNC_STATE_ERR;
1001 
1002     // The block transfer main body starts from here
1003 
1004     // Determine the file that is the send target
1005     for (i = 0; i < MB_MAX_FILE; i++)
1006     {
1007         pPwork->cur_fileid = (u8)((pPwork->cur_fileid + 1) % MB_MAX_FILE);
1008         if (pPwork->fileinfo[pPwork->cur_fileid].active
1009             && pPwork->fileinfo[pPwork->cur_fileid].pollbmp)
1010         {
1011             MB_DEBUG_OUTPUT("Send File ID:%2d\n", pPwork->cur_fileid);
1012             break;
1013         }
1014     }
1015     if (i == MB_MAX_FILE)              // No file to send
1016     {
1017         return MB_SENDFUNC_STATE_ERR;
1018     }
1019 
1020     /* Calculate the number of blocks to send for the file being sent */
1021     MBi_calc_sendblock(pPwork->cur_fileid);
1022 
1023     // Get the block information
1024     if (!MBi_get_blockinfo(&bi,
1025                            &pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table,
1026                            pPwork->fileinfo[pPwork->cur_fileid].currentb,
1027                            &pPwork->fileinfo[pPwork->cur_fileid].dl_fileinfo.header))
1028     {
1029         return MB_SENDFUNC_STATE_ERR;
1030     }
1031     /* Prepare the packets to send */
1032     hd.type = MB_COMM_TYPE_PARENT_DATA;
1033     hd.fid = pPwork->cur_fileid;
1034     hd.seqno = pPwork->fileinfo[pPwork->cur_fileid].currentb;
1035     databuf = MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
1036 
1037     /* Access though the cache (will always hit if there is enough memory) */
1038     {
1039         /* Calculate the CARD address from the block offset */
1040         u32     card_addr = (u32)(bi.offset -
1041                                   pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table.
1042                                   seg_src_offset[bi.segment_no] +
1043                                   pPwork->fileinfo[pPwork->cur_fileid].card_mapping[bi.segment_no]);
1044         /* Cache read for the specified CARD address */
1045         MBiCacheList *const pl = pPwork->fileinfo[pPwork->cur_fileid].cache_list;
1046         if (!MBi_ReadFromCache(pl, card_addr, databuf, bi.size))
1047         {
1048             /* If a cache miss, send a reload request to the task thread */
1049             MBiTaskInfo *const p_task = &pPwork->cur_task;
1050             if (!MBi_IsTaskBusy(p_task))
1051             {
1052                 /* Lifetime value to avoid continuous page faults */
1053                 if (pl->lifetime)
1054                 {
1055                     --pl->lifetime;
1056                 }
1057                 else
1058                 {
1059                     /*
1060                      * Destroy the cache with the newest address.
1061                      * We will continue to test the operation of this part later.
1062                      */
1063                     MBiCacheInfo *pi = pl->list;
1064                     MBiCacheInfo *trg = NULL;
1065                     int     i;
1066                     for (i = 0; i < MB_CACHE_INFO_MAX; ++i)
1067                     {
1068                         if (pi[i].state == MB_CACHE_STATE_READY)
1069                         {
1070                             if (!trg || (trg->src > pi[i].src))
1071                                 trg = &pi[i];
1072                         }
1073                     }
1074                     if (!trg)
1075                     {
1076                         OS_TPanic("cache-list is invalid! (all the pages are locked)");
1077                     }
1078                     pl->lifetime = 2;
1079                     trg->state = MB_CACHE_STATE_BUSY;
1080                     trg->src = (card_addr & ~31);
1081                     p_task->param[0] = (u32)trg;        /* MBiCacheInfo* */
1082                     p_task->param[1] = (u32)pl; /* MBiCacheList* */
1083                     MBi_SetTask(p_task, MBi_ReloadCache, NULL, 4);
1084                 }
1085             }
1086             return MB_SENDFUNC_STATE_ERR;
1087         }
1088     }
1089 
1090     return MBi_BlockHeaderEnd((int)(bi.size + MB_COMM_PARENT_HEADER_SIZE),
1091                               pPwork->fileinfo[pPwork->cur_fileid].pollbmp, pPwork->common.sendbuf);
1092 }
1093 
1094 /*---------------------------------------------------------------------------*
1095   Name:         MBi_CommParentSendData
1096 
1097   Description:  Sends parent data.
1098 
1099   Arguments:    None.
1100 
1101   Returns:      None.
1102  *---------------------------------------------------------------------------*/
1103 
MBi_CommParentSendData(void)1104 static int MBi_CommParentSendData(void)
1105 {
1106     struct bitmap
1107     {
1108         u16     connected;
1109         u16     req;
1110         u16     kick;
1111         u16     boot;
1112         u16     mem_full;
1113     };
1114     struct bitmap bmp;
1115     u16     child;
1116     int     errcode;
1117 
1118     MI_CpuClear16(&bmp, sizeof(struct bitmap));
1119 
1120     // Evaluate the parent status of each child
1121     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
1122     {
1123 
1124         switch (pPwork->p_comm_state[child - 1])
1125         {
1126         case MB_COMM_PSTATE_CONNECTED:
1127             bmp.connected |= (1 << child);
1128             break;
1129 
1130         case MB_COMM_PSTATE_REQ_ACCEPTED:
1131             bmp.req |= (1 << child);
1132             break;
1133 
1134         case MB_COMM_PSTATE_KICKED:
1135             bmp.kick |= (1 << child);
1136             break;
1137 
1138         case MB_COMM_PSTATE_SEND_PROCEED:
1139             break;
1140 
1141         case MB_COMM_PSTATE_BOOT_REQUEST:
1142             bmp.boot |= (1 << child);
1143             break;
1144 
1145         case MB_COMM_PSTATE_MEMBER_FULL:
1146             bmp.mem_full |= (1 << child);
1147             break;
1148 
1149         default:
1150             break;                     // Does not count states other than those above
1151         }
1152 
1153     }
1154     /*
1155        Send in the priority order of Startmsg > DLFileInfo > Block
1156 
1157      */
1158     if (bmp.boot)
1159     {
1160         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_BOOTREQ, bmp.boot);
1161     }
1162     else if (bmp.connected)            // Send entry request permitted message
1163     {
1164         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_SENDSTART, bmp.connected);
1165     }
1166     else if (bmp.mem_full)             // Send member exceeded message
1167     {
1168         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_MEMBER_FULL, bmp.mem_full);
1169     }
1170     else if (bmp.kick)                 // Send entry denied message
1171     {
1172         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_KICKREQ, bmp.kick);
1173     }
1174     else if (bmp.req)                  // Send MbDownloadFileInfo
1175     {
1176         errcode = MBi_CommParentSendDLFileInfo();
1177     }
1178     else                               // Send Block data
1179     {
1180         errcode = MBi_CommParentSendBlock();
1181     }
1182 
1183     // MP transmission for keeping Connection
1184     if (MB_SENDFUNC_STATE_ERR == errcode)
1185     {
1186         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_DUMMY, 0xffff);
1187     }
1188 
1189     return errcode;
1190 
1191 }
1192 
1193 
1194 /*---------------------------------------------------------------------------*
1195   Name:         MBi_calc_sendblock
1196 
1197   Description:  Calculates the blocks to be sent.
1198 
1199   Arguments:    file_id: ID of the file to be sent
1200 
1201   Returns:
1202  *---------------------------------------------------------------------------*/
1203 
MBi_calc_sendblock(u8 file_id)1204 static void MBi_calc_sendblock(u8 file_id)
1205 {
1206     /* Do not update if a request for the block specified by the child device has not been received */
1207     if ((any_recv_bitmap & (1 << file_id)) == 0)
1208     {
1209         return;
1210     }
1211 
1212     if (pPwork->fileinfo[file_id].active && pPwork->fileinfo[file_id].pollbmp)
1213     {
1214         if (pPwork->fileinfo[file_id].nextb <= pPwork->fileinfo[file_id].currentb &&
1215             pPwork->fileinfo[file_id].currentb <=
1216             pPwork->fileinfo[file_id].nextb + MB_SEND_THRESHOLD)
1217         {
1218             pPwork->fileinfo[file_id].currentb++;
1219         }
1220         else
1221         {
1222             pPwork->fileinfo[file_id].currentb = pPwork->fileinfo[file_id].nextb;
1223         }
1224         MB_DEBUG_OUTPUT("**FILE %2d SendBlock %d\n", file_id, pPwork->fileinfo[file_id].currentb);
1225     }
1226 
1227 }
1228 
1229 /*---------------------------------------------------------------------------*
1230   Name:         MBi_calc_nextsendblock
1231 
1232   Description:  Returns the next block to be sent.
1233 
1234   Arguments:
1235 
1236   Returns:
1237  *---------------------------------------------------------------------------*/
1238 
MBi_calc_nextsendblock(u16 next_block,u16 next_block_req)1239 static u16 MBi_calc_nextsendblock(u16 next_block, u16 next_block_req)
1240 {
1241     return max(next_block_req, next_block);
1242 }
1243 
1244 
1245 /*  ============================================================================
1246 
1247     Miscellaneous functions
1248 
1249     ============================================================================*/
1250 
max(u16 a,u16 b)1251 static inline u16 max(u16 a, u16 b)
1252 {
1253     return (u16)((a > b) ? a : b);
1254 }
1255 
IsChildAidValid(u16 child_aid)1256 static BOOL IsChildAidValid(u16 child_aid)
1257 {
1258     return (child_aid >= 1 && child_aid <= WM_NUM_MAX_CHILD) ? TRUE : FALSE;
1259 }
1260 
MBi_CommCallParentError(u16 aid,u16 errcode)1261 static void MBi_CommCallParentError(u16 aid, u16 errcode)
1262 {
1263     MBErrorStatus e_stat;
1264     e_stat.errcode = errcode;
1265 
1266     MBi_CommChangeParentStateCallbackOnly(aid, MB_COMM_PSTATE_ERROR, &e_stat);
1267 }
1268