1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WBT - libraries
3   File:     wbt_context.c
4 
5   Copyright 2006-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-11-04#$
14   $Rev: 9198 $
15   $Author: yosizaki $
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:  Transfer memory or clear 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          The 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 unlimited 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               The 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:  Search for a not-yet-received index within 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 within 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      * Since GetBlockInfo() processing uses GetBlock() internally inside 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 within 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 which 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 contents 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            The buffer to store the data.
697                 length            The 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            The buffer to store the data.
797                 length            The 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            The buffer to store the data.
875                 length            The 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 since 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->my_cmd_counter == token->token_peer_cmd_counter)
1024     {
1025         int     peer_bmp = (1 << aid);
1026         current->peer_cmd_counter = token->token_peer_cmd_counter;
1027         current->peer_bmp = (u16)peer_bmp;      /* For debugging */
1028         if ((current->target_bmp & peer_bmp) != 0)
1029         {
1030             /* This is a completion notification, so it's always "SUCCESS." (Errors are notified to a system callback.) */
1031             current->target_bmp &= ~peer_bmp;
1032             current->event = event;
1033             current->result = WBT_RESULT_SUCCESS;
1034             /* New specifications. */
1035             if (list->callback)
1036             {
1037                 list->callback(work->userdata, current);
1038             }
1039             /* Old specifications. */
1040             else if (current->callback)
1041             {
1042                 current->callback(current);
1043             }
1044         }
1045         /* Delete the command if all targets have finished responding. */
1046         if (current->target_bmp == 0)
1047         {
1048             WBTCommandList *list = work->command;
1049             work->command = list->next;
1050             WBT_AddCommandPool(work, list, 1);
1051             WBTi_SwitchNextCommand(work);
1052         }
1053     }
1054 }
1055 
1056 /*---------------------------------------------------------------------------*
1057   Name:         WBT_CallPacketRecvHook
1058 
1059   Description:  Parses the receive packet data.
1060 
1061   Arguments:    work              WBT structure.
1062                 aid               The data sender's AID
1063                 buffer            The received data buffer.
1064                 length            Length of the received data.
1065 
1066   Returns:      None.
1067  *---------------------------------------------------------------------------*/
WBT_CallPacketRecvHook(WBTContext * work,int aid,const void * buffer,int length)1068 void WBT_CallPacketRecvHook(WBTContext * work, int aid, const void *buffer, int length)
1069 {
1070     WBTRecvToken *token = &work->peer_param[aid].recv_token;
1071 
1072     /* The previous reception state is always cleared here. */
1073     work->req_bitmap &= ~(1 << aid);
1074 
1075     /* At the very least, the command header should always exist. */
1076     if (buffer && (length >= sizeof(WBTPacketHeaderFormat)))
1077     {
1078         const WBTPacketFormat *format = (const WBTPacketFormat *)buffer;
1079 
1080         u8      command;
1081         u16     bitmap;
1082 
1083         command = MI_LoadLE8(&format->header.command);
1084         bitmap = MI_LoadLE16(&format->header.bitmap);
1085         token->token_peer_cmd_counter = MI_LoadLE8(&format->header.counter);
1086         token->token_command = command;
1087 
1088 
1089         /*
1090          * Perform command processing if the packet is addressed to the local host.
1091          * NOTE: Although these are if-else statements, we ultimately want to use a function table.
1092          */
1093         if ((WBT_GetAid(work) != -1) && ((bitmap & (1 << WBT_GetAid(work))) != 0))
1094         {
1095             /* Ignore unknown, out-of-range commands. */
1096             if (command >= WBT_COMMAND_MAX)
1097             {
1098             }
1099             /* Ignore if the command's packet size does not satisfy the minimum length. */
1100             else if (length < WBTi_CommandTable[command].packet)
1101             {
1102             }
1103             /** Request command. */
1104             else if (WBTi_CommandTable[command].is_req)
1105             {
1106                 if (command == WBT_CMD_REQ_WAIT)
1107                 {
1108                 }
1109 
1110                 else if (command == WBT_CMD_REQ_SYNC)
1111                 {
1112                     WBTRequestSyncCallback *cb = &work->system_cmd.sync;
1113                     cb->peer_packet_size = (s16)MI_LoadLE16(&format->req_sync.peer_packet);
1114                     cb->my_packet_size = (s16)MI_LoadLE16(&format->req_sync.own_packet);
1115                     cb->num_of_list = 0;        /* In the old specifications, this is the only member not included in a request. */
1116                     /* The child device always complies with the parent device's communication settings. */
1117                     if (WBT_GetAid(work) != 0)
1118                     {
1119                         work->my_data_packet_size = cb->my_packet_size;
1120                         work->peer_data_packet_size = cb->peer_packet_size;
1121                     }
1122                     work->req_bitmap |= (1 << aid);
1123                 }
1124                 /* User-defined data request. */
1125                 else if (command == WBT_CMD_REQ_USER_DATA)
1126                 {
1127                     WBTRecvUserDataCallback *cb = &work->system_cmd.user_data;
1128                     cb->size = MI_LoadLE8(&format->req_userdata.length);
1129                     if (cb->size > WBT_SIZE_USER_DATA)
1130                     {
1131                         cb->size = 0;
1132                     }
1133                     MI_CpuCopy8(format->req_userdata.buffer, cb->data, cb->size);
1134                     work->req_bitmap |= (1 << aid);
1135                 }
1136                 /* Block information request or block request (same format) */
1137                 else if ((command == WBT_CMD_REQ_GET_BLOCK) ||
1138                          (command == WBT_CMD_REQ_GET_BLOCKINFO))
1139                 {
1140                     token->token_block_id = MI_LoadLE32(&format->req_getblock.id);
1141                     token->token_block_seq_no = (s32)MI_LoadLE32(&format->req_getblock.index);
1142                     work->req_bitmap |= (1 << aid);
1143                     WBT_DEBUG_OUTPUT1("get req Block from %d id = %d seq no = %d\n", aid, token->token_block_id,
1144                                       token->token_block_seq_no);
1145                 }
1146                 /* Notification that reception of a block has completed. */
1147                 else if (command == WBT_CMD_REQ_GET_BLOCK_DONE)
1148                 {
1149                     WBTGetBlockDoneCallback *cb = &work->system_cmd.blockdone;
1150                     cb->block_id = MI_LoadLE32(&format->req_getblock_done.id);
1151                     // 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.
1152                     //
1153                     token->token_block_id = MI_LoadLE32(&format->req_getblock_done.id);
1154                     work->req_bitmap |= (1 << aid);
1155                 }
1156             }
1157 
1158             /* Response command */
1159             else if (WBTi_CommandTable[command].is_res)
1160             {
1161                 WBTCommand *current = WBT_GetCurrentCommand(work);
1162 
1163                 /* Ignore if not currently requesting a command. */
1164                 if (!current)
1165                 {
1166                 }
1167                 /*
1168                  * CAUTION!
1169                  *     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.
1170                  *
1171                  *     (1) WBT_CMD_RES_GET_BLOCK / WBT_CMD_REQ_GET_BLOCK
1172                  *     (2) WBT_CMD_RES_GET_BLOCKINFO / WBT_CMD_REQ_GET_BLOCKINFO
1173                  *     (3) WBT_CMD_RES_GET_BLOCK_DONE / WBT_CMD_REQ_GET_BLOCK, WBT_CMD_REQ_GET_BLOCKINFO
1174                  *     What ought to be done when sending WBT_CMD_REQ_GET_BLOCK_DONE?
1175                  */
1176                 else
1177                 {
1178                     /* Synchronous response */
1179                     if (command == WBT_CMD_RES_SYNC)
1180                     {
1181                         if (current->command == WBT_CMD_REQ_SYNC)
1182                         {
1183                             current->sync.num_of_list =
1184                                 (s16)MI_LoadLE16(&format->res_sync.block_total);
1185                             current->sync.peer_packet_size =
1186                                 (s16)MI_LoadLE16(&format->res_sync.peer_packet);
1187                             current->sync.my_packet_size =
1188                                 (s16)MI_LoadLE16(&format->res_sync.own_packet);
1189 
1190                             /* The child device always complies with the parent device's communication settings. */
1191                             if (WBT_GetAid(work) != 0)
1192                             {
1193                                 work->my_data_packet_size = current->sync.my_packet_size;
1194                                 work->peer_data_packet_size = current->sync.peer_packet_size;
1195                             }
1196                             WBT_DEBUG_OUTPUT0("Get res Sync from %d my %d peer %d\n", aid,
1197                                               current->sync.my_packet_size,
1198                                               current->sync.peer_packet_size);
1199                             WBTi_NotifyCompletionCallback(work, (WBTCommandType)command, aid);
1200                         }
1201                     }
1202                     /* Completion notification */
1203                     else if (command == WBT_CMD_RES_USER_DATA)
1204                     {
1205                         if (current->command == WBT_CMD_REQ_USER_DATA)
1206                         {
1207                             WBTi_NotifyCompletionCallback(work, (WBTCommandType)command, aid);
1208                         }
1209                     }
1210                     /* Block response */
1211                     else if ((command == WBT_CMD_RES_GET_BLOCK) ||
1212                              (command == WBT_CMD_RES_GET_BLOCKINFO))
1213                     {
1214                         if ((current->command == WBT_CMD_REQ_GET_BLOCK) ||
1215                             (current->command == WBT_CMD_REQ_GET_BLOCKINFO))
1216                         {
1217                             u32     id = MI_LoadLE32(&format->res_getblock.id);
1218                             s32     index = (s32)MI_LoadLE32(&format->res_getblock.index);
1219 
1220                             /* Determine whether or not this matches the requested ID */
1221                             if (id == current->get.block_id)
1222                             {
1223                                 /* Determine whether the response is from the request location. */
1224                                 if ((current->target_bmp & (1 << aid)) != 0)
1225                                 {
1226                                     /* Determine whether the index is in range. */
1227                                     WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
1228                                     if (index >= pkt_bmp->total)
1229                                     {
1230                                         WBT_DEBUG_OUTPUT1
1231                                             ("%s num of seq over seq no = %d total = %d\n",
1232                                              __FUNCTION__, index, pkt_bmp->total);
1233                                         /* Save failed */
1234                                         WBTi_NotifySystemCallback(work, WBT_CMD_RES_ERROR, aid,
1235                                                                   WBT_RESULT_ERROR_SAVE_FAILURE);
1236                                     }
1237                                     else
1238                                     {
1239                                         /* If the data is not yet received, store. */
1240                                         const void *src = (const u8 *)format +
1241                                             sizeof(format->header) + sizeof(format->res_getblock);
1242                                         u32     packet = (u32)work->peer_data_packet_size;
1243                                         if (WBTi_MergeBitmapIndex(pkt_bmp, index, packet, src))
1244                                         {
1245                                             pkt_bmp->current = index;
1246                                         }
1247                                     }
1248                                 }
1249                             }
1250                         }
1251                     }
1252                     /* Notification that reception of a block has completed. */
1253                     else if (command == WBT_CMD_RES_GET_BLOCK_DONE)
1254                     {
1255                         /* Completion notification if the response is the correct one corresponding to the current request */
1256                         if ((current->command == WBT_CMD_REQ_GET_BLOCK) ||
1257                             (current->command == WBT_CMD_REQ_GET_BLOCKINFO))
1258                         {
1259                             u32     id = MI_LoadLE32(&format->res_getblock_done.id);
1260                             if (current->get.block_id == id)
1261                             {
1262                                 WBT_DEBUG_OUTPUT1
1263                                     ("get block my cmd counter = %d peer cmd counter = %d\n",
1264                                      current->my_cmd_counter, token->token_peer_cmd_counter);
1265                                 WBTi_NotifyCompletionCallback(work,
1266                                                               (current->command ==
1267                                                                WBT_CMD_REQ_GET_BLOCK) ?
1268                                                               WBT_CMD_RES_GET_BLOCK :
1269                                                               WBT_CMD_RES_GET_BLOCKINFO, aid);
1270                             }
1271                             WBT_DEBUG_OUTPUT0("c usr cmd tbmp 0x%x\n", current->target_bmp);
1272                         }
1273                     }
1274                 }
1275             }
1276 
1277             /* Not supported or an illegal command */
1278             else
1279             {
1280                 WBTi_NotifySystemCallback(work, WBT_CMD_RES_ERROR, aid,
1281                                           WBT_RESULT_ERROR_UNKNOWN_PACKET_COMMAND);
1282             }
1283 
1284         }
1285 
1286         /* System callback if a request is received */
1287         if ((work->req_bitmap & (1 << aid)) != 0)
1288         {
1289             /* However, do not send notifications for GetBlock* commands, because they are received numerous times. */
1290             if ((command != WBT_CMD_REQ_GET_BLOCK) && (command != WBT_CMD_REQ_GET_BLOCKINFO))
1291             {
1292                 WBTi_NotifySystemCallback(work, (WBTCommandType)command, aid, WBT_RESULT_SUCCESS);
1293             }
1294         }
1295 
1296     }
1297 }
1298 
1299 /*---------------------------------------------------------------------------*
1300   Name:         WBT_InitContext
1301 
1302   Description:  Initializes the WBT structure.
1303 
1304   Arguments:    work              WBT structure.
1305                 userdata         Any user-defined value.
1306                 callback          The system callback.
1307 
1308   Returns:      None.
1309  *---------------------------------------------------------------------------*/
WBT_InitContext(WBTContext * work,void * userdata,WBTEventCallback callback)1310 void WBT_InitContext(WBTContext * work, void *userdata, WBTEventCallback callback)
1311 {
1312     work->userdata = userdata;
1313     work->callback = callback;
1314 
1315     /* Initialization of transmission history for block transfers */
1316     work->last_block_id = (u32)-1;
1317     work->last_seq_no_1 = -1;
1318     work->last_seq_no_2 = -1;
1319 
1320     /* Initialize command management */
1321     work->command = NULL;
1322     work->command_pool = NULL;
1323     work->my_command_counter = 0;
1324     work->last_target_aid = -1;
1325     work->req_bitmap = 0;
1326     MI_CpuFill8(&work->system_cmd, 0x00, sizeof(work->system_cmd));
1327     MI_CpuFill8(work->peer_param, 0x00, sizeof(work->peer_param));
1328 
1329     /* Clear the command list */
1330     WBT_ResetContext(work, callback);
1331 }
1332 
1333 /*---------------------------------------------------------------------------*
1334   Name:         WBT_ResetContext
1335 
1336   Description:  Re-initializes a WBT structure.
1337 
1338   Arguments:    work              WBT structure.
1339                 callback          The system callback.
1340 
1341   Returns:      None.
1342  *---------------------------------------------------------------------------*/
WBT_ResetContext(WBTContext * work,WBTEventCallback callback)1343 void WBT_ResetContext(WBTContext * work, WBTEventCallback callback)
1344 {
1345     int     i;
1346 
1347     work->my_aid = -1;
1348     work->peer_data_packet_size = 0;
1349     work->my_data_packet_size = 0;
1350 
1351     work->list = NULL;
1352     work->callback = callback;
1353 
1354     /* Destroy all commands */
1355     while (work->command)
1356     {
1357         WBTCommandList *list = work->command;
1358         work->command = list->next;
1359         list->command.command = WBT_CMD_REQ_NONE;
1360     }
1361 
1362     work->system_cmd.command = WBT_CMD_REQ_NONE;
1363     work->system_cmd.target_bmp = 0;
1364     work->system_cmd.peer_bmp = 0;
1365 
1366     for (i = 0; i < 16; ++i)
1367     {
1368         work->peer_param[i].recv_token.last_peer_cmd_counter = 0;
1369     }
1370 
1371 }
1372 
1373 /*---------------------------------------------------------------------------*
1374   Name:         WBT_PostCommand
1375 
1376   Description:  Issues a command and adds it to the command queue.
1377 
1378   Arguments:    work              WBT structure.
1379                 cmd               Structure that stores the command information.
1380                                   Managed within the library until the command is completed.
1381                 bitmap            The AID bitmap corresponding to the command issue.
1382                 callback          Command completion callback. NULL if not used.
1383 
1384   Returns:      None.
1385  *---------------------------------------------------------------------------*/
WBT_PostCommand(WBTContext * work,WBTCommandList * list,u16 bitmap,WBTEventCallback callback)1386 void WBT_PostCommand(WBTContext *work, WBTCommandList *list, u16 bitmap,
1387                      WBTEventCallback callback)
1388 {
1389     PLATFORM_ENTER_CRITICALSECTION();
1390     {
1391         if (list)
1392         {
1393             /* Add to the end of the list */
1394             WBTCommandList **pp;
1395             for (pp = &work->command; *pp; pp = &(*pp)->next)
1396             {
1397             }
1398             *pp = list;
1399             list->next = NULL;
1400             list->command.target_bmp = bitmap;
1401             list->callback = callback;
1402             /* If new command comes during idle, begin processing here */
1403             if (work->command == list)
1404             {
1405                 WBTi_SwitchNextCommand(work);
1406             }
1407         }
1408     }
1409     PLATFORM_LEAVE_CRITICALSECTION();
1410 }
1411 
1412 /*---------------------------------------------------------------------------*
1413   Name:         WBT_CancelCommand
1414 
1415   Description:  Cancels the currently processing command.
1416 
1417   Arguments:    work              WBT structure.
1418                 bitmap            The peer that will cancel the command.
1419 
1420   Returns:      The bitmap that indicates the peer that will actually cancel the command.
1421  *---------------------------------------------------------------------------*/
WBT_CancelCommand(WBTContext * work,int bitmap)1422 int WBT_CancelCommand(WBTContext * work, int bitmap)
1423 {
1424     PLATFORM_ENTER_CRITICALSECTION();
1425     {
1426         WBTCommandList *list = WBT_GetCurrentCommandList(work);
1427         WBTCommand *current = WBT_GetCurrentCommand(work);
1428         if (current)
1429         {
1430             int     aid;
1431             /* Cancellation notification for all AIDs that are currently processing */
1432             bitmap &= current->target_bmp;
1433             for (aid = 0;; ++aid)
1434             {
1435                 int     bit = (1 << aid);
1436                 if (bit > bitmap)
1437                 {
1438                     break;
1439                 }
1440                 if ((bit & bitmap) == 0)
1441                 {
1442                     bitmap &= ~bit;
1443                 }
1444                 /* New specifications. */
1445                 else if (list->callback)
1446                 {
1447                     current->event = WBT_CMD_CANCEL;
1448                     current->target_bmp &= ~bit;
1449                     current->peer_bmp = (u16)bit;
1450                     list->callback(work->userdata, current);
1451                 }
1452                 /* Old specifications. */
1453                 else if (current->callback)
1454                 {
1455                     current->event = WBT_CMD_CANCEL;
1456                     current->target_bmp &= ~bit;
1457                     current->peer_bmp = (u16)bit;
1458                     (*current->callback) (current);
1459                 }
1460             }
1461             /* Destroy the cancelled command (similar to WBTi_NotifyCompletionCallback) */
1462             if (current->target_bmp == 0)
1463             {
1464                 WBTCommandList *list = work->command;
1465                 work->command = list->next;
1466                 WBT_AddCommandPool(work, list, 1);
1467                 WBTi_SwitchNextCommand(work);
1468             }
1469         }
1470     }
1471     PLATFORM_LEAVE_CRITICALSECTION();
1472     return bitmap;
1473 }
1474 
1475 /*---------------------------------------------------------------------------*
1476   Name:         WBT_GetBitmapLength
1477 
1478   Description:  Gets the bitmap buffer size needed for the block transfer control.
1479 
1480   Arguments:    work              WBT structure.
1481                 length            The maximum block size to be transferred.
1482 
1483   Returns:      Size of the necessary bitmap buffer
1484  *---------------------------------------------------------------------------*/
WBT_GetBitmapLength(const WBTContext * work,int length)1485 int WBT_GetBitmapLength(const WBTContext *work, int length)
1486 {
1487     int     packet = work->peer_data_packet_size;
1488     SDK_ASSERT(packet > 0);
1489     return (int)(sizeof(u32) * MATH_ROUNDUP(((length + packet - 1) / packet), 32));
1490 }
1491 
1492 /*---------------------------------------------------------------------------*
1493   Name:         WBT_GetDownloadProgress
1494 
1495   Description:  Gets the block transfer progress status.
1496 
1497   Arguments:    work              WBT structure.
1498                 id                The receive block ID.
1499                 aid               The recipient's AID.
1500                 count             Storage location for the received packet count.
1501                 total             Where the total number of packets is stored.
1502 
1503   Returns:      None.
1504                 Returns 0 for both current and total if there is not block transfer status.
1505  *---------------------------------------------------------------------------*/
WBT_GetDownloadProgress(const WBTContext * work,u32 id,int aid,int * count,int * total)1506 void WBT_GetDownloadProgress(const WBTContext *work, u32 id, int aid, int *count, int *total)
1507 {
1508     const WBTCommand *current = WBT_GetCurrentCommand(work);
1509     if ((current != NULL) &&
1510         (current->command == WBT_CMD_REQ_GET_BLOCK) && (current->get.block_id == id))
1511     {
1512         const WBTPacketBitmap *pkt_bmp = &work->peer_param[aid].pkt_bmp;
1513         *count = pkt_bmp->count;
1514         *total = pkt_bmp->total;
1515     }
1516     else
1517     {
1518         *count = 0;
1519         *total = 0;
1520     }
1521 }
1522 
1523 /*---------------------------------------------------------------------------*
1524   Name:         WBT_SetPacketLength
1525 
1526   Description:  Changes the packet size.
1527                 Can only be used with the parent.
1528 
1529   Arguments:    work              WBT structure.
1530                 own               Own MP send packet size.
1531                 peer              Peer MP send packet size.
1532 
1533   Returns:      Returns TRUE if the setting succeeds.
1534  *---------------------------------------------------------------------------*/
WBT_SetPacketLength(WBTContext * work,int own,int peer)1535 BOOL WBT_SetPacketLength(WBTContext * work, int own, int peer)
1536 {
1537     BOOL    retval = FALSE;
1538     WBTCommand *current;
1539 
1540     SDK_ASSERT(own >= WBT_PACKET_SIZE_MIN);
1541     SDK_ASSERT(peer >= WBT_PACKET_SIZE_MIN);
1542 
1543     current = WBT_GetCurrentCommand(work);
1544     /* Cannot change packet size while requesting a block transmission */
1545     if ((current == NULL) ||
1546         ((current->command != WBT_CMD_REQ_GET_BLOCK) &&
1547         (current->command != WBT_CMD_REQ_GET_BLOCKINFO)))
1548     {
1549         work->my_data_packet_size = (s16)(own - WBT_PACKET_SIZE_MIN);
1550         work->peer_data_packet_size = (s16)(peer - WBT_PACKET_SIZE_MIN);
1551     }
1552     return retval;
1553 }
1554 
1555 /*---------------------------------------------------------------------------*
1556   Name:         WBT_RegisterBlockInfo
1557 
1558   Description:  Newly registers data blocks.
1559 
1560   Arguments:    work              WBT structure.
1561                 list              The list structure used for registration.
1562                                   Used by the library until deallocated with Unregister.
1563                 id                An ID associated with the data block.
1564                 userinfo          User-defined information associated with the data block.
1565                                   This pointer's target is only referenced within this function.
1566                                   A NULL can be designated here if unnecessary.
1567                 buffer            The buffer where the block data was stored.
1568                                   When NULL is specified, the WBT_CMD_PREPARE_SEND_DATA callback sends notification from the library if needed.
1569 
1570                 length            The size of the block data.
1571                                   This value must be correctly specified even when NULL is specified for 'buffer'.
1572 
1573 
1574   Returns:      None.
1575  *---------------------------------------------------------------------------*/
1576 void
WBT_RegisterBlockInfo(WBTContext * work,WBTBlockInfoList * list,u32 id,const void * userinfo,const void * buffer,int length)1577 WBT_RegisterBlockInfo(WBTContext * work, WBTBlockInfoList *list, u32 id,
1578                       const void *userinfo, const void *buffer, int length)
1579 {
1580     PLATFORM_ENTER_CRITICALSECTION();
1581     {
1582         WBTBlockInfoList **pp;
1583         for (pp = &work->list; *pp; pp = &((*pp)->next))
1584         {
1585         }
1586         *pp = list;
1587         list->next = NULL;
1588         list->data_info.id = id;
1589         list->data_info.block_size = length;
1590         WBTi_CopySafeMemory(userinfo, list->data_info.user_id, WBT_USER_ID_LEN);
1591         list->data_ptr = (void *)buffer;
1592         /* Currently unused members */
1593         list->permission_bmp = 0;
1594         list->block_type = (u16)(buffer ? WBT_BLOCK_LIST_TYPE_COMMON : WBT_BLOCK_LIST_TYPE_USER);
1595     }
1596     PLATFORM_LEAVE_CRITICALSECTION();
1597 }
1598 
1599 
1600 /*---------------------------------------------------------------------------*
1601   Name:         WBT_UnregisterBlockInfo
1602 
1603   Description:  Deallocates registered data blocks.
1604 
1605   Arguments:    work              WBT structure.
1606                 id                An ID associated with the data block to be deallocated.
1607 
1608   Returns:      Either the deallocated list structure or NULL.
1609  *---------------------------------------------------------------------------*/
WBT_UnregisterBlockInfo(WBTContext * work,u32 id)1610 WBTBlockInfoList *WBT_UnregisterBlockInfo(WBTContext * work, u32 id)
1611 {
1612     WBTBlockInfoList *retval = NULL;
1613     {
1614         PLATFORM_ENTER_CRITICALSECTION();
1615         WBTBlockInfoList **pp;
1616         for (pp = &work->list; *pp; pp = &(*pp)->next)
1617         {
1618             if ((*pp)->data_info.id == id)
1619             {
1620                 retval = *pp;
1621                 *pp = (*pp)->next;
1622                 break;
1623             }
1624         }
1625         PLATFORM_LEAVE_CRITICALSECTION();
1626     }
1627     return retval;
1628 }
1629 
1630 /*---------------------------------------------------------------------------*
1631   Name:         WBT_GetRegisteredCount
1632 
1633   Description:  Gets the total number of registered data blocks.
1634 
1635   Arguments:    work              WBT structure.
1636 
1637   Returns:      The total number of registered data blocks.
1638  *---------------------------------------------------------------------------*/
WBT_GetRegisteredCount(const WBTContext * work)1639 int WBT_GetRegisteredCount(const WBTContext * work)
1640 {
1641     int     n = 0;
1642     {
1643         PLATFORM_ENTER_CRITICALSECTION();
1644         WBTBlockInfoList *list = work->list;
1645         for (list = work->list; list; list = list->next)
1646         {
1647             ++n;
1648         }
1649         PLATFORM_LEAVE_CRITICALSECTION();
1650     }
1651     return n;
1652 }
1653 
1654 
1655 /*---------------------------------------------------------------------------*
1656   $Log: wbt_context.c,v $
1657   Revision 1.5  2007/12/06 01:39:01  yosizaki
1658   Fixed WBT_CancelCommand.
1659 
1660   Revision 1.4  2007/11/22 02:04:46  yosizaki
1661   Fixes specific to GETBLOCK_DONE sequence.
1662 
1663   Revision 1.3  2007/07/30 08:50:29  yosizaki
1664   Fix related to GetBlock response.
1665 
1666   Revision 1.2  2007/05/15 03:17:02  yosizaki
1667   Fix related to response iterations.
1668 
1669   Revision 1.1  2007/04/10 08:19:45  yosizaki
1670   Initial upload.
1671 s
1672   $NoKeywords: $
1673  *---------------------------------------------------------------------------*/
1674