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