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