1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WBT - libraries
3   File:     wbt_context.c
4 
5   Copyright 2006-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-19#$
14   $Rev: 10786 $
15   $Author: okajima_manabu $
16  *---------------------------------------------------------------------------*/
17 
18 #include	<nitro.h>
19 #include	<nitro/wbt.h>
20 #include	<nitro/wbt/context.h>
21 
22 
23 /*---------------------------------------------------------------------------*/
24 /* Macros */
25 
26 // #define PRINTF_DEBUG 1
27 // #define PRINTF_DEBUG_L1 1
28 // #define PRINTF_DEBUG_L2 1
29 
30 #if defined(PRINTF_DEBUG)
31 #define WBT_DEBUG_OUTPUT0       OS_TPrintf
32 #else
33 #define WBT_DEBUG_OUTPUT0(...)  (void)0
34 #endif
35 
36 #if defined(PRINTF_DEBUG_L1)
37 #define WBT_DEBUG_OUTPUT1       OS_TPrintf
38 #else
39 #define WBT_DEBUG_OUTPUT1(...)  (void)0
40 #endif
41 
42 #if defined(PRINTF_DEBUG_L2)
43 #define WBT_DEBUG_OUTPUT2       OS_TPrintf
44 #else
45 #define WBT_DEBUG_OUTPUT2(...)  (void)0
46 #endif
47 
48 
49 /*---------------------------------------------------------------------------*/
50 /* Constants */
51 
52 /* *INDENT-OFF* */
53 #define WBT_CMD_0   WBT_CMD_REQ_NONE
54 #define WBT_COMMAND_REQ(type, pair_type, argument)                  \
55     {                                                               \
56         (u16) WBT_CMD_REQ_ ## type, (u16) WBT_CMD_ ## pair_type,    \
57         sizeof(WBTPacketHeaderFormat) + argument,                   \
58         TRUE, FALSE                                                 \
59     }
60 #define WBT_COMMAND_RES(type, pair_type, argument)                  \
61     {                                                               \
62         (u16) WBT_CMD_RES_ ## type, (u16) WBT_CMD_ ## pair_type,    \
63         sizeof(WBTPacketHeaderFormat) + argument,                   \
64         FALSE, TRUE                                                 \
65     }
66 #define WBT_COMMAND_MSG(type)                                       \
67     {                                                               \
68         (u16) WBT_CMD_ ## type, 0, 0, FALSE, FALSE                  \
69     }
70 static const struct
71 {
72     u32     type:8;         /* One's own command type */
73     u32     pair_type:8;    /* Command type that is a pair */
74     u32     packet;         /* Command packet size (minimum length) */
75     u32     is_req:1;       /* TRUE if WBT_CMD_REQ_* */
76     u32     is_res:1;       /* TRUE if WBT_CMD_RES_* */
77 }
78 WBTi_CommandTable[] =
79 {
80     WBT_COMMAND_MSG(REQ_NONE),
81     WBT_COMMAND_REQ(WAIT,           0,                  0),
82     WBT_COMMAND_REQ(SYNC,           RES_SYNC,           sizeof(WBTPacketRequestSyncFormat)),
83     WBT_COMMAND_RES(SYNC,           REQ_SYNC,           sizeof(WBTPacketResponseSyncFormat)),
84     WBT_COMMAND_REQ(GET_BLOCK,      RES_GET_BLOCK,      sizeof(WBTPacketRequestGetBlockFormat)),
85     WBT_COMMAND_RES(GET_BLOCK,      REQ_GET_BLOCK,      sizeof(WBTPacketResponseGetBlockFormat)),
86     WBT_COMMAND_REQ(GET_BLOCKINFO,  RES_GET_BLOCKINFO,  sizeof(WBTPacketRequestGetBlockFormat)),
87     WBT_COMMAND_RES(GET_BLOCKINFO,  REQ_GET_BLOCKINFO,  sizeof(WBTPacketResponseGetBlockFormat)),
88     WBT_COMMAND_REQ(GET_BLOCK_DONE, RES_GET_BLOCK_DONE, sizeof(WBTPacketRequestGetBlockDoneFormat)),
89     WBT_COMMAND_RES(GET_BLOCK_DONE, REQ_GET_BLOCK_DONE, sizeof(WBTPacketResponseGetBlockDoneFormat)),
90     WBT_COMMAND_REQ(USER_DATA,      RES_USER_DATA,      sizeof(WBTPacketRequestUserDataFormat)),
91     WBT_COMMAND_RES(USER_DATA,      REQ_USER_DATA,      0),
92     WBT_COMMAND_MSG(SYSTEM_CALLBACK),
93     WBT_COMMAND_MSG(PREPARE_SEND_DATA),
94     WBT_COMMAND_MSG(REQ_ERROR),
95     WBT_COMMAND_MSG(RES_ERROR),
96     WBT_COMMAND_MSG(CANCEL),
97 };
98 enum { WBT_COMMAND_MAX = sizeof(WBTi_CommandTable) / sizeof(*WBTi_CommandTable) };
99 #undef WBT_CMD_0
100 #undef WBT_COMMAND_REQ
101 #undef WBT_COMMAND_RES
102 #undef WBT_COMMAND_MSG
103 /* *INDENT-ON* */
104 
105 
106 /*---------------------------------------------------------------------------*/
107 /* Functions */
108 
div32(int a)109 SDK_INLINE int div32(int a)
110 {
111     return (a >> 5);
112 }
113 
mod32(int a)114 SDK_INLINE int mod32(int a)
115 {
116     return (a & 0x1f);
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         WBTi_CopySafeMemory
121 
122   Description:  Transfers memory or clears it to zero.
123 
124   Arguments:    src: Transfer source buffer or NULL
125                 dst: Transfer destination buffer.
126                      If src is NULL, clear to zero.
127                 len: Transfer size
128 
129   Returns:      None.
130  *---------------------------------------------------------------------------*/
WBTi_CopySafeMemory(const void * src,void * dst,u32 len)131 PLATFORM_ATTRIBUTE_INLINE void WBTi_CopySafeMemory(const void *src, void *dst, u32 len)
132 {
133     if (!src)
134     {
135         MI_CpuFill8(dst, 0x00, len);
136     }
137     else
138     {
139         MI_CpuCopy8(src, dst, len);
140     }
141 }
142 
143 /*---------------------------------------------------------------------------*
144   Name:         WBTi_GetFirstIterationAID
145 
146   Description:  Preparations for performing a looping search with the previous communications target as the starting point.
147 
148   Arguments:    context: WBTContext structure
149 
150   Returns:      AID of the search's starting position.
151  *---------------------------------------------------------------------------*/
152 PLATFORM_ATTRIBUTE_INLINE
WBTi_GetFirstIterationAID(WBTContext * context)153 int WBTi_GetFirstIterationAID(WBTContext *context)
154 {
155     const int   mask = context->req_bitmap;
156     /* Avoid an infinite loop (search from the front if no previous communications target exists) */
157     if (((1 << context->last_target_aid) & mask) == 0)
158     {
159         context->last_target_aid = 31 - (int)MATH_CLZ((u32)mask);
160     }
161     return context->last_target_aid;
162 }
163 
164 /*---------------------------------------------------------------------------*
165   Name:         WBTi_GetNextIterationAID
166 
167   Description:  Gets the AID that corresponds to the next position in a looping search.
168 
169   Arguments:    aid: Current AID
170                 mask: Bitmap of all search targets
171 
172   Returns:      The next AID.
173  *---------------------------------------------------------------------------*/
174 PLATFORM_ATTRIBUTE_INLINE
WBTi_GetNextIterationAID(int aid,int mask)175 int WBTi_GetNextIterationAID(int aid, int mask)
176 {
177     ++aid;
178     if ((1 << aid) > mask)
179     {
180         aid = (int)MATH_CTZ((u32)mask);
181     }
182     return aid;
183 }
184 
185 /*---------------------------------------------------------------------------*
186   Name:         WBTi_InitBitmap
187 
188   Description:  Initializes the bitmap structure.
189 
190   Arguments:    pkt_bmp: Bitmap structure
191                 length: Byte size of the data length
192                 bits: Bitmap buffer
193                 buffer: Data buffer
194 
195   Returns:      None.
196  *---------------------------------------------------------------------------*/
WBTi_InitBitmap(WBTContext * work,WBTPacketBitmap * pkt_bmp,s32 length,u32 * bits,u8 * buffer,int packet)197 static void WBTi_InitBitmap(WBTContext * work, WBTPacketBitmap * pkt_bmp, s32 length, u32 *bits, u8 *buffer,
198                             int packet)
199 {
200     SDK_ASSERT(packet > 0);
201     pkt_bmp->length = length;
202     pkt_bmp->buffer = buffer;
203     pkt_bmp->total = (length + packet - 1) / packet;
204     pkt_bmp->count = 0;
205     pkt_bmp->bitmap = bits;
206     MI_CpuFill8(bits, 0x00, (u32)WBT_GetBitmapLength(work, length));
207 }
208 
209 /*---------------------------------------------------------------------------*
210   Name:         WBTi_MergeBitmapIndex
211 
212   Description:  If the specified index in the bitmap has not yet been received, stores it.
213 
214   Arguments:    pkt_bmp: Bitmap structure
215                 index: Packet index
216                 packet: Per-packet size
217                 src: Packet data
218 
219   Returns:      If not yet received, store it and return TRUE.
220  *---------------------------------------------------------------------------*/
WBTi_MergeBitmapIndex(WBTPacketBitmap * pkt_bmp,int index,u32 packet,const void * src)221 static BOOL WBTi_MergeBitmapIndex(WBTPacketBitmap * pkt_bmp, int index, u32 packet, const void *src)
222 {
223     BOOL    retval = FALSE;
224     u32     pos = (u32)div32(index);
225     u32     bit = (u32)mod32(index);
226     if ((pkt_bmp->bitmap[pos] & (1 << bit)) == 0)
227     {
228         u8     *dst = pkt_bmp->buffer;
229         const u32 offset = index * packet;
230         const u32 total = (u32)pkt_bmp->length;
231         u32     length = (u32)MATH_MIN(packet, total - offset);
232         MI_CpuCopy8(src, dst + offset, length);
233         pkt_bmp->bitmap[pos] |= (1 << bit);
234         pkt_bmp->count += 1;
235         retval = TRUE;
236     }
237     return retval;
238 }
239 
240 /*---------------------------------------------------------------------------*
241   Name:         WBTi_FindBitmapIndex
242 
243   Description:  Searches for a not-yet-received index in the bitmap.
244 
245   Arguments:    pkt_bmp: Bitmap structure
246 
247   Returns:      The unreceived index or -1.
248  *---------------------------------------------------------------------------*/
WBTi_FindBitmapIndex(WBTPacketBitmap * pkt_bmp)249 static s32 WBTi_FindBitmapIndex(WBTPacketBitmap * pkt_bmp)
250 {
251     int     last_num;
252     int     bit_num;
253     u32    *bmp;
254     int     num;
255 
256     num = pkt_bmp->current + 1;
257     if (num >= pkt_bmp->total)
258     {
259         num = 0;
260     }
261     last_num = num;
262     bmp = pkt_bmp->bitmap + div32(num);
263     bit_num = mod32(num);
264 
265     for (;;)
266     {
267         /* If the specified index has not yet been received, finish searching */
268         if ((*bmp & (u32)((u32)1 << bit_num)) == 0)
269         {
270             break;
271         }
272         /* Otherwise, move on to the next index */
273         else
274         {
275             /* Loop to the beginning once the last index point is reached */
276             if (++num >= pkt_bmp->total)
277             {
278                 num = 0;
279                 bit_num = 0;
280                 bmp = pkt_bmp->bitmap;
281             }
282             /* The bitmap for managing receptions is controlled in 32-bit increments */
283             else if (++bit_num >= 32)
284             {
285                 bit_num = 0;
286                 ++bmp;
287             }
288             /* All packets have been received */
289             if (num == last_num)
290             {
291                 num = -1;
292                 break;
293             }
294         }
295     }
296     return num;
297 }
298 
299 /*---------------------------------------------------------------------------*
300   Name:         WBTi_GetPacketBuffer
301 
302   Description:  Gets the buffer of the packet data represented by the index in the specified block.
303 
304 
305   Arguments:    work: WBT structure
306                 id: Requested block ID
307                 index: Requested index
308 
309   Returns:      Pointer to the block data.
310  *---------------------------------------------------------------------------*/
WBTi_GetPacketBuffer(WBTContext * work,u32 id,s32 index)311 static u8 *WBTi_GetPacketBuffer(WBTContext * work, u32 id, s32 index)
312 {
313     u8     *ptr = NULL;
314     WBTBlockInfoList *list = work->list;
315     int     count = 0;
316     for (; list != NULL; list = list->next)
317     {
318         if (id < WBT_NUM_MAX_BLOCK_INFO_ID)
319         {
320             if (id == count)
321             {
322                 /*
323                  * CAUTION!
324                  * Don't pass the internal management structure unchanged. Decide endianness here.
325                  * (However, this is not a permanent measure, just a temporary workaround.)
326                  */
327                 static WBTBlockInfo tmp;
328                 tmp = list->data_info;
329                 tmp.id = MI_HToLE32(tmp.id);
330                 tmp.block_size = (s32)MI_HToLE32(tmp.block_size);
331                 ptr = (u8 *)&tmp;
332 //                ptr = (u8 *)&list->data_info;
333                 break;
334             }
335         }
336         else
337         {
338             if (id == list->data_info.id)
339             {
340                 ptr = (u8 *)list->data_ptr;
341                 break;
342             }
343         }
344         ++count;
345     }
346     if (ptr)
347     {
348         ptr += index * work->my_data_packet_size;
349     }
350     return ptr;
351 }
352 
353 /*---------------------------------------------------------------------------*
354   Name:         WBTi_SwitchNextCommand
355 
356   Description:  Called when there is an update to the command list.
357                   - When a new command is issued.
358                   - When the current command has completed.
359 
360   Arguments:    work: WBT structure
361 
362   Returns:      None.
363  *---------------------------------------------------------------------------*/
WBTi_SwitchNextCommand(WBTContext * work)364 static void WBTi_SwitchNextCommand(WBTContext * work)
365 {
366     BOOL    retval = FALSE;
367 
368     /* Process if the updated command is valid */
369     WBTCommand *current = WBT_GetCurrentCommand(work);
370     if (current)
371     {
372         /* Increment the command counter (avoid 0) */
373         if (++work->my_command_counter == 0)
374         {
375             ++work->my_command_counter;
376         }
377         current->my_cmd_counter = work->my_command_counter;
378 
379         /* Initialization processing for each command */
380         switch (current->command)
381         {
382 
383         case WBT_CMD_REQ_GET_BLOCK:
384         case WBT_CMD_REQ_GET_BLOCKINFO:
385             /* Initialize the bitmap */
386             {
387                 int     aid;
388                 for (aid = 0; aid < 16; ++aid)
389                 {
390                     if ((current->target_bmp & (1 << aid)) != 0)
391                     {
392                         WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
393                         WBTi_InitBitmap(work, pkt_bmp, (int)current->get.recv_data_size,
394                                         current->get.pkt_bmp_table.packet_bitmap[aid],
395                                         current->get.recv_buf_table.recv_buf[aid],
396                                         work->peer_data_packet_size);
397                         pkt_bmp->current = 0;
398                     }
399                 }
400             }
401             break;
402 
403         case WBT_CMD_REQ_SYNC:
404         case WBT_CMD_REQ_USER_DATA:
405             /* Unnecessary initialization commands */
406             break;
407 
408         default:
409             /* Commands that should not be possible */
410             current->command = WBT_CMD_REQ_NONE;
411             break;
412 
413         }
414         retval = (current->command != WBT_CMD_REQ_NONE);
415     }
416 }
417 
418 /*---------------------------------------------------------------------------*
419   Name:         WBTi_NotifySystemCallback
420 
421   Description:  System callback notification.
422 
423   Arguments:    work: WBT structure
424                 event: Event type
425                 aid: In the case of a requested receive event, the other party's AID
426                 result: Processing result
427 
428   Returns:      None.
429  *---------------------------------------------------------------------------*/
WBTi_NotifySystemCallback(WBTContext * work,WBTCommandType event,int aid,WBTResult result)430 static void WBTi_NotifySystemCallback(WBTContext * work, WBTCommandType event, int aid,
431                                       WBTResult result)
432 {
433     BOOL    retval = TRUE;
434     WBTRecvToken *peer = &work->peer_param[aid].recv_token;
435 
436     /* For anything other than WBT_CMD_PREPARE_SEND_DATA, only notify once */
437     if ((event != WBT_CMD_PREPARE_SEND_DATA) &&
438         (peer->token_peer_cmd_counter == peer->last_peer_cmd_counter))
439     {
440         retval = FALSE;
441     }
442     /*
443      * Because the GetBlockInfo function uses the GetBlock function in the library, it is not necessary (and is not allowed) to notify the application of completion of this internal processing
444      *
445      */
446     else if ((event == WBT_CMD_REQ_GET_BLOCK_DONE) &&
447              (peer->token_block_id < WBT_NUM_MAX_BLOCK_INFO_ID))
448     {
449         retval = FALSE;
450     }
451     /* If necessary, generate a system callback */
452     if (retval)
453     {
454         WBTCommand *cmd = &work->system_cmd;
455         peer->last_peer_cmd_counter = peer->token_peer_cmd_counter;
456         cmd->peer_cmd_counter = peer->token_peer_cmd_counter;   /* For debugging */
457         cmd->result = result;
458         cmd->event = event;
459         cmd->command = WBT_CMD_SYSTEM_CALLBACK;
460         cmd->peer_bmp = (u16)(1 << aid);
461         /* New specifications */
462         if (work->callback)
463         {
464             work->callback(work->userdata, cmd);
465         }
466         /* Old specifications */
467         else if (cmd->callback)
468         {
469             (*cmd->callback) (cmd);
470         }
471     }
472 }
473 
474 
475 /*****************************************************************************
476  * Packet Transmission
477  *****************************************************************************/
478 
479 PLATFORM_ATTRIBUTE_INLINE
WBTi_MakeCommandHeader(void * dst,u8 cmd,int target,u8 counter)480     WBTPacketFormat * WBTi_MakeCommandHeader(void *dst, u8 cmd, int target, u8 counter)
481 {
482     WBTPacketFormat *format = (WBTPacketFormat *) dst;
483     MI_StoreLE8(&format->header.command, cmd);
484     MI_StoreLE16(&format->header.bitmap, (u16)target);
485     MI_StoreLE8(&format->header.counter, counter);
486     return format;
487 }
488 
489 /*---------------------------------------------------------------------------*
490   Name:         WBTi_TryCreateResponse
491 
492   Description:  Generates a response if a request is currently being received.
493 
494   Arguments:    work: WBT structure
495                 aid: Other party's AID
496                 buf: Buffer for creating a send command
497                 size: Buffer size
498                 command: Command that verifies the response
499                 foroce_blockinfo: TRUE if there is a response, even if the specified ID does not exist
500 
501   Returns:      The packet length of the response, if it could be generated, and 0 otherwise.
502  *---------------------------------------------------------------------------*/
503 static
WBTi_TryCreateResponse(WBTContext * work,int aid,void * buf,int size,int command,BOOL foroce_blockinfo)504     int WBTi_TryCreateResponse(WBTContext * work, int aid, void *buf, int size, int command,
505                                BOOL foroce_blockinfo)
506 {
507     int     ret_size = 0;
508     WBTRecvToken *token = &work->peer_param[aid].recv_token;
509     BOOL    done = FALSE;
510     (void)size;
511     if (command == WBT_CMD_REQ_SYNC)
512     {
513         WBTPacketFormat *format = WBTi_MakeCommandHeader(buf, WBT_CMD_RES_SYNC, (1 << aid),
514                                                          token->token_peer_cmd_counter);
515         /* Be cautious of the fact that the transmission destination is the standard for distinguishing between oneself and others */
516         MI_StoreLE16(&format->res_sync.block_total, (u16)WBT_GetRegisteredCount(work));
517         MI_StoreLE16(&format->res_sync.peer_packet, (u16)work->my_data_packet_size);
518         MI_StoreLE16(&format->res_sync.own_packet, (u16)work->peer_data_packet_size);
519         ret_size = (int /* Temporary */ )sizeof(format->header) + sizeof(format->res_sync);
520         done = TRUE;
521     }
522     else if (command == WBT_CMD_REQ_GET_BLOCK_DONE)
523     {
524         u32     id = token->token_block_id;
525         WBTPacketFormat *format =
526             WBTi_MakeCommandHeader(buf, WBT_CMD_RES_GET_BLOCK_DONE, (1 << aid),
527                                    token->token_peer_cmd_counter);
528         MI_StoreLE32(&format->res_getblock_done.id, id);
529         ret_size = (int /* Temporary */ )sizeof(format->header) + sizeof(format->res_getblock_done);
530         done = TRUE;
531         WBT_DEBUG_OUTPUT1("send BlockDone to %d id = %d\n", aid, id);
532     }
533     else if (command == WBT_CMD_REQ_USER_DATA)
534     {
535         WBTPacketFormat *format = WBTi_MakeCommandHeader(buf, WBT_CMD_RES_USER_DATA, (1 << aid),
536                                                          token->token_peer_cmd_counter);
537         ret_size = (int /* Temporary */ )sizeof(format->header);
538         done = TRUE;
539     }
540     else if (command == WBT_CMD_REQ_GET_BLOCK)
541     {
542         /*
543          * Currently, if the requested block does not exist, nothing is done.
544          * Establishing a new error and sending notification would also be acceptable.
545          */
546         u32     id = token->token_block_id;
547         /* Even for id < 1000, block information is not returned here */
548         WBTBlockInfoList *list = work->list;
549         for (; list != NULL; list = list->next)
550         {
551             if (list->data_info.id == id)
552             {
553                 break;
554             }
555         }
556         if (list)
557         {
558             /*
559              * Calculate the appropriate response index corresponding to the block request.
560              * Because it is easy for request contents to be duplicated due to MP communications information delays, manage the response history on the responding side and avoid duplicates in the past two responses.
561              *
562              */
563             s32     index = token->token_block_seq_no;
564             s32     block_seq_no;
565             /* Respond with the specified index as is for GetBlockInfo requests */
566             if (id >= WBT_NUM_MAX_BLOCK_INFO_ID)
567             {
568                 /*
569                  * Search for the specified block.
570                  * CAUTION!
571                  *     This determination is already made at the one location where this function is called.
572                  *     It is therefore impossible for this function to return -1!
573                  */
574                 /* Take the response history into account in the case of blocks that recently responded */
575                 if (id == work->last_block_id)
576                 {
577                     const int index_total =
578                         (list->data_info.block_size + work->my_data_packet_size -
579                          1) / work->my_data_packet_size;
580                     int     i;
581                     /* Search for the most recent indices, which do not exist in the response history */
582                     for (i = 0; (i < 3) && ((index == work->last_seq_no_1) ||
583                                             (index == work->last_seq_no_2)); ++i)
584                     {
585                         if (++index >= index_total)
586                         {
587                             index = 0;
588                         }
589                     }
590                 }
591                 /*
592                  * Record the contents of the current response in the response history.
593                  * CAUTION!
594                  *     In this implementation, the index of an unrelated block from the previous cycle is also unfortunately retained, in last_seq_no_2.
595                  *
596                  */
597                 work->last_block_id = id;
598                 work->last_seq_no_2 = work->last_seq_no_1;
599                 work->last_seq_no_1 = index;
600             }
601             block_seq_no = index;
602 
603             {
604                 u32     packet = work->my_data_packet_size;
605                 u8     *data_ptr = NULL;
606                 BOOL    sendable = FALSE;
607                 if (list->data_ptr)
608                 {
609                     data_ptr = WBTi_GetPacketBuffer(work, id, block_seq_no);
610                     WBT_DEBUG_OUTPUT1("send BlockData to %d id = %d seq no = %d pktsize %d\n", aid,
611                                       id, index, packet);
612                     sendable = TRUE;
613                 }
614                 else if (list->block_type == WBT_BLOCK_LIST_TYPE_USER)
615                 {
616                     /* Notification to bring the data packet preparation to the user's attention */
617                     WBTCommand *system_cmd = &work->system_cmd;
618                     system_cmd->prepare_send_data.block_id = id;
619                     system_cmd->prepare_send_data.block_seq_no = block_seq_no;
620                     system_cmd->prepare_send_data.own_packet_size = (s16)packet;
621                     system_cmd->prepare_send_data.data_ptr = NULL;
622                     WBTi_NotifySystemCallback(work, WBT_CMD_PREPARE_SEND_DATA, aid,
623                                               WBT_RESULT_SUCCESS);
624                     WBT_DEBUG_OUTPUT1("peer req seq no  = %d seq no = %d dataptr = %p\n", index,
625                                       block_seq_no, system_cmd->prepare_send_data.data_ptr);
626                     if (system_cmd->prepare_send_data.data_ptr != NULL)
627                     {
628                         id = system_cmd->prepare_send_data.block_id;
629                         block_seq_no = system_cmd->prepare_send_data.block_seq_no;
630                         data_ptr = system_cmd->prepare_send_data.data_ptr;
631                         packet = system_cmd->prepare_send_data.own_packet_size;
632                         sendable = TRUE;
633                     }
634                 }
635                 /* Send if the data has been prepared */
636                 if (sendable)
637                 {
638                     /* CAUTION! This calculation of the transmission destination bitmap is apparently only provisional processing */
639                     u16     target = (u16)((WBT_GetAid(work) == WBT_AID_PARENT) ? 0xFFFE : 0x0001);
640                     WBTPacketFormat *format =
641                         WBTi_MakeCommandHeader(buf, WBT_CMD_RES_GET_BLOCK, target,
642                                                token->token_peer_cmd_counter);
643                     MI_StoreLE32(&format->res_getblock.id, id);
644                     MI_StoreLE32(&format->res_getblock.index, (u32)block_seq_no);
645                     WBTi_CopySafeMemory(data_ptr, &format->res_getblock + 1, (u32)packet);
646                     ret_size = (int /* Temporary */ )(sizeof(format->header) +
647                                                      sizeof(format->res_getblock) + packet);
648                     done = TRUE;
649                 }
650             }
651         }
652     }
653     else if (command == WBT_CMD_REQ_GET_BLOCKINFO)
654     {
655         u32     id = token->token_block_id;
656         s32     index = token->token_block_seq_no;
657         int     packet = work->my_data_packet_size;
658         u8     *data_ptr = WBTi_GetPacketBuffer(work, id, index);
659         WBT_DEBUG_OUTPUT1("send BlockData to %d id = %d seq no = %d pktsize %d\n", aid, id, index,
660                           packet);
661         /*
662          * CAUTION!
663          *     It is possible for data_ptr to become NULL, but only if there are no blocks for the specified ID.
664          *     In that case, wouldn't it be better to return a callback or always send 0 data?
665          *     This is currently being revised in HEAD!
666          */
667         if (foroce_blockinfo || data_ptr)
668         {
669             /* CAUTION! This calculation of the transmission destination bitmap is apparently only provisional processing */
670             u16     target = (u16)((WBT_GetAid(work) == 0) ? 0xFFFF : 0x0001);
671             WBTPacketFormat *format = WBTi_MakeCommandHeader(buf, WBT_CMD_RES_GET_BLOCKINFO, target,
672                                                              token->token_peer_cmd_counter);
673             MI_StoreLE32(&format->res_getblock.id, id);
674             MI_StoreLE32(&format->res_getblock.index, (u32)index);
675             WBTi_CopySafeMemory(data_ptr, &format->res_getblock + 1, (u32)packet);
676             ret_size = (int /* Temporary */ )(sizeof(format->header) + sizeof(format->res_getblock) +
677                                              packet);
678             done = TRUE;
679         }
680     }
681 
682     /* Destroy the response content after responding */
683     if (done)
684     {
685         work->req_bitmap &= ~(1 << aid);
686     }
687     return ret_size;
688 }
689 
690 /*---------------------------------------------------------------------------*
691   Name:         WBTi_CheckRequest
692 
693   Description:  Generate one's own command request.
694 
695   Arguments:    work: WBT structure
696                 buffer: Buffer to store the data
697                 length: Buffer size
698 
699   Returns:      The size of the request, if it could be generated, and 0 otherwise.
700  *---------------------------------------------------------------------------*/
WBTi_CheckRequest(WBTContext * work,void * send_buf,int size)701 static int WBTi_CheckRequest(WBTContext * work, void *send_buf, int size)
702 {
703     int     send_size = 0;
704     WBTCommand *current = WBT_GetCurrentCommand(work);
705     (void)size;
706     if (current)
707     {
708         switch (current->command)
709         {
710         case WBT_CMD_REQ_SYNC:
711             {
712                 WBTPacketFormat *format =
713                     WBTi_MakeCommandHeader(send_buf, WBT_CMD_REQ_SYNC, current->target_bmp,
714                                            current->my_cmd_counter);
715                 /* Be cautious of the fact that the transmission destination is the standard for distinguishing between oneself and others */
716                 MI_StoreLE16(&format->req_sync.peer_packet, (u16)work->my_data_packet_size);
717                 MI_StoreLE16(&format->req_sync.own_packet, (u16)work->peer_data_packet_size);
718                 send_size = (int /* Temporary */ )sizeof(format->header) + sizeof(format->req_sync);
719                 WBT_DEBUG_OUTPUT0("send ReqSync to 0x%04x cmd counter %d\n",
720                                   current->target_bmp, current->my_cmd_counter);
721             }
722             break;
723         case WBT_CMD_REQ_GET_BLOCK:
724         case WBT_CMD_REQ_GET_BLOCKINFO:
725             {
726                 int     aid;
727                 for (aid = 0; aid < 16; ++aid)
728                 {
729                     /* Confirm that this is the partner that should be requested */
730                     if ((current->target_bmp & (1 << aid)) != 0)
731                     {
732                         WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
733                         s32     next_seq_no = WBTi_FindBitmapIndex(pkt_bmp);
734                         /* BlockDone if reception is complete */
735                         if (next_seq_no == -1)
736                         {
737                             WBTPacketFormat *format =
738                                 WBTi_MakeCommandHeader(send_buf, WBT_CMD_REQ_GET_BLOCK_DONE,
739                                                        (1 << aid), current->my_cmd_counter);
740                             MI_StoreLE32(&format->req_getblock_done.id, current->get.block_id);
741                             send_size = (int /* Temporary */ )sizeof(format->header) +
742                                 sizeof(format->req_getblock_done);
743                             WBT_DEBUG_OUTPUT0("send ReqBlockDone to %d 0x%04x\n", aid, (1 << aid));
744                         }
745                         /* Request the next block if reception is not complete */
746                         else
747                         {
748                             WBTPacketFormat *format =
749                                 WBTi_MakeCommandHeader(send_buf, current->command,
750                                                        current->target_bmp,
751                                                        current->my_cmd_counter);
752                             MI_StoreLE32(&format->req_getblock.id, current->get.block_id);
753                             MI_StoreLE32(&format->req_getblock.index, (u32)next_seq_no);
754                             send_size = (int /* Temporary */ )sizeof(format->header) +
755                                 sizeof(format->req_getblock);
756                             WBT_DEBUG_OUTPUT1("send ReqBlock id=%d seq=%d\n", current->get.block_id,
757                                               next_seq_no);
758                         }
759                         if (send_size)
760                         {
761                             break;
762                         }
763                     }
764                 }
765             }
766             break;
767 
768         case WBT_CMD_REQ_USER_DATA:
769             {
770                 WBTPacketFormat *format =
771                     WBTi_MakeCommandHeader(send_buf, WBT_CMD_REQ_USER_DATA, current->target_bmp,
772                                            current->my_cmd_counter);
773                 MI_StoreLE8(&format->req_userdata.length, current->user_data.size);
774                 MI_CpuCopy8(current->user_data.data, &format->req_userdata.buffer,
775                             WBT_SIZE_USER_DATA);
776                 send_size =
777                     (int /* Temporary */ )sizeof(format->header) + sizeof(format->req_userdata);
778             }
779             break;
780 
781         default:
782             WBT_DEBUG_OUTPUT0("Unknown User Command:Error %s %s %d\n", __FILE__, __FUNCTION__,
783                               __LINE__);
784             break;
785         }
786     }
787     return send_size;
788 }
789 
790 /*---------------------------------------------------------------------------*
791   Name:         WBTi_CheckBlockResponse
792 
793   Description:  Confirm requests in order from each AID, and generate appropriate block responses.
794 
795   Arguments:    work: WBT structure
796                 buffer: Buffer to store the data
797                 length: Buffer size
798 
799   Returns:      The size of the block response, if it could be generated, and 0 otherwise.
800  *---------------------------------------------------------------------------*/
WBTi_CheckBlockResponse(WBTContext * work,void * buffer,int length)801 static int WBTi_CheckBlockResponse(WBTContext * work, void *buffer, int length)
802 {
803     int     retval = 0;
804 
805     /* Determine the currently requested targets in order */
806     int     mask = work->req_bitmap;
807     if (!retval && (mask != 0))
808     {
809         int     aid = WBTi_GetFirstIterationAID(work);
810         do
811         {
812             aid = WBTi_GetNextIterationAID(aid, mask);
813             if ((work->req_bitmap & (1 << aid)) != 0)
814             {
815                 WBTRecvToken *token = &work->peer_param[aid].recv_token;
816                 if (WBT_CMD_REQ_GET_BLOCK == token->token_command)
817                 {
818                     /*
819                      * Attempt to create a response command.
820                      * For execution that has come here, the only things that return 0 are:
821                      * -WBT_CMD_REQ_GET_BLOCK
822                      *   -- There are no blocks for the specified ID.
823                      *   -- Preparations were not done in the PREPARE callback.
824                      *
825                      * However, even if there is no response for WBT_CMD_REQ_GET_BLOCK, execution will at least finish.
826                      *
827                      */
828                     retval =
829                         WBTi_TryCreateResponse(work, aid, buffer, length, WBT_CMD_REQ_GET_BLOCK,
830                                                FALSE);
831                 }
832                 if (retval)
833                 {
834                     work->last_target_aid = aid;
835                 }
836             }
837         }
838         while (aid != work->last_target_aid);
839     }
840 
841     if (!retval && (mask != 0))
842     {
843         int     aid = WBTi_GetFirstIterationAID(work);
844         do
845         {
846             aid = WBTi_GetNextIterationAID(aid, mask);
847             if ((work->req_bitmap & (1 << aid)) != 0)
848             {
849                 WBTRecvToken *token = &work->peer_param[aid].recv_token;
850                 if (WBT_CMD_REQ_GET_BLOCKINFO == token->token_command)
851                 {
852                     retval =
853                         WBTi_TryCreateResponse(work, aid, buffer, length, WBT_CMD_REQ_GET_BLOCKINFO,
854                                                TRUE);
855                 }
856                 if (retval)
857                 {
858                     work->last_target_aid = aid;
859                 }
860             }
861         }
862         while (aid != work->last_target_aid);
863     }
864 
865     return retval;
866 }
867 
868 /*---------------------------------------------------------------------------*
869   Name:         WBT_CallPacketSendHook
870 
871   Description:  Hook function for generating the send packet data.
872 
873   Arguments:    work: WBT structure
874                 buffer: Buffer to store the data
875                 length: Buffer size
876 
877   Returns:      The generated packet size.
878  *---------------------------------------------------------------------------*/
WBT_CallPacketSendHook(WBTContext * work,void * buffer,int length,BOOL is_parent)879 int WBT_CallPacketSendHook(WBTContext * work, void *buffer, int length, BOOL is_parent)
880 {
881     int     retval = 0;
882 
883     if (work->last_target_aid == -1)
884     {
885         work->last_target_aid = (is_parent ? 1 : 0);
886     }
887 
888     /* Check for illegal arguments */
889     if (!buffer || (length <= 0))
890     {
891         return 0;
892     }
893 
894     /* Confirm requests from each AID in order, and generate appropriate responses */
895     {
896         /*
897          * CAUTION!
898          *     If the response generation priority is (AID order > command), isn't a single determination reasonable because duplicate commands from the same AID are not accepted?
899          *
900          *
901          */
902         static const WBTCommandType tbl[] = {
903             WBT_CMD_REQ_USER_DATA,
904             WBT_CMD_REQ_SYNC,
905             WBT_CMD_REQ_GET_BLOCKINFO,
906             WBT_CMD_REQ_GET_BLOCK_DONE,
907             WBT_CMD_REQ_NONE,
908         };
909         /* Determine the currently requested targets in order */
910         int     mask = work->req_bitmap;
911         if (mask != 0)
912         {
913             int     aid = WBTi_GetFirstIterationAID(work);
914             do
915             {
916                 aid = WBTi_GetNextIterationAID(aid, mask);
917                 if ((mask & (1 << aid)) != 0)
918                 {
919                     /*
920                      * Attempt to create a response command.
921                      * For execution that has come here, the only things that return 0 are:
922                      * - WBT_CMD_REQ_GET_BLOCKINFO
923                      *   -- There are no blocks for the specified ID, and "force" is not used.
924                      *
925                      */
926                     WBTRecvToken *token = &work->peer_param[aid].recv_token;
927                     int     i;
928                     for (i = 0; !retval && (tbl[i] != WBT_CMD_REQ_NONE); ++i)
929                     {
930                         /* WBT_CMD_REQ_*** */
931                         if (tbl[i] == token->token_command)
932                         {
933                             retval =
934                                 WBTi_TryCreateResponse(work, aid, buffer, length, tbl[i], FALSE);
935                         }
936                     }
937                     if (retval)
938                     {
939                         work->last_target_aid = aid;
940                     }
941                 }
942             }
943             while (aid != work->last_target_aid);
944         }
945     }
946 
947 
948     if (!retval)
949     {
950         /*
951          * A parent device's command priority is:
952          *   (1) General response (unregistered GetBlockInfo is ignored)
953          *   (2) Requests from the local host
954          *   (3) Block response (unregistered GetBlockInfo is also forcibly responded to)
955          *   (4) (Wait)
956          */
957         if (is_parent)
958         {
959             /*
960              * 0 is returned here in the following cases.
961              * - When no command is being issued.
962              */
963             retval = WBTi_CheckRequest(work, buffer, length);
964             if (!retval)
965             {
966                 retval = WBTi_CheckBlockResponse(work, buffer, length);
967             }
968         }
969         /*
970          * A child device's command priority is:
971          *   (1) General response (unregistered GetBlockInfo is ignored)
972          *   (3) Block response (unregistered GetBlockInfo is also forcibly responded to)
973          *   (2) Requests from the local host
974          *   (4) (Wait)
975          */
976         else
977         {
978             retval = WBTi_CheckBlockResponse(work, buffer, length);
979             if (!retval)
980             {
981                 /*
982                  * 0 is returned here in the following cases.
983                  * - When no command is being issued.
984                  */
985                 retval = WBTi_CheckRequest(work, buffer, length);
986             }
987         }
988         if (!retval)
989         {
990             /* A WAIT command is always sent when the counter is 0 */
991             int     mask = (is_parent ? 0xFFFE : 0x0001);
992             WBTPacketFormat *format =
993                 WBTi_MakeCommandHeader(buffer, WBT_CMD_REQ_WAIT, (u16)mask, (WBTCommandCounter)0);
994             retval = (int /* Temporary */ )sizeof(format->header);
995         }
996     }
997 
998     return retval;
999 }
1000 
1001 
1002 /*****************************************************************************
1003  * Packet Reception
1004  *****************************************************************************/
1005 
1006 /*---------------------------------------------------------------------------*
1007   Name:         WBTi_NotifyCompletionCallback
1008 
1009   Description:  Notification of user command completion.
1010 
1011   Arguments:    work: WBT structure
1012                 event: Event type
1013                 aid: AID of the other party that has completed the command
1014 
1015   Returns:      None.
1016  *---------------------------------------------------------------------------*/
WBTi_NotifyCompletionCallback(WBTContext * work,WBTCommandType event,int aid)1017 static void WBTi_NotifyCompletionCallback(WBTContext * work, WBTCommandType event, int aid)
1018 {
1019     WBTCommandList *list = WBT_GetCurrentCommandList(work);
1020     WBTCommand *current = WBT_GetCurrentCommand(work);
1021     WBTRecvToken *token = &work->peer_param[aid].recv_token;
1022     /* A notification is only generated once */
1023     if ((current != NULL) &&
1024         (current->my_cmd_counter == token->token_peer_cmd_counter))
1025     {
1026         int     peer_bmp = (1 << aid);
1027         current->peer_cmd_counter = token->token_peer_cmd_counter;
1028         current->peer_bmp = (u16)peer_bmp;      /* For debugging */
1029         if ((current->target_bmp & peer_bmp) != 0)
1030         {
1031             /* This is a completion notification, so it's always "SUCCESS." (Errors are notified to a system callback) */
1032             current->target_bmp &= ~peer_bmp;
1033             current->event = event;
1034             current->result = WBT_RESULT_SUCCESS;
1035             /* New specifications */
1036             if (list->callback)
1037             {
1038                 list->callback(work->userdata, current);
1039             }
1040             /* Old specifications */
1041             else if (current->callback)
1042             {
1043                 current->callback(current);
1044             }
1045         }
1046         /* Delete the command if all targets have finished responding */
1047         if (current->target_bmp == 0)
1048         {
1049             WBTCommandList *list = work->command;
1050             work->command = list->next;
1051             WBT_AddCommandPool(work, list, 1);
1052             WBTi_SwitchNextCommand(work);
1053         }
1054     }
1055 }
1056 
1057 /*---------------------------------------------------------------------------*
1058   Name:         WBT_CallPacketRecvHook
1059 
1060   Description:  Parses the receive packet data.
1061 
1062   Arguments:    work: WBT structure
1063                 aid: Data sender's AID
1064                 buffer: Received data buffer
1065                 length: Length of the received data
1066 
1067   Returns:      None.
1068  *---------------------------------------------------------------------------*/
WBT_CallPacketRecvHook(WBTContext * work,int aid,const void * buffer,int length)1069 void WBT_CallPacketRecvHook(WBTContext * work, int aid, const void *buffer, int length)
1070 {
1071     WBTRecvToken *token = &work->peer_param[aid].recv_token;
1072 
1073     /* The previous reception state is always cleared here */
1074     work->req_bitmap &= ~(1 << aid);
1075 
1076     /* At the very least, the command header should always exist */
1077     if (buffer && (length >= sizeof(WBTPacketHeaderFormat)))
1078     {
1079         const WBTPacketFormat *format = (const WBTPacketFormat *)buffer;
1080 
1081         u8      command;
1082         u16     bitmap;
1083 
1084         command = MI_LoadLE8(&format->header.command);
1085         bitmap = MI_LoadLE16(&format->header.bitmap);
1086         token->token_peer_cmd_counter = MI_LoadLE8(&format->header.counter);
1087         token->token_command = command;
1088 
1089 
1090         /*
1091          * Perform command processing if the packet is addressed to the local host.
1092          * Note: Although these are if-else statements, we ultimately want to use a function table.
1093          */
1094         if ((WBT_GetAid(work) != -1) && ((bitmap & (1 << WBT_GetAid(work))) != 0))
1095         {
1096             /* Ignore unknown, out-of-range commands */
1097             if (command >= WBT_COMMAND_MAX)
1098             {
1099             }
1100             /* Ignore if the command's packet size does not satisfy the minimum length */
1101             else if (length < WBTi_CommandTable[command].packet)
1102             {
1103             }
1104             /** Request command */
1105             else if (WBTi_CommandTable[command].is_req)
1106             {
1107                 if (command == WBT_CMD_REQ_WAIT)
1108                 {
1109                 }
1110 
1111                 else if (command == WBT_CMD_REQ_SYNC)
1112                 {
1113                     WBTRequestSyncCallback *cb = &work->system_cmd.sync;
1114                     cb->peer_packet_size = (s16)MI_LoadLE16(&format->req_sync.peer_packet);
1115                     cb->my_packet_size = (s16)MI_LoadLE16(&format->req_sync.own_packet);
1116                     cb->num_of_list = 0;        /* In the old specifications, this is the only member not included in a request */
1117                     /* The child device always complies with the parent device's communication settings */
1118                     if (WBT_GetAid(work) != 0)
1119                     {
1120                         work->my_data_packet_size = cb->my_packet_size;
1121                         work->peer_data_packet_size = cb->peer_packet_size;
1122                     }
1123                     work->req_bitmap |= (1 << aid);
1124                 }
1125                 /* User-defined data request */
1126                 else if (command == WBT_CMD_REQ_USER_DATA)
1127                 {
1128                     WBTRecvUserDataCallback *cb = &work->system_cmd.user_data;
1129                     cb->size = MI_LoadLE8(&format->req_userdata.length);
1130                     if (cb->size > WBT_SIZE_USER_DATA)
1131                     {
1132                         cb->size = 0;
1133                     }
1134                     MI_CpuCopy8(format->req_userdata.buffer, cb->data, cb->size);
1135                     work->req_bitmap |= (1 << aid);
1136                 }
1137                 /* Block information request or block request (same format) */
1138                 else if ((command == WBT_CMD_REQ_GET_BLOCK) ||
1139                          (command == WBT_CMD_REQ_GET_BLOCKINFO))
1140                 {
1141                     token->token_block_id = MI_LoadLE32(&format->req_getblock.id);
1142                     token->token_block_seq_no = (s32)MI_LoadLE32(&format->req_getblock.index);
1143                     work->req_bitmap |= (1 << aid);
1144                     WBT_DEBUG_OUTPUT1("get req Block from %d id = %d seq no = %d\n", aid, token->token_block_id,
1145                                       token->token_block_seq_no);
1146                 }
1147                 /* Notification that reception of a block has completed */
1148                 else if (command == WBT_CMD_REQ_GET_BLOCK_DONE)
1149                 {
1150                     WBTGetBlockDoneCallback *cb = &work->system_cmd.blockdone;
1151                     cb->block_id = MI_LoadLE32(&format->req_getblock_done.id);
1152                     // It is also possible for a completion notification to be sent without a request ever being sent. This happens when a child piggy-backs on another child's currently executing request to the same ID
1153                     //
1154                     token->token_block_id = MI_LoadLE32(&format->req_getblock_done.id);
1155                     work->req_bitmap |= (1 << aid);
1156                 }
1157             }
1158 
1159             /* Response command */
1160             else if (WBTi_CommandTable[command].is_res)
1161             {
1162                 WBTCommand *current = WBT_GetCurrentCommand(work);
1163 
1164                 /* Ignore if not currently requesting a command */
1165                 if (!current)
1166                 {
1167                 }
1168                 /*
1169                  * CAUTION!
1170                  *     Although we would like to unify the processes which determine whether or not REQ_ and RES_ have been dealt with, GetBlock-related processes do not have a one-to-one correspondence and therefore we have not addressed this yet
1171                  *
1172                  *     (1) WBT_CMD_RES_GET_BLOCK / WBT_CMD_REQ_GET_BLOCK
1173                  *     (2) WBT_CMD_RES_GET_BLOCKINFO / WBT_CMD_REQ_GET_BLOCKINFO
1174                  *     (3) WBT_CMD_RES_GET_BLOCK_DONE / WBT_CMD_REQ_GET_BLOCK, WBT_CMD_REQ_GET_BLOCKINFO
1175                  *     What ought to be done when sending WBT_CMD_REQ_GET_BLOCK_DONE?
1176                  */
1177                 else
1178                 {
1179                     /* Synchronous response */
1180                     if (command == WBT_CMD_RES_SYNC)
1181                     {
1182                         if (current->command == WBT_CMD_REQ_SYNC)
1183                         {
1184                             current->sync.num_of_list =
1185                                 (s16)MI_LoadLE16(&format->res_sync.block_total);
1186                             current->sync.peer_packet_size =
1187                                 (s16)MI_LoadLE16(&format->res_sync.peer_packet);
1188                             current->sync.my_packet_size =
1189                                 (s16)MI_LoadLE16(&format->res_sync.own_packet);
1190 
1191                             /* The child device always complies with the parent device's communication settings */
1192                             if (WBT_GetAid(work) != 0)
1193                             {
1194                                 work->my_data_packet_size = current->sync.my_packet_size;
1195                                 work->peer_data_packet_size = current->sync.peer_packet_size;
1196                             }
1197                             WBT_DEBUG_OUTPUT0("Get res Sync from %d my %d peer %d\n", aid,
1198                                               current->sync.my_packet_size,
1199                                               current->sync.peer_packet_size);
1200                             WBTi_NotifyCompletionCallback(work, (WBTCommandType)command, aid);
1201                         }
1202                     }
1203                     /* Completion notification */
1204                     else if (command == WBT_CMD_RES_USER_DATA)
1205                     {
1206                         if (current->command == WBT_CMD_REQ_USER_DATA)
1207                         {
1208                             WBTi_NotifyCompletionCallback(work, (WBTCommandType)command, aid);
1209                         }
1210                     }
1211                     /* Block response */
1212                     else if ((command == WBT_CMD_RES_GET_BLOCK) ||
1213                              (command == WBT_CMD_RES_GET_BLOCKINFO))
1214                     {
1215                         if ((current->command == WBT_CMD_REQ_GET_BLOCK) ||
1216                             (current->command == WBT_CMD_REQ_GET_BLOCKINFO))
1217                         {
1218                             u32     id = MI_LoadLE32(&format->res_getblock.id);
1219                             s32     index = (s32)MI_LoadLE32(&format->res_getblock.index);
1220 
1221                             /* Determine whether or not this matches the requested ID */
1222                             if (id == current->get.block_id)
1223                             {
1224                                 /* Determine whether the response is from the request location */
1225                                 if ((current->target_bmp & (1 << aid)) != 0)
1226                                 {
1227                                     /* Determine whether the index is in range */
1228                                     WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
1229                                     if (index >= pkt_bmp->total)
1230                                     {
1231                                         WBT_DEBUG_OUTPUT1
1232                                             ("%s num of seq over seq no = %d total = %d\n",
1233                                              __FUNCTION__, index, pkt_bmp->total);
1234                                         /* Save failed */
1235                                         WBTi_NotifySystemCallback(work, WBT_CMD_RES_ERROR, aid,
1236                                                                   WBT_RESULT_ERROR_SAVE_FAILURE);
1237                                     }
1238                                     else
1239                                     {
1240                                         /* If the data is not yet received, store */
1241                                         const void *src = (const u8 *)format +
1242                                             sizeof(format->header) + sizeof(format->res_getblock);
1243                                         u32     packet = (u32)work->peer_data_packet_size;
1244                                         if (WBTi_MergeBitmapIndex(pkt_bmp, index, packet, src))
1245                                         {
1246                                             pkt_bmp->current = index;
1247                                         }
1248                                     }
1249                                 }
1250                             }
1251                         }
1252                     }
1253                     /* Notification that reception of a block has completed */
1254                     else if (command == WBT_CMD_RES_GET_BLOCK_DONE)
1255                     {
1256                         /* Completion notification if the response is the correct one corresponding to the current request */
1257                         if ((current->command == WBT_CMD_REQ_GET_BLOCK) ||
1258                             (current->command == WBT_CMD_REQ_GET_BLOCKINFO))
1259                         {
1260                             u32     id = MI_LoadLE32(&format->res_getblock_done.id);
1261                             if (current->get.block_id == id)
1262                             {
1263                                 WBT_DEBUG_OUTPUT1
1264                                     ("get block my cmd counter = %d peer cmd counter = %d\n",
1265                                      current->my_cmd_counter, token->token_peer_cmd_counter);
1266                                 WBTi_NotifyCompletionCallback(work,
1267                                                               (current->command ==
1268                                                                WBT_CMD_REQ_GET_BLOCK) ?
1269                                                               WBT_CMD_RES_GET_BLOCK :
1270                                                               WBT_CMD_RES_GET_BLOCKINFO, aid);
1271                             }
1272                             WBT_DEBUG_OUTPUT0("c usr cmd tbmp 0x%x\n", current->target_bmp);
1273                         }
1274                     }
1275                 }
1276             }
1277 
1278             /* Not supported or an illegal command */
1279             else
1280             {
1281                 WBTi_NotifySystemCallback(work, WBT_CMD_RES_ERROR, aid,
1282                                           WBT_RESULT_ERROR_UNKNOWN_PACKET_COMMAND);
1283             }
1284 
1285         }
1286 
1287         /* System callback if a request is received */
1288         if ((work->req_bitmap & (1 << aid)) != 0)
1289         {
1290             /* However, do not send notifications for GetBlock* commands, because they are received numerous times */
1291             if ((command != WBT_CMD_REQ_GET_BLOCK) && (command != WBT_CMD_REQ_GET_BLOCKINFO))
1292             {
1293                 WBTi_NotifySystemCallback(work, (WBTCommandType)command, aid, WBT_RESULT_SUCCESS);
1294             }
1295         }
1296 
1297     }
1298 }
1299 
1300 /*---------------------------------------------------------------------------*
1301   Name:         WBT_InitContext
1302 
1303   Description:  Initializes the WBT structure.
1304 
1305   Arguments:    work: WBT structure
1306                 userdata: Any user-defined value
1307                 callback: System callback
1308 
1309   Returns:      None.
1310  *---------------------------------------------------------------------------*/
WBT_InitContext(WBTContext * work,void * userdata,WBTEventCallback callback)1311 void WBT_InitContext(WBTContext * work, void *userdata, WBTEventCallback callback)
1312 {
1313     work->userdata = userdata;
1314     work->callback = callback;
1315 
1316     /* Initialization of transmission history for block transfers */
1317     work->last_block_id = (u32)-1;
1318     work->last_seq_no_1 = -1;
1319     work->last_seq_no_2 = -1;
1320 
1321     /* Initialize command management */
1322     work->command = NULL;
1323     work->command_pool = NULL;
1324     work->my_command_counter = 0;
1325     work->last_target_aid = -1;
1326     work->req_bitmap = 0;
1327     MI_CpuFill8(&work->system_cmd, 0x00, sizeof(work->system_cmd));
1328     MI_CpuFill8(work->peer_param, 0x00, sizeof(work->peer_param));
1329 
1330     /* Clear the command list */
1331     WBT_ResetContext(work, callback);
1332 }
1333 
1334 /*---------------------------------------------------------------------------*
1335   Name:         WBT_ResetContext
1336 
1337   Description:  Reinitializes a WBT structure.
1338 
1339   Arguments:    work: WBT structure
1340                 callback: System callback
1341 
1342   Returns:      None.
1343  *---------------------------------------------------------------------------*/
WBT_ResetContext(WBTContext * work,WBTEventCallback callback)1344 void WBT_ResetContext(WBTContext * work, WBTEventCallback callback)
1345 {
1346     int     i;
1347 
1348     work->my_aid = -1;
1349     work->peer_data_packet_size = 0;
1350     work->my_data_packet_size = 0;
1351 
1352     work->list = NULL;
1353     work->callback = callback;
1354 
1355     /* Destroy all commands */
1356     while (work->command)
1357     {
1358         WBTCommandList *list = work->command;
1359         work->command = list->next;
1360         list->command.command = WBT_CMD_REQ_NONE;
1361     }
1362 
1363     work->system_cmd.command = WBT_CMD_REQ_NONE;
1364     work->system_cmd.target_bmp = 0;
1365     work->system_cmd.peer_bmp = 0;
1366 
1367     for (i = 0; i < 16; ++i)
1368     {
1369         work->peer_param[i].recv_token.last_peer_cmd_counter = 0;
1370     }
1371 
1372 }
1373 
1374 /*---------------------------------------------------------------------------*
1375   Name:         WBT_PostCommand
1376 
1377   Description:  Issues a command and adds it to the command queue.
1378 
1379   Arguments:    work: WBT structure
1380                 cmd: Structure that stores the command information.
1381                      Managed in the library until the command is completed.
1382                 bitmap: AID bitmap corresponding to the command issue
1383                 callback: Command completion callback. NULL if not used
1384 
1385   Returns:      None.
1386  *---------------------------------------------------------------------------*/
WBT_PostCommand(WBTContext * work,WBTCommandList * list,u16 bitmap,WBTEventCallback callback)1387 void WBT_PostCommand(WBTContext *work, WBTCommandList *list, u16 bitmap,
1388                      WBTEventCallback callback)
1389 {
1390     PLATFORM_ENTER_CRITICALSECTION();
1391     {
1392         if (list)
1393         {
1394             /* Add to the end of the list */
1395             WBTCommandList **pp;
1396             for (pp = &work->command; *pp; pp = &(*pp)->next)
1397             {
1398             }
1399             *pp = list;
1400             list->next = NULL;
1401             list->command.target_bmp = bitmap;
1402             list->callback = callback;
1403             /* If new command comes during idle, begin processing here */
1404             if (work->command == list)
1405             {
1406                 WBTi_SwitchNextCommand(work);
1407             }
1408         }
1409     }
1410     PLATFORM_LEAVE_CRITICALSECTION();
1411 }
1412 
1413 /*---------------------------------------------------------------------------*
1414   Name:         WBT_CancelCommand
1415 
1416   Description:  Cancels the currently processing command.
1417 
1418   Arguments:    work: WBT structure
1419                 bitmap: Peer that will cancel the command
1420 
1421   Returns:      The bitmap that indicates the peer that will actually cancel the command.
1422  *---------------------------------------------------------------------------*/
WBT_CancelCommand(WBTContext * work,int bitmap)1423 int WBT_CancelCommand(WBTContext * work, int bitmap)
1424 {
1425     PLATFORM_ENTER_CRITICALSECTION();
1426     {
1427         WBTCommandList *list = WBT_GetCurrentCommandList(work);
1428         WBTCommand *current = WBT_GetCurrentCommand(work);
1429         if (current)
1430         {
1431             int     aid;
1432             /* Cancellation notification for all AIDs that are currently processing */
1433             bitmap &= current->target_bmp;
1434             for (aid = 0;; ++aid)
1435             {
1436                 int     bit = (1 << aid);
1437                 if (bit > bitmap)
1438                 {
1439                     break;
1440                 }
1441                 if ((bit & bitmap) == 0)
1442                 {
1443                     bitmap &= ~bit;
1444                 }
1445                 /* New specifications */
1446                 else if (list->callback)
1447                 {
1448                     current->event = WBT_CMD_CANCEL;
1449                     current->target_bmp &= ~bit;
1450                     current->peer_bmp = (u16)bit;
1451                     list->callback(work->userdata, current);
1452                 }
1453                 /* Old specifications */
1454                 else if (current->callback)
1455                 {
1456                     current->event = WBT_CMD_CANCEL;
1457                     current->target_bmp &= ~bit;
1458                     current->peer_bmp = (u16)bit;
1459                     (*current->callback) (current);
1460                 }
1461             }
1462             /* Destroy the cancelled command (similar to WBTi_NotifyCompletionCallback) */
1463             if (current->target_bmp == 0)
1464             {
1465                 WBTCommandList *list = work->command;
1466                 work->command = list->next;
1467                 WBT_AddCommandPool(work, list, 1);
1468                 WBTi_SwitchNextCommand(work);
1469             }
1470         }
1471     }
1472     PLATFORM_LEAVE_CRITICALSECTION();
1473     return bitmap;
1474 }
1475 
1476 /*---------------------------------------------------------------------------*
1477   Name:         WBT_GetBitmapLength
1478 
1479   Description:  Gets the bitmap buffer size needed for the block transfer control.
1480 
1481   Arguments:    work: WBT structure
1482                 length: Maximum block size to be transferred
1483 
1484   Returns:      Size of the necessary bitmap buffer.
1485  *---------------------------------------------------------------------------*/
WBT_GetBitmapLength(const WBTContext * work,int length)1486 int WBT_GetBitmapLength(const WBTContext *work, int length)
1487 {
1488     int     packet = work->peer_data_packet_size;
1489     SDK_ASSERT(packet > 0);
1490     return (int)(sizeof(u32) * MATH_ROUNDUP(((length + packet - 1) / packet), 32));
1491 }
1492 
1493 /*---------------------------------------------------------------------------*
1494   Name:         WBT_GetDownloadProgress
1495 
1496   Description:  Gets the block transfer progress status.
1497 
1498   Arguments:    work: WBT structure
1499                 id: Receive block ID
1500                 aid: Recipient's AID
1501                 count: Storage location for the received packet count
1502                 total: Where the total number of packets is stored
1503 
1504   Returns:      None.
1505                 Returns 0 for both current and total if there is not block transfer status.
1506  *---------------------------------------------------------------------------*/
WBT_GetDownloadProgress(const WBTContext * work,u32 id,int aid,int * count,int * total)1507 void WBT_GetDownloadProgress(const WBTContext *work, u32 id, int aid, int *count, int *total)
1508 {
1509     const WBTCommand *current = WBT_GetCurrentCommand(work);
1510     if ((current != NULL) &&
1511         (current->command == WBT_CMD_REQ_GET_BLOCK) && (current->get.block_id == id))
1512     {
1513         const WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
1514         *count = pkt_bmp->count;
1515         *total = pkt_bmp->total;
1516     }
1517     else
1518     {
1519         *count = 0;
1520         *total = 0;
1521     }
1522 }
1523 
1524 /*---------------------------------------------------------------------------*
1525   Name:         WBT_SetPacketLength
1526 
1527   Description:  Changes the packet size.
1528                 Can only be used with the parent.
1529 
1530   Arguments:    work: WBT structure
1531                 own: Own MP send packet size
1532                 peer: Peer MP send packet size
1533 
1534   Returns:      Returns TRUE if the setting succeeds.
1535  *---------------------------------------------------------------------------*/
WBT_SetPacketLength(WBTContext * work,int own,int peer)1536 BOOL WBT_SetPacketLength(WBTContext * work, int own, int peer)
1537 {
1538     BOOL    retval = FALSE;
1539     WBTCommand *current;
1540 
1541     SDK_ASSERT(own >= WBT_PACKET_SIZE_MIN);
1542     SDK_ASSERT(peer >= WBT_PACKET_SIZE_MIN);
1543 
1544     current = WBT_GetCurrentCommand(work);
1545     /* Cannot change packet size while requesting a block transmission */
1546     if ((current == NULL) ||
1547         ((current->command != WBT_CMD_REQ_GET_BLOCK) &&
1548         (current->command != WBT_CMD_REQ_GET_BLOCKINFO)))
1549     {
1550         work->my_data_packet_size = (s16)(own - WBT_PACKET_SIZE_MIN);
1551         work->peer_data_packet_size = (s16)(peer - WBT_PACKET_SIZE_MIN);
1552     }
1553     return retval;
1554 }
1555 
1556 /*---------------------------------------------------------------------------*
1557   Name:         WBT_RegisterBlockInfo
1558 
1559   Description:  Newly registers data blocks.
1560 
1561   Arguments:    work: WBT structure
1562                 list: List structure used for registration.
1563                       Used by the library until deallocated with Unregister.
1564                 id: ID associated with the data block
1565                 userinfo: User-defined information associated with the data block.
1566                           This pointer's target is only referenced within this function.
1567                           A NULL can be designated here if unnecessary.
1568                 buffer: Buffer where the block data was stored.
1569                         When NULL is specified, the WBT_CMD_PREPARE_SEND_DATA callback sends notification from the library if needed.
1570 
1571                 length: Size of the block data.
1572                         This value must be correctly specified even when NULL is specified for 'buffer'.
1573 
1574 
1575   Returns:      FALSE if 'id' has already been registered or is smaller than WBT_BLOCK_ID_MIN.
1576  *---------------------------------------------------------------------------*/
1577 BOOL
WBT_RegisterBlockInfo(WBTContext * work,WBTBlockInfoList * list,u32 id,const void * userinfo,const void * buffer,int length)1578 WBT_RegisterBlockInfo(WBTContext * work, WBTBlockInfoList *list, u32 id,
1579                       const void *userinfo, const void *buffer, int length)
1580 {
1581     PLATFORM_ENTER_CRITICALSECTION();
1582     {
1583         WBTBlockInfoList **pp;
1584         for (pp = &work->list; *pp; pp = &((*pp)->next))
1585         {
1586             /* Return FALSE and exit if 'id' has already been registered with 'work' */
1587             if ((*pp)->data_info.id == id)
1588             {
1589                 OS_TWarning("block_id is registered already.");
1590                 return FALSE;
1591             }
1592         }
1593         *pp = list;
1594         list->next = NULL;
1595         list->data_info.id = id;
1596         list->data_info.block_size = length;
1597         WBTi_CopySafeMemory(userinfo, list->data_info.user_id, WBT_USER_ID_LEN);
1598         list->data_ptr = (void *)buffer;
1599         /* Currently unused members */
1600         list->permission_bmp = 0;
1601         list->block_type = (u16)(buffer ? WBT_BLOCK_LIST_TYPE_COMMON : WBT_BLOCK_LIST_TYPE_USER);
1602     }
1603     PLATFORM_LEAVE_CRITICALSECTION();
1604 
1605     return TRUE;
1606 }
1607 
1608 
1609 /*---------------------------------------------------------------------------*
1610   Name:         WBT_UnregisterBlockInfo
1611 
1612   Description:  Deallocates registered data blocks.
1613 
1614   Arguments:    work: WBT structure
1615                 id: ID associated with the data block to be deallocated
1616 
1617   Returns:      Either the deallocated list structure or NULL.
1618  *---------------------------------------------------------------------------*/
WBT_UnregisterBlockInfo(WBTContext * work,u32 id)1619 WBTBlockInfoList *WBT_UnregisterBlockInfo(WBTContext * work, u32 id)
1620 {
1621     WBTBlockInfoList *retval = NULL;
1622     {
1623         PLATFORM_ENTER_CRITICALSECTION();
1624         WBTBlockInfoList **pp;
1625         for (pp = &work->list; *pp; pp = &(*pp)->next)
1626         {
1627             if ((*pp)->data_info.id == id)
1628             {
1629                 retval = *pp;
1630                 *pp = (*pp)->next;
1631                 break;
1632             }
1633         }
1634         PLATFORM_LEAVE_CRITICALSECTION();
1635     }
1636     return retval;
1637 }
1638 
1639 /*---------------------------------------------------------------------------*
1640   Name:         WBT_GetRegisteredCount
1641 
1642   Description:  Gets the total number of registered data blocks.
1643 
1644   Arguments:    work: WBT structure
1645 
1646   Returns:      The total number of registered data blocks.
1647  *---------------------------------------------------------------------------*/
WBT_GetRegisteredCount(const WBTContext * work)1648 int WBT_GetRegisteredCount(const WBTContext * work)
1649 {
1650     int     n = 0;
1651     {
1652         PLATFORM_ENTER_CRITICALSECTION();
1653         WBTBlockInfoList *list = work->list;
1654         for (list = work->list; list; list = list->next)
1655         {
1656             ++n;
1657         }
1658         PLATFORM_LEAVE_CRITICALSECTION();
1659     }
1660     return n;
1661 }
1662 
1663 
1664 /*---------------------------------------------------------------------------*
1665   $Log: wbt_context.c,v $
1666   Revision 1.5  2007/12/06 01:39:01  yosizaki
1667   Fixed WBT_CancelCommand.
1668 
1669   Revision 1.4  2007/11/22 02:04:46  yosizaki
1670   Fixes specific to GETBLOCK_DONE sequence.
1671 
1672   Revision 1.3  2007/07/30 08:50:29  yosizaki
1673   Fix related to GetBlock response.
1674 
1675   Revision 1.2  2007/05/15 03:17:02  yosizaki
1676   Fix related to response iterations.
1677 
1678   Revision 1.1  2007/04/10 08:19:45  yosizaki
1679   Initial upload.
1680 s
1681   $NoKeywords: $
1682  *---------------------------------------------------------------------------*/
1683