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