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-04#$
14 $Rev: 10698 $
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 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 // 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, 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?)
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 u32 length = p_info->len;
930 arc = FS_FindArchive(p_list->arc_name, (int)p_list->arc_name_len);
931 if (!arc)
932 {
933 arc = p_list->arc_pointer;
934 }
935 #ifdef SDK_TWL
936 // When running in TWL mode, avoid reading outside the ROM
937 if (OS_IsRunOnTwl() && (arc == FS_FindArchive("rom", 3)))
938 {
939 const CARDRomHeaderTWL *header = (const CARDRomHeaderTWL *)CARD_GetOwnRomHeaderTWL();
940 // Note that in some cases the distributed program may be maintained as a TWL-exclusive file
941 const u32 boundary_ntr = header->digest_area_ntr.offset + header->digest_area_ntr.length;
942 const u32 boundary_ltd = header->digest_area_ltd.offset + header->digest_area_ltd.length;
943 if ((p_info->src < boundary_ntr) && (p_info->src + length > boundary_ntr))
944 {
945 length = boundary_ntr - p_info->src;
946 }
947 else if ((p_info->src < boundary_ltd) && (p_info->src + length > boundary_ltd))
948 {
949 length = boundary_ltd - p_info->src;
950 }
951 }
952 #endif
953
954 FS_InitFile(file);
955
956 /* Specify the target archive for the MB_ReadSegment function */
957 if (FS_OpenFileDirect(file,
958 arc,
959 p_info->src, p_info->src + length, (u32)~0))
960 {
961 if (FS_ReadFile(file, p_info->ptr, (int)length) == length)
962 {
963 /* It is acceptable to set to READY here */
964 p_info->state = MB_CACHE_STATE_READY;
965 }
966 (void)FS_CloseFile(file);
967 }
968
969 /* File loading failed, due to causes such as card removal */
970 if (p_info->state != MB_CACHE_STATE_READY)
971 {
972 /*
973 * 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].
974 *
975 *
976 *
977 * 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.
978 *
979 * (However, in actuality, this should not be called twice when the card is removed)
980 */
981 p_info->src = 0;
982 p_info->state = MB_CACHE_STATE_READY;
983 }
984 }
985
986 /*---------------------------------------------------------------------------*
987 Name: MBi_CommParentSendBlock
988
989 Description: Sends Block data from the parent.
990
991 Arguments: None.
992
993 Returns: None.
994 *---------------------------------------------------------------------------*/
995
MBi_CommParentSendBlock(void)996 static int MBi_CommParentSendBlock(void)
997 {
998 MBCommParentBlockHeader hd;
999 u8 *databuf;
1000 u8 i;
1001 MB_BlockInfo bi;
1002
1003 // Determine the file number to send
1004 if (pPwork->file_num == 0)
1005 return MB_SENDFUNC_STATE_ERR;
1006
1007 // The block transfer main body starts from here
1008
1009 // Determine the file that is the send target
1010 for (i = 0; i < MB_MAX_FILE; i++)
1011 {
1012 pPwork->cur_fileid = (u8)((pPwork->cur_fileid + 1) % MB_MAX_FILE);
1013 if (pPwork->fileinfo[pPwork->cur_fileid].active
1014 && pPwork->fileinfo[pPwork->cur_fileid].pollbmp)
1015 {
1016 MB_DEBUG_OUTPUT("Send File ID:%2d\n", pPwork->cur_fileid);
1017 break;
1018 }
1019 }
1020 if (i == MB_MAX_FILE) // No file to send
1021 {
1022 return MB_SENDFUNC_STATE_ERR;
1023 }
1024
1025 /* Calculate the number of blocks to send for the file being sent */
1026 MBi_calc_sendblock(pPwork->cur_fileid);
1027
1028 // Get the block information
1029 if (!MBi_get_blockinfo(&bi,
1030 &pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table,
1031 pPwork->fileinfo[pPwork->cur_fileid].currentb,
1032 &pPwork->fileinfo[pPwork->cur_fileid].dl_fileinfo.header))
1033 {
1034 return MB_SENDFUNC_STATE_ERR;
1035 }
1036 /* Prepare the packets to send */
1037 hd.type = MB_COMM_TYPE_PARENT_DATA;
1038 hd.fid = pPwork->cur_fileid;
1039 hd.seqno = pPwork->fileinfo[pPwork->cur_fileid].currentb;
1040 databuf = MBi_MakeParentSendBuffer(&hd, (u8 *)pPwork->common.sendbuf);
1041
1042 /* Access though the cache (will always hit if there is enough memory) */
1043 {
1044 /* Calculate the CARD address from the block offset */
1045 u32 card_addr = (u32)(bi.offset -
1046 pPwork->fileinfo[pPwork->cur_fileid].blockinfo_table.
1047 seg_src_offset[bi.segment_no] +
1048 pPwork->fileinfo[pPwork->cur_fileid].card_mapping[bi.segment_no]);
1049 /* Cache read for the specified CARD address */
1050 MBiCacheList *const pl = pPwork->fileinfo[pPwork->cur_fileid].cache_list;
1051 if (!MBi_ReadFromCache(pl, card_addr, databuf, bi.size))
1052 {
1053 /* If a cache miss, send a reload request to the task thread */
1054 MBiTaskInfo *const p_task = &pPwork->cur_task;
1055 if (!MBi_IsTaskBusy(p_task))
1056 {
1057 /* Lifetime value to avoid continuous page faults */
1058 if (pl->lifetime)
1059 {
1060 --pl->lifetime;
1061 }
1062 else
1063 {
1064 /*
1065 * Destroy the cache with the newest address.
1066 * We will continue to test the operation of this part later.
1067 */
1068 MBiCacheInfo *pi = pl->list;
1069 MBiCacheInfo *trg = NULL;
1070 int i;
1071 for (i = 0; i < MB_CACHE_INFO_MAX; ++i)
1072 {
1073 if (pi[i].state == MB_CACHE_STATE_READY)
1074 {
1075 if (!trg || (trg->src > pi[i].src))
1076 trg = &pi[i];
1077 }
1078 }
1079 if (!trg)
1080 {
1081 OS_TPanic("cache-list is invalid! (all the pages are locked)");
1082 }
1083 pl->lifetime = 2;
1084 trg->state = MB_CACHE_STATE_BUSY;
1085 trg->src = (card_addr & ~31);
1086 p_task->param[0] = (u32)trg; /* MBiCacheInfo* */
1087 p_task->param[1] = (u32)pl; /* MBiCacheList* */
1088 MBi_SetTask(p_task, MBi_ReloadCache, NULL, 4);
1089 }
1090 }
1091 return MB_SENDFUNC_STATE_ERR;
1092 }
1093 }
1094
1095 return MBi_BlockHeaderEnd((int)(bi.size + MB_COMM_PARENT_HEADER_SIZE),
1096 pPwork->fileinfo[pPwork->cur_fileid].pollbmp, pPwork->common.sendbuf);
1097 }
1098
1099 /*---------------------------------------------------------------------------*
1100 Name: MBi_CommParentSendData
1101
1102 Description: Sends parent data.
1103
1104 Arguments: None.
1105
1106 Returns: None.
1107 *---------------------------------------------------------------------------*/
1108
MBi_CommParentSendData(void)1109 static int MBi_CommParentSendData(void)
1110 {
1111 struct bitmap
1112 {
1113 u16 connected;
1114 u16 req;
1115 u16 kick;
1116 u16 boot;
1117 u16 mem_full;
1118 };
1119 struct bitmap bmp;
1120 u16 child;
1121 int errcode;
1122
1123 MI_CpuClear16(&bmp, sizeof(struct bitmap));
1124
1125 // Evaluate the parent status of each child
1126 for (child = 1; child <= WM_NUM_MAX_CHILD; child++)
1127 {
1128
1129 switch (pPwork->p_comm_state[child - 1])
1130 {
1131 case MB_COMM_PSTATE_CONNECTED:
1132 bmp.connected |= (1 << child);
1133 break;
1134
1135 case MB_COMM_PSTATE_REQ_ACCEPTED:
1136 bmp.req |= (1 << child);
1137 break;
1138
1139 case MB_COMM_PSTATE_KICKED:
1140 bmp.kick |= (1 << child);
1141 break;
1142
1143 case MB_COMM_PSTATE_SEND_PROCEED:
1144 break;
1145
1146 case MB_COMM_PSTATE_BOOT_REQUEST:
1147 bmp.boot |= (1 << child);
1148 break;
1149
1150 case MB_COMM_PSTATE_MEMBER_FULL:
1151 bmp.mem_full |= (1 << child);
1152 break;
1153
1154 default:
1155 break; // Does not count states other than those above
1156 }
1157
1158 }
1159 /*
1160 Send in the priority order of Startmsg > DLFileInfo > Block
1161
1162 */
1163 if (bmp.boot)
1164 {
1165 errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_BOOTREQ, bmp.boot);
1166 }
1167 else if (bmp.connected) // Send entry request permitted message
1168 {
1169 errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_SENDSTART, bmp.connected);
1170 }
1171 else if (bmp.mem_full) // Send member exceeded message
1172 {
1173 errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_MEMBER_FULL, bmp.mem_full);
1174 }
1175 else if (bmp.kick) // Send entry denied message
1176 {
1177 errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_PARENT_KICKREQ, bmp.kick);
1178 }
1179 else if (bmp.req) // Send MbDownloadFileInfo
1180 {
1181 errcode = MBi_CommParentSendDLFileInfo();
1182 }
1183 else // Send Block data
1184 {
1185 errcode = MBi_CommParentSendBlock();
1186 }
1187
1188 // MP transmission for keeping Connection
1189 if (MB_SENDFUNC_STATE_ERR == errcode)
1190 {
1191 errcode = MBi_CommParentSendMsg(MB_COMM_TYPE_DUMMY, 0xffff);
1192 }
1193
1194 return errcode;
1195
1196 }
1197
1198
1199 /*---------------------------------------------------------------------------*
1200 Name: MBi_calc_sendblock
1201
1202 Description: Calculates the blocks to be sent.
1203
1204 Arguments: file_id: ID of the file to be sent
1205
1206 Returns:
1207 *---------------------------------------------------------------------------*/
1208
MBi_calc_sendblock(u8 file_id)1209 static void MBi_calc_sendblock(u8 file_id)
1210 {
1211 /* Do not update if a request for the block specified by the child device has not been received */
1212 if ((any_recv_bitmap & (1 << file_id)) == 0)
1213 {
1214 return;
1215 }
1216
1217 if (pPwork->fileinfo[file_id].active && pPwork->fileinfo[file_id].pollbmp)
1218 {
1219 if (pPwork->fileinfo[file_id].nextb <= pPwork->fileinfo[file_id].currentb &&
1220 pPwork->fileinfo[file_id].currentb <=
1221 pPwork->fileinfo[file_id].nextb + MB_SEND_THRESHOLD)
1222 {
1223 pPwork->fileinfo[file_id].currentb++;
1224 }
1225 else
1226 {
1227 pPwork->fileinfo[file_id].currentb = pPwork->fileinfo[file_id].nextb;
1228 }
1229 MB_DEBUG_OUTPUT("**FILE %2d SendBlock %d\n", file_id, pPwork->fileinfo[file_id].currentb);
1230 }
1231
1232 }
1233
1234 /*---------------------------------------------------------------------------*
1235 Name: MBi_calc_nextsendblock
1236
1237 Description: Returns the next block to be sent.
1238
1239 Arguments:
1240
1241 Returns:
1242 *---------------------------------------------------------------------------*/
1243
MBi_calc_nextsendblock(u16 next_block,u16 next_block_req)1244 static u16 MBi_calc_nextsendblock(u16 next_block, u16 next_block_req)
1245 {
1246 return max(next_block_req, next_block);
1247 }
1248
1249
1250 /* ============================================================================
1251
1252 Miscellaneous functions
1253
1254 ============================================================================*/
1255
max(u16 a,u16 b)1256 static inline u16 max(u16 a, u16 b)
1257 {
1258 return (u16)((a > b) ? a : b);
1259 }
1260
IsChildAidValid(u16 child_aid)1261 static BOOL IsChildAidValid(u16 child_aid)
1262 {
1263 return (child_aid >= 1 && child_aid <= WM_NUM_MAX_CHILD) ? TRUE : FALSE;
1264 }
1265
MBi_CommCallParentError(u16 aid,u16 errcode)1266 static void MBi_CommCallParentError(u16 aid, u16 errcode)
1267 {
1268 MBErrorStatus e_stat;
1269 e_stat.errcode = errcode;
1270
1271 MBi_CommChangeParentStateCallbackOnly(aid, MB_COMM_PSTATE_ERROR, &e_stat);
1272 }
1273