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