1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - libraries
3   File:     mb_parent.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:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
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 disabled */
74 
75     pPwork->parent_callback = callback;
76 
77     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
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 disabled */
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);    /* Cancel interrupt disabling. */
119         return &pPwork->childUserBuf;
120     }
121     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
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  failed - 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 disabled */
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);    /* Cancel interrupt disabling. */
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);        /* Cancel interrupt disabling. */
250             return TRUE;
251         }
252     }
253 
254     (void)OS_RestoreInterrupts(enabled);        /* Cancel interrupt disabling. */
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         /* Release 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             // Only accept when MB_COMM_PSTATE_CONNECTED.
566             if (state == MB_COMM_PSTATE_CONNECTED)
567             {
568                 MBCommRequestData req_data;
569 
570                 if (p_data == NULL)
571                 {
572                     // Do not move to the next state until all of the child's request data is present.
573                     break;
574                 }
575 
576                 MI_CpuCopy8(p_data, &req_data, MB_COMM_REQ_DATA_SIZE);
577 
578                 pPwork->childggid[child - 1] = req_data.ggid;
579                 pPwork->childversion[child - 1] = req_data.version;
580                 MB_DEBUG_OUTPUT("Child [%2d] MB_IPL_VERSION : %04x\n", child, req_data.version);
581                 MI_CpuCopy8(&req_data.userinfo, &pPwork->childUser[child - 1], sizeof(MBUserInfo));
582                 pPwork->childUser[child - 1].playerNo = child;
583                 /* Pass the received MBCommRequestData to the callback arguments. */
584                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_REQUESTED, &req_data.userinfo);
585             }
586 
587             if (state == MB_COMM_PSTATE_REQUESTED)
588             {
589                 u8      i, entry_num = 0;
590                 u8      fileid = ((MBCommRequestData *)p_data)->fileid;
591 
592                 /* Kick if an inactive fileNo is requested, the fileid is invalid, or the GGID of the fileNo does not match the requested GGID.
593 
594                    */
595                 if (fileid >= MB_MAX_FILE
596                     || pPwork->fileinfo[fileid].active == 0
597                     || pPwork->childggid[child - 1] != pPwork->fileinfo[fileid].game_reg->ggid)
598                 {
599                     pPwork->req2child[child - 1] = MB_COMM_USER_REQ_KICK;
600                 }
601                 else
602                 {
603                     /* Kick if the set number of people was exceeded. */
604                     for (i = 0; i < WM_NUM_MAX_CHILD + 1; i++)
605                     {
606                         if (pPwork->fileinfo[fileid].gameinfo_child_bmp & (0x0001 << i))
607                         {
608                             entry_num++;
609                         }
610                     }
611 
612                     if (entry_num >= pPwork->fileinfo[fileid].game_reg->maxPlayerNum)
613                     {
614                         MB_DEBUG_OUTPUT("Member full (AID:%2d)\n", child);
615                         /* Forcibly cancel the request. */
616                         pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
617                         MBi_CommChangeParentState(child, MB_COMM_PSTATE_MEMBER_FULL, NULL);
618                         break;
619                     }
620                 }
621 
622                 switch (pPwork->req2child[child - 1])
623                 {
624                 case MB_COMM_USER_REQ_ACCEPT:
625                     {
626 
627                         if (0 == (pPwork->child_entry_bmp & (0x0001 << (child))))
628                         {
629                             pPwork->child_num++;
630                             pPwork->child_entry_bmp |= (0x0001 << (child));
631                             pPwork->fileid_of_child[child - 1] = (s8)fileid;
632 
633                             pPwork->fileinfo[fileid].gameinfo_child_bmp |=
634                                 MB_GAMEINFO_CHILD_FLAG(child);
635                             pPwork->fileinfo[fileid].gameinfo_changed_bmp |=
636                                 MB_GAMEINFO_CHILD_FLAG(child);
637                             MB_DEBUG_OUTPUT("Update Member (AID:%2d)\n", child);
638                             pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
639 
640                             MBi_CommChangeParentState(child, MB_COMM_PSTATE_REQ_ACCEPTED, NULL);
641                         }
642                     }
643                     break;
644 
645                 case MB_COMM_USER_REQ_KICK:
646                     MB_DEBUG_OUTPUT("Kick (AID:%2d)\n", child);
647                     pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
648                     MBi_CommChangeParentState(child, MB_COMM_PSTATE_KICKED, NULL);
649                     break;
650                 }
651             }
652         }
653         break;
654 
655     case MB_COMM_TYPE_CHILD_ACCEPT_FILEINFO:
656 
657         /* When MB_COMM_PSTATE_REQ_ACCEPTED, only transition to MB_COMM_PSTATE_WAIT_TO_SEND. */
658         if (state == MB_COMM_PSTATE_REQ_ACCEPTED)
659         {
660             MBi_CommChangeParentState(child, MB_COMM_PSTATE_WAIT_TO_SEND, NULL);
661         }
662 
663         /* When MB_COMM_PSTATE_WAIT_TO_SEND, add to pollbitmap for the requested file and shift to MB_COMM_PSTATE_SEND_PROCEED.
664 
665             */
666         else if (state == MB_COMM_PSTATE_WAIT_TO_SEND)
667         {
668             // If the SendStart trigger was on, transition to the block send state.
669             if (pPwork->req2child[child - 1] == MB_COMM_USER_REQ_SEND_START)
670             {
671                 u8      fid = (u8)pPwork->fileid_of_child[child - 1];
672                 pPwork->fileinfo[fid].pollbmp |= (0x0001 << (child));
673                 pPwork->fileinfo[fid].currentb = 0;
674 
675                 pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
676                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_SEND_PROCEED, NULL);
677             }
678         }
679         break;
680 
681     case MB_COMM_TYPE_CHILD_CONTINUE:
682         if (state == MB_COMM_PSTATE_SEND_PROCEED)
683         {
684             u8      fileid = (u8)pPwork->fileid_of_child[child - 1];
685 
686             if (fileid == (u8)-1)
687                 break;
688 
689             // Of the nextSend's that come from multiple children, choose the largest one as the send target.
690             SDK_ASSERT(fileid < MB_MAX_FILE);
691             SDK_ASSERT(pPwork->fileinfo[fileid].pollbmp);
692 
693             pPwork->fileinfo[fileid].nextb =
694                 MBi_calc_nextsendblock(pPwork->fileinfo[fileid].nextb, hd.data.req);
695             any_recv_bitmap |= (1 << fileid);
696         }
697         break;
698 
699     case MB_COMM_TYPE_CHILD_STOPREQ:
700         if (state == MB_COMM_PSTATE_SEND_PROCEED)
701         {
702             u8      fileid = (u8)pPwork->fileid_of_child[child - 1];
703 
704             if (fileid == (u8)-1)
705                 break;
706 
707             SDK_ASSERT(fileid < MB_MAX_FILE);
708 
709             pPwork->fileinfo[fileid].pollbmp &= ~(0x0001 << (child));
710 
711             MBi_CommChangeParentState(child, MB_COMM_PSTATE_SEND_COMPLETE, NULL);       // Send completed
712         }
713         else if (state == MB_COMM_PSTATE_SEND_COMPLETE)
714         {
715             if (pPwork->req2child[child - 1] == MB_COMM_USER_REQ_BOOT)
716             {
717                 pPwork->req2child[child - 1] = MB_COMM_USER_REQ_NONE;
718                 MBi_CommChangeParentState(child, MB_COMM_PSTATE_BOOT_REQUEST, NULL);
719                 break;
720             }
721         }
722         break;
723 
724     case MB_COMM_TYPE_CHILD_BOOTREQ_ACCEPTED:
725         if (state == MB_COMM_PSTATE_BOOT_REQUEST)
726         {
727             /* BOOTREQ_ACCEPTED from a child is not used for state transitions. */
728             break;
729         }
730 
731         break;
732 
733     default:
734         break;
735     }
736 
737 }
738 
739 /*---------------------------------------------------------------------------*
740   Name:         MBi_CommParentRecvData
741 
742   Description:  Receives parent data.
743 
744   Arguments:    arg: Pointer to callback argument.
745 
746   Returns:      None.
747  *---------------------------------------------------------------------------*/
748 
MBi_CommParentRecvData(void * arg)749 static void MBi_CommParentRecvData(void *arg)
750 {
751     // The argument arg contains a pointer to the receive buffer.
752     WMmpRecvHeader *mpHeader = (WMmpRecvHeader *)arg;
753 
754     u16     i;
755     WMmpRecvData *datap;
756 
757     // Initialize at this point in order to evaluate the total with MBi_CommParentRecvDataPerChild.
758     for (i = 0; i < MB_MAX_FILE; i++)
759     {
760         if (pPwork->fileinfo[i].active)
761             pPwork->fileinfo[i].nextb = 0;
762     }
763     any_recv_bitmap = 0;
764 
765     // Display the data received from each child.
766     for (i = 1; i <= WM_NUM_MAX_CHILD; ++i)
767     {
768         // Get the starting address of the data for the child with AID==i.
769         datap = WM_ReadMPData(mpHeader, (u16)i);
770         // If data exists for the child with AID==i.
771         if (datap != NULL)
772         {
773             // Display the received data.
774             if (datap->length == 0xffff)
775             {
776             }
777             else if (datap->length != 0)
778             {
779                 // Processing for each child's data.
780                 MBi_CommParentRecvDataPerChild(datap, i);
781             }
782         }
783     }
784 }
785 
786 
787 /*---------------------------------------------------------------------------*
788   Name:         MBi_CommParentSendMsg
789 
790   Description:  Sends a message from the parent.
791 
792   Arguments:    pollbmp
793 
794   Returns:      None.
795  *---------------------------------------------------------------------------*/
796 
MBi_CommParentSendMsg(u8 type,u16 pollbmp)797 static int MBi_CommParentSendMsg(u8 type, u16 pollbmp)
798 {
799     MBCommParentBlockHeader hd;
800 
801     /* Notify that transmission has begun (without arguments). */
802     hd.type = type;
803 
804     (void)MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
805     return MBi_BlockHeaderEnd(MB_COMM_PARENT_HEADER_SIZE, pollbmp, pPwork->common.sendbuf);
806 }
807 
808 /*---------------------------------------------------------------------------*
809   Name:         MBi_CommParentSendDLFileInfo
810 
811   Description:  Sends DownloadFileInfo from the parent.
812 
813   Arguments:    None.
814 
815   Returns:      None.
816  *---------------------------------------------------------------------------*/
817 
MBi_CommParentSendDLFileInfo(void)818 static int MBi_CommParentSendDLFileInfo(void)
819 {
820     MBCommParentBlockHeader hd;
821     u8     *databuf = ((u8 *)pPwork->common.sendbuf) + MB_COMM_PARENT_HEADER_SIZE;
822     u16     child;
823     u8      i, fid;
824     s8      send_candidate_fid = -1;
825     static s8 prev_fid = -1;
826     u8      file_req_num[MB_MAX_FILE];
827     u16     pollbmp = 0;
828 
829     MI_CpuClear8(&file_req_num[0], sizeof(u8) * MB_MAX_FILE);
830 
831     // Aggregate the FileID's that children are requesting.
832     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
833     {
834         if (pPwork->p_comm_state[child - 1] == MB_COMM_PSTATE_REQ_ACCEPTED)
835         {
836             // Count only children that are MB_COMM_PSTATE_REQ_ACCEPTED targets.
837             ++(file_req_num[pPwork->fileid_of_child[child - 1]]);
838         }
839     }
840 
841     fid = (u8)prev_fid;
842 
843     for (i = 0; i < MB_MAX_FILE; i++)  // Determine the send file ID.
844     {
845 #if 1
846         fid = (u8)((fid + 1) % MB_MAX_FILE);
847 
848         if (pPwork->fileinfo[fid].active && file_req_num[fid] > 0)
849         {
850             send_candidate_fid = (s8)fid;
851             break;
852         }
853 
854 #else
855         if (pPwork->fileinfo[i].active)
856         {
857             if (file_req_num[i] > 0)
858             {
859 
860                 /*
861                    Majority decision
862                    (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.
863 
864                    Although there are no problems with multiboot operations, since 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?)
865 
866 
867 
868                  */
869 
870                 if (send_candidate_fid == -1 || file_req_num[i] > file_req_num[send_candidate_fid])
871                 {
872                     send_candidate_fid = i;
873                 }
874 
875             }
876         }
877 #endif
878 
879     }
880 
881     if (send_candidate_fid == -1)
882         return MB_SENDFUNC_STATE_ERR;
883 
884     prev_fid = send_candidate_fid;
885 
886     // Poll bitmap settings (only children that are requesting the same file number as the one to be sent)
887     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
888     {
889         if (pPwork->p_comm_state[child - 1] == MB_COMM_PSTATE_REQ_ACCEPTED
890             && pPwork->fileid_of_child[child - 1] == send_candidate_fid)
891         {
892             pollbmp |= (1 << child);
893         }
894     }
895 
896     MB_DEBUG_OUTPUT("DLinfo No %2d Pollbmp %04x\n", send_candidate_fid, pollbmp);
897 
898     // Send the FileInfo of the last child that received the request.
899     hd.type = MB_COMM_TYPE_PARENT_DL_FILEINFO;
900     hd.fid = send_candidate_fid;
901 
902     databuf = MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
903     if (databuf)
904     {
905         // Copy data to the send buffer.
906         MI_CpuCopy8(&pPwork->fileinfo[send_candidate_fid].dl_fileinfo,
907                     databuf, sizeof(MBDownloadFileInfo));
908     }
909 
910     return MBi_BlockHeaderEnd(sizeof(MBDownloadFileInfo) + MB_COMM_PARENT_HEADER_SIZE, pollbmp,
911                               pPwork->common.sendbuf);
912 }
913 
914 /*---------------------------------------------------------------------------*
915   Name:         MBi_ReloadCache
916 
917   Description:  Reload data in the destroyed cache that is specified.
918 
919   Arguments:    p_task:           Task that stores MBiCacheInfo in param[0].
920 
921   Returns:      None.
922  *---------------------------------------------------------------------------*/
MBi_ReloadCache(MBiTaskInfo * p_task)923 static void MBi_ReloadCache(MBiTaskInfo * p_task)
924 {
925     MBiCacheInfo *const p_info = (MBiCacheInfo *) p_task->param[0];
926     MBiCacheList *const p_list = (MBiCacheList *) p_task->param[1];
927     FSFile  file[1];
928     FSArchive   *arc;
929     arc = FS_FindArchive(p_list->arc_name, (int)p_list->arc_name_len);
930     if (!arc)
931     {
932         arc = p_list->arc_pointer;
933     }
934 
935     FS_InitFile(file);
936 
937     /* Specify the target archive for MB_ReadSegment(). */
938     if (FS_OpenFileDirect(file,
939                           arc,
940                           p_info->src, p_info->src + p_info->len, (u32)~0))
941     {
942         if (FS_ReadFile(file, p_info->ptr, (int)p_info->len) == p_info->len)
943         {
944             /* It is acceptable to set to READY here. */
945             p_info->state = MB_CACHE_STATE_READY;
946         }
947         (void)FS_CloseFile(file);
948     }
949 
950     /* File loading failed, due to causes such as card removal. */
951     if (p_info->state != MB_CACHE_STATE_READY)
952     {
953         /*
954          * 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].
955          *
956          *
957          *
958          * 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.
959          *
960          * (However, in actuality, this should not be called twice when the card is removed)
961          */
962         p_info->src = 0;
963         p_info->state = MB_CACHE_STATE_READY;
964     }
965 }
966 
967 /*---------------------------------------------------------------------------*
968   Name:         MBi_CommParentSendBlock
969 
970   Description:  Sends Block data from the parent.
971 
972   Arguments:    None.
973 
974   Returns:      None.
975  *---------------------------------------------------------------------------*/
976 
MBi_CommParentSendBlock(void)977 static int MBi_CommParentSendBlock(void)
978 {
979     MBCommParentBlockHeader hd;
980     u8     *databuf;
981     u8      i;
982     MB_BlockInfo bi;
983 
984     // Determine the file number to send.
985     if (pPwork->file_num == 0)
986         return MB_SENDFUNC_STATE_ERR;
987 
988     // The block transfer main body starts from here.
989 
990     // Determine the file that is the send target.
991     for (i = 0; i < MB_MAX_FILE; i++)
992     {
993         pPwork->cur_fileid = (u8)((pPwork->cur_fileid + 1) % MB_MAX_FILE);
994         if (pPwork->fileinfo[pPwork->cur_fileid].active
995             && pPwork->fileinfo[pPwork->cur_fileid].pollbmp)
996         {
997             MB_DEBUG_OUTPUT("Send File ID:%2d\n", pPwork->cur_fileid);
998             break;
999         }
1000     }
1001     if (i == MB_MAX_FILE)              // No file to send.
1002     {
1003         return MB_SENDFUNC_STATE_ERR;
1004     }
1005 
1006     /* Calculate the number of blocks to send for the file being sent. */
1007     MBi_calc_sendblock(pPwork->cur_fileid);
1008 
1009     // Obtain the block information.
1010     if (!MBi_get_blockinfo(&bi,
1011                            &pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table,
1012                            pPwork->fileinfo[pPwork->cur_fileid].currentb,
1013                            &pPwork->fileinfo[pPwork->cur_fileid].dl_fileinfo.header))
1014     {
1015         return MB_SENDFUNC_STATE_ERR;
1016     }
1017     /* Prepare the packets to send. */
1018     hd.type = MB_COMM_TYPE_PARENT_DATA;
1019     hd.fid = pPwork->cur_fileid;
1020     hd.seqno = pPwork->fileinfo[pPwork->cur_fileid].currentb;
1021     databuf = MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
1022 
1023     /* Access though the cache (will always hit if there is enough memory). */
1024     {
1025         /* Calculate the CARD address from the block offset. */
1026         u32     card_addr = (u32)(bi.offset -
1027                                   pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table.
1028                                   seg_src_offset[bi.segment_no] +
1029                                   pPwork->fileinfo[pPwork->cur_fileid].card_mapping[bi.segment_no]);
1030         /* Cache read for the specified CARD address. */
1031         MBiCacheList *const pl = pPwork->fileinfo[pPwork->cur_fileid].cache_list;
1032         if (!MBi_ReadFromCache(pl, card_addr, databuf, bi.size))
1033         {
1034             /* If a cache miss, send a reload request to the task thread. */
1035             MBiTaskInfo *const p_task = &pPwork->cur_task;
1036             if (!MBi_IsTaskBusy(p_task))
1037             {
1038                 /* Lifetime value to avoid continuous page faults. */
1039                 if (pl->lifetime)
1040                 {
1041                     --pl->lifetime;
1042                 }
1043                 else
1044                 {
1045                     /*
1046                      * Destroy the cache with the newest address.
1047                      * We will continue to test the operation of this part later.
1048                      */
1049                     MBiCacheInfo *pi = pl->list;
1050                     MBiCacheInfo *trg = NULL;
1051                     int     i;
1052                     for (i = 0; i < MB_CACHE_INFO_MAX; ++i)
1053                     {
1054                         if (pi[i].state == MB_CACHE_STATE_READY)
1055                         {
1056                             if (!trg || (trg->src > pi[i].src))
1057                                 trg = &pi[i];
1058                         }
1059                     }
1060                     if (!trg)
1061                     {
1062                         OS_TPanic("cache-list is invalid! (all the pages are locked)");
1063                     }
1064                     pl->lifetime = 2;
1065                     trg->state = MB_CACHE_STATE_BUSY;
1066                     trg->src = (card_addr & ~31);
1067                     p_task->param[0] = (u32)trg;        /* MBiCacheInfo* */
1068                     p_task->param[1] = (u32)pl; /* MBiCacheList* */
1069                     MBi_SetTask(p_task, MBi_ReloadCache, NULL, 4);
1070                 }
1071             }
1072             return MB_SENDFUNC_STATE_ERR;
1073         }
1074     }
1075 
1076     return MBi_BlockHeaderEnd((int)(bi.size + MB_COMM_PARENT_HEADER_SIZE),
1077                               pPwork->fileinfo[pPwork->cur_fileid].pollbmp, pPwork->common.sendbuf);
1078 }
1079 
1080 /*---------------------------------------------------------------------------*
1081   Name:         MBi_CommParentSendData
1082 
1083   Description:  Sends parent data.
1084 
1085   Arguments:    None.
1086 
1087   Returns:      None.
1088  *---------------------------------------------------------------------------*/
1089 
MBi_CommParentSendData(void)1090 static int MBi_CommParentSendData(void)
1091 {
1092     struct bitmap
1093     {
1094         u16     connected;
1095         u16     req;
1096         u16     kick;
1097         u16     boot;
1098         u16     mem_full;
1099     };
1100     struct bitmap bmp;
1101     u16     child;
1102     int     errcode;
1103 
1104     MI_CpuClear16(&bmp, sizeof(struct bitmap));
1105 
1106     // Evaluate the parent status of each child.
1107     for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
1108     {
1109 
1110         switch (pPwork->p_comm_state[child - 1])
1111         {
1112         case MB_COMM_PSTATE_CONNECTED:
1113             bmp.connected |= (1 << child);
1114             break;
1115 
1116         case MB_COMM_PSTATE_REQ_ACCEPTED:
1117             bmp.req |= (1 << child);
1118             break;
1119 
1120         case MB_COMM_PSTATE_KICKED:
1121             bmp.kick |= (1 << child);
1122             break;
1123 
1124         case MB_COMM_PSTATE_SEND_PROCEED:
1125             break;
1126 
1127         case MB_COMM_PSTATE_BOOT_REQUEST:
1128             bmp.boot |= (1 << child);
1129             break;
1130 
1131         case MB_COMM_PSTATE_MEMBER_FULL:
1132             bmp.mem_full |= (1 << child);
1133             break;
1134 
1135         default:
1136             break;                     // Does not count states other than those above.
1137         }
1138 
1139     }
1140     /*
1141        Send in the priority order of  Startmsg > DLFileInfo > Block.
1142 
1143      */
1144     if (bmp.boot)
1145     {
1146         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_BOOTREQ, bmp.boot);
1147     }
1148     else if (bmp.connected)            // Send entry request permitted message
1149     {
1150         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_SENDSTART, bmp.connected);
1151     }
1152     else if (bmp.mem_full)             // Send member exceeded message
1153     {
1154         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_MEMBER_FULL, bmp.mem_full);
1155     }
1156     else if (bmp.kick)                 // Send entry denied message
1157     {
1158         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_KICKREQ, bmp.kick);
1159     }
1160     else if (bmp.req)                  // Send MbDownloadFileInfo
1161     {
1162         errcode = MBi_CommParentSendDLFileInfo();
1163     }
1164     else                               // Send Block data
1165     {
1166         errcode = MBi_CommParentSendBlock();
1167     }
1168 
1169     // MP transmission for keeping Connection
1170     if (MB_SENDFUNC_STATE_ERR == errcode)
1171     {
1172         errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_DUMMY, 0xffff);
1173     }
1174 
1175     return errcode;
1176 
1177 }
1178 
1179 
1180 /*---------------------------------------------------------------------------*
1181   Name:         MBi_calc_sendblock
1182 
1183   Description:  Calculates the blocks to be sent.
1184 
1185   Arguments:    file_id - ID of the file to be sent.
1186 
1187   Returns:
1188  *---------------------------------------------------------------------------*/
1189 
MBi_calc_sendblock(u8 file_id)1190 static void MBi_calc_sendblock(u8 file_id)
1191 {
1192     /* Do not update if a request for the block specified by the child device has not been received. */
1193     if ((any_recv_bitmap & (1 << file_id)) == 0)
1194     {
1195         return;
1196     }
1197 
1198     if (pPwork->fileinfo[file_id].active && pPwork->fileinfo[file_id].pollbmp)
1199     {
1200         if (pPwork->fileinfo[file_id].nextb <= pPwork->fileinfo[file_id].currentb &&
1201             pPwork->fileinfo[file_id].currentb <=
1202             pPwork->fileinfo[file_id].nextb + MB_SEND_THRESHOLD)
1203         {
1204             pPwork->fileinfo[file_id].currentb++;
1205         }
1206         else
1207         {
1208             pPwork->fileinfo[file_id].currentb = pPwork->fileinfo[file_id].nextb;
1209         }
1210         MB_DEBUG_OUTPUT("**FILE %2d SendBlock %d\n", file_id, pPwork->fileinfo[file_id].currentb);
1211     }
1212 
1213 }
1214 
1215 /*---------------------------------------------------------------------------*
1216   Name:         MBi_calc_nextsendblock
1217 
1218   Description:  Returns the next block to be sent.
1219 
1220   Arguments:
1221 
1222   Returns:
1223  *---------------------------------------------------------------------------*/
1224 
MBi_calc_nextsendblock(u16 next_block,u16 next_block_req)1225 static u16 MBi_calc_nextsendblock(u16 next_block, u16 next_block_req)
1226 {
1227     return max(next_block_req, next_block);
1228 }
1229 
1230 
1231 /* ============================================================================
1232 
1233     Miscellaneous functions
1234 
1235     ============================================================================*/
1236 
max(u16 a,u16 b)1237 static inline u16 max(u16 a, u16 b)
1238 {
1239     return (u16)((a > b) ? a : b);
1240 }
1241 
IsChildAidValid(u16 child_aid)1242 static BOOL IsChildAidValid(u16 child_aid)
1243 {
1244     return (child_aid >= 1 && child_aid <= WM_NUM_MAX_CHILD) ? TRUE : FALSE;
1245 }
1246 
MBi_CommCallParentError(u16 aid,u16 errcode)1247 static void MBi_CommCallParentError(u16 aid, u16 errcode)
1248 {
1249     MBErrorStatus e_stat;
1250     e_stat.errcode = errcode;
1251 
1252     MBi_CommChangeParentStateCallbackOnly(aid, MB_COMM_PSTATE_ERROR, &e_stat);
1253 }
1254