1 /*---------------------------------------------------------------------------*
2 Project: NitroSDK - WFS - libraries
3 File: wfs_client.c
4
5 Copyright 2007-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 *---------------------------------------------------------------------------*/
14
15
16 #include <nitro/wfs/client.h>
17
18
19 /*---------------------------------------------------------------------------*/
20 /* Functions */
21
22 /*---------------------------------------------------------------------------*
23 Name: WFSi_NotifyEvent
24
25 Description: Notifies for events within the WFS server.
26
27 Arguments: context: The WFSClientContext structure.
28 event: The event type for the notification.
29 argument: The event argument.
30
31 Returns: None.
32 *---------------------------------------------------------------------------*/
WFSi_NotifyEvent(WFSClientContext * context,WFSEventType event,void * argument)33 inline static void WFSi_NotifyEvent(WFSClientContext *context,
34 WFSEventType event, void *argument)
35 {
36 if (context->callback)
37 {
38 context->callback(context, event, argument);
39 }
40 }
41
42 /*---------------------------------------------------------------------------*
43 Name: WFSi_ReallocBitmap
44
45 Description: Reallocates a bitmap capable of receiving the specified size.
46
47 Arguments: context: The WFSClientContext structure.
48 length: The anticipated file size to be received.
49 Specifying a negative value will reallocate with the current value.
50
51 Returns: None.
52 *---------------------------------------------------------------------------*/
WFSi_ReallocBitmap(WFSClientContext * context,int length)53 static void WFSi_ReallocBitmap(WFSClientContext *context, int length)
54 {
55 if (length < 0)
56 {
57 length = (int)context->max_file_size;
58 context->max_file_size = 0;
59 }
60 if (context->max_file_size < length)
61 {
62 const int packet = WBT_GetParentPacketLength(context->wbt);
63 const u32 newsize = WBT_PACKET_BITMAP_SIZE((u32)length, packet);
64 context->max_file_size = (u32)length;
65 MI_CallFree(context->allocator, context->recv_pkt_bmp_buf);
66 context->recv_pkt_bmp_buf = (u32 *)MI_CallAlloc(context->allocator,
67 sizeof(u32) * newsize, sizeof(u32));
68 if (context->recv_pkt_bmp_buf == NULL)
69 {
70 OS_TPanic("cannot allocate bitmap buffer %d BYTEs!", sizeof(u32) * newsize);
71 }
72 context->recv_buf_packet_bmp_table.packet_bitmap[0] = context->recv_pkt_bmp_buf;
73 }
74 SDK_ASSERT(context->recv_pkt_bmp_buf);
75 }
76
77 /*---------------------------------------------------------------------------*
78 Name: WFSi_ReceiveTableSequence
79
80 Description: The sequence that receives the ROM file table.
81 Can only be run once immediately after connecting to the server.
82
83 Arguments: userdata: The WFSClientContext structure.
84 callback: The WBT completion callback argument.
85 Specify NULL for the call when at the start of the sequence.
86
87 Returns: None.
88 *---------------------------------------------------------------------------*/
WFSi_ReceiveTableSequence(void * userdata,WBTCommand * callback)89 static void WFSi_ReceiveTableSequence(void *userdata, WBTCommand *callback)
90 {
91 WFSClientContext * const context = (WFSClientContext *)userdata;
92 WBTContext * const wbt = context->wbt;
93
94 if ((callback == NULL) || (callback->result == WBT_RESULT_SUCCESS))
95 {
96 BOOL post = FALSE;
97 const int bitmap = 0x0001;
98 /* Sequence start => issue WBT-SYNC() and synchronize the packet size */
99 if (callback == NULL)
100 {
101 WFS_DEBUG_OUTPUT(("WBT-SYNC():post"));
102 post = WBT_PostCommandSYNC(wbt, bitmap, WFSi_ReceiveTableSequence);
103 }
104 /* WBT-SYNC completion => issue WBT-INFO(0) and get the size of the ROM file table */
105 else if (callback->event == WBT_CMD_RES_SYNC)
106 {
107 WFS_DEBUG_OUTPUT(("WBT-SYNC():done [server = %d, client = %d]",
108 callback->sync.peer_packet_size + WBT_PACKET_SIZE_MIN,
109 callback->sync.my_packet_size + WBT_PACKET_SIZE_MIN));
110 WFS_DEBUG_OUTPUT(("WBT-INFO(0):post"));
111 post = WBT_PostCommandINFO(wbt, bitmap, WFSi_ReceiveTableSequence,
112 0, &context->block_info_table);
113 }
114 /* WBT-INFO(0) completion => issue WBT-GET(0x20000) and get the size of the ROM file table */
115 else if (callback->event == WBT_CMD_RES_GET_BLOCKINFO)
116 {
117 const int length = context->block_info_table.block_info[0]->block_size;
118 WFS_DEBUG_OUTPUT(("WBT-INFO(0):done [table-length = %d]", length));
119 context->table->length = (u32)length;
120 context->table->buffer = (u8 *)MI_CallAlloc(context->allocator, (u32)length, 1);
121 if (context->table->buffer == NULL)
122 {
123 OS_TPanic("cannot allocate FAT buffer %d BYTEs!", length);
124 }
125 WFSi_ReallocBitmap(context, length);
126 context->recv_buf_table.recv_buf[0] = context->table->buffer;
127 WFS_DEBUG_OUTPUT(("WBT-GET(0x%08X):post", WFS_TABLE_BLOCK_INDEX));
128 post = WBT_PostCommandGET(wbt, bitmap, WFSi_ReceiveTableSequence,
129 WFS_TABLE_BLOCK_INDEX, context->table->length,
130 &context->recv_buf_table,
131 &context->recv_buf_packet_bmp_table);
132 }
133 /* WBT-GET(0x20000) completion => mount preparations complete event notification */
134 else if (callback->event == WBT_CMD_RES_GET_BLOCK)
135 {
136 WFS_DEBUG_OUTPUT(("WBT-GET(0x%08X):done [ready for mount]", WFS_TABLE_BLOCK_INDEX));
137 WFS_ParseTable(context->table);
138 context->fat_ready = TRUE;
139 WFSi_NotifyEvent(context, WFS_EVENT_CLIENT_READY, NULL);
140 post = TRUE; /* As a matter of convenience */
141 }
142 /* WBT command issue failure (insufficient command queue resulting from an internal WFS problem) */
143 if (!post)
144 {
145 WFS_DEBUG_OUTPUT(("internal-error (failed to post WBT command)"));
146 }
147 }
148 /* Some kind of internal error */
149 else
150 {
151 /* Cancelled during the WFS start up (no need to do anything special here) */
152 if (callback->event == WBT_CMD_CANCEL)
153 {
154 }
155 /* An unexpected WBT error (a state management problem occurred as a result of an internal WFS problem) */
156 else
157 {
158 WFS_DEBUG_OUTPUT(("internal-error (unexpected WBT result)"));
159 WFS_DEBUG_OUTPUT((" command = %d", callback->command));
160 WFS_DEBUG_OUTPUT((" event = %d", callback->event));
161 WFS_DEBUG_OUTPUT((" result = %d", callback->result));
162 }
163 }
164 }
165
166 /*---------------------------------------------------------------------------*
167 Name: WFSi_ReadRomSequence
168
169 Description: The sequence that receives the server-side ROM image.
170 Run every time the FS_ReadFile function is called from the client.
171
172 Arguments: userdata: The WFSClientContext structure.
173 callback: The WBT completion callback argument.
174 Specify NULL for the call when at the start of the sequence.
175
176 Returns: None.
177 *---------------------------------------------------------------------------*/
WFSi_ReadRomSequence(void * userdata,WBTCommand * callback)178 static void WFSi_ReadRomSequence(void *userdata, WBTCommand *callback)
179 {
180 WFSClientContext * const context = (WFSClientContext *)userdata;
181 WBTContext * const wbt = context->wbt;
182
183 if ((callback == NULL) || (callback->result == WBT_RESULT_SUCCESS))
184 {
185 BOOL post = FALSE;
186 const int bitmap = 0x0001;
187 /* Sequence start => issue WBT-MSG(LOCK) and lock the transfer range */
188 if (callback == NULL)
189 {
190 WFS_DEBUG_OUTPUT(("WBT-MSG(LOCK):post"));
191 post = WFS_SendMessageLOCK_REQ(wbt, WFSi_ReadRomSequence, bitmap,
192 context->request_region.offset + context->table->origin,
193 context->request_region.length);
194 }
195 /* WBT-MSG() issued (wait for the server response; no need to do anything here) */
196 else if (callback->event == WBT_CMD_RES_USER_DATA)
197 {
198 /* waiting for response from server... */
199 post = TRUE; /* As a matter of convenience */
200 }
201 else
202 {
203 const WFSMessageFormat *const msg = (const WFSMessageFormat *)callback->user_data.data;
204 /* WBT-MSG(LOCK) response received */
205 if ((callback->event == WBT_CMD_REQ_USER_DATA) &&
206 (msg->type == WFS_MSG_LOCK_ACK))
207 {
208 BOOL accepted = (BOOL)MI_LEToH32(msg->arg2);
209 /* Denial => reissue WBT-SYNC() and synchronize the packet size */
210 if (!accepted)
211 {
212 WFS_DEBUG_OUTPUT(("WBT-MSG(LOCK):failed [packet-length renewal]"));
213 WFS_DEBUG_OUTPUT(("WBT-SYNC():post"));
214 post = WBT_PostCommandSYNC(wbt, bitmap, WFSi_ReadRomSequence);
215 }
216 /* Permission => reissue WBT-GET(id) and receive blocks */
217 else
218 {
219 u32 id = MI_LEToH32(msg->arg1);
220 WFS_DEBUG_OUTPUT(("WBT-MSG(LOCK):done [lock-id = 0x%08X]", id));
221 context->block_id = id;
222 context->recv_buf_table.recv_buf[0] = context->request_buffer;
223 WFS_DEBUG_OUTPUT(("WBT-GET(0x%08X):post", id));
224 post = WBT_PostCommandGET(wbt, bitmap, WFSi_ReadRomSequence,
225 context->block_id, context->request_region.length,
226 &context->recv_buf_table,
227 &context->recv_buf_packet_bmp_table);
228 }
229 }
230 /* WBT-SYNC() completion => retry the sequence (will only be a single level recursive call) */
231 else if (callback->event == WBT_CMD_RES_SYNC)
232 {
233 WFS_DEBUG_OUTPUT(("WBT-SYNC():done [server = %d, client = %d]",
234 callback->sync.peer_packet_size + WBT_PACKET_SIZE_MIN,
235 callback->sync.my_packet_size + WBT_PACKET_SIZE_MIN));
236 WFSi_ReallocBitmap(context, -1);
237 WFSi_ReadRomSequence(context, NULL);
238 post = TRUE; /* As a matter of convenience */
239 }
240 /* WBT-GET(id) completion => issue WBT-MSG(UNLOCK, id) and deallocate the transfer range */
241 else if (callback->event == WBT_CMD_RES_GET_BLOCK)
242 {
243 u32 id = context->block_id;
244 WFS_DEBUG_OUTPUT(("WBT-GET(0x%08X):done", id));
245 WFS_DEBUG_OUTPUT(("WBT-MSG(UNLOCK,0x%08X):post", id));
246 post = WFS_SendMessageUNLOCK_REQ(wbt, WFSi_ReadRomSequence, bitmap, id);
247 }
248 /* WBT-MSG(UNLOCK, id) response received => read complete event notification */
249 else if ((callback->event == WBT_CMD_REQ_USER_DATA) &&
250 (msg->type == WFS_MSG_UNLOCK_ACK))
251 {
252 WFS_DEBUG_OUTPUT(("WBT-MSG(UNLOCK,0x%08X):done [read-operation completed]", context->block_id));
253 context->request_buffer = NULL;
254 {
255 WFSRequestClientReadDoneCallback callback = context->request_callback;
256 void *argument = context->request_argument;
257 context->request_callback = NULL;
258 context->request_argument = NULL;
259 if (callback)
260 {
261 (*callback)(context, TRUE, argument);
262 }
263 }
264 post = TRUE; /* As a matter of convenience */
265 }
266 }
267 /* WBT command issue failure (insufficient command queue resulting from an internal WFS problem) */
268 if (!post)
269 {
270 WFS_DEBUG_OUTPUT(("internal-error (failed to post WBT command)"));
271 }
272 }
273 /* Some kind of internal error */
274 else
275 {
276 /* Cancelled during the WFS read process (no need to do anything special here) */
277 if (callback->event == WBT_CMD_CANCEL)
278 {
279 }
280 /* An unexpected WBT error (a state management problem occurred as a result of an internal WFS problem) */
281 else
282 {
283 WFS_DEBUG_OUTPUT(("internal-error (unexpected WBT result)"));
284 WFS_DEBUG_OUTPUT((" command = %d", callback->command));
285 WFS_DEBUG_OUTPUT((" event = %d", callback->event));
286 WFS_DEBUG_OUTPUT((" result = %d", callback->result));
287 }
288 }
289 }
290
291 /*---------------------------------------------------------------------------*
292 Name: WFSi_WBTSystemCallback
293
294 Description: The client-side WBT system callback.
295
296 Arguments: userdata: The WFSServerContext structure.
297 callback: The WBT event argument.
298
299 Returns: None.
300 *---------------------------------------------------------------------------*/
WFSi_WBTSystemCallback(void * userdata,WBTCommand * callback)301 static void WFSi_WBTSystemCallback(void *userdata, WBTCommand *callback)
302 {
303 WFSClientContext * const context = (WFSClientContext *)userdata;
304 /* The response from the server is redirected to WFSi_ReadRomSequence */
305 if ((callback->event == WBT_CMD_REQ_USER_DATA) &&
306 (context->request_buffer))
307 {
308 WFSi_ReadRomSequence(context, callback);
309 }
310 }
311
312 /*---------------------------------------------------------------------------*
313 Name: WFS_CallClientConnectHook
314
315 Description: Connection notification on the client side.
316
317 Arguments: context: The WFSClientContext structure.
318 peer: Information for the connected communication peer.
319
320 Returns: None.
321 *---------------------------------------------------------------------------*/
WFS_CallClientConnectHook(WFSClientContext * context,const WFSPeerInfo * peer)322 void WFS_CallClientConnectHook(WFSClientContext *context, const WFSPeerInfo *peer)
323 {
324 (void)context;
325 (void)peer;
326 }
327
328 /*---------------------------------------------------------------------------*
329 Name: WFS_CallClientDisconnectHook
330
331 Description: Disconnect notification on the client side.
332
333 Arguments: context: The WFSClientContext structure.
334 peer: Information for the disconnected communication peer.
335
336 Returns: None.
337 *---------------------------------------------------------------------------*/
WFS_CallClientDisconnectHook(WFSClientContext * context,const WFSPeerInfo * peer)338 void WFS_CallClientDisconnectHook(WFSClientContext *context, const WFSPeerInfo *peer)
339 {
340 (void)context;
341 (void)peer;
342 }
343
344 /*---------------------------------------------------------------------------*
345 Name: WFS_CallClientPacketSendHook
346
347 Description: Notification of timing when it is possible to send packets on the client side.
348
349 Arguments: context: The WFSClientContext structure.
350 packet: Send packet settings
351
352 Returns: The actual packet size.
353 *---------------------------------------------------------------------------*/
WFS_CallClientPacketSendHook(WFSClientContext * context,WFSPacketBuffer * packet)354 void WFS_CallClientPacketSendHook(WFSClientContext *context, WFSPacketBuffer *packet)
355 {
356 packet->length = WBT_CallPacketSendHook(context->wbt, packet->buffer, packet->length, FALSE);
357 }
358
359 /*---------------------------------------------------------------------------*
360 Name: WFS_CallClientPacketRecvHook
361
362 Description: Notification of timing when it is possible to receive packets on the client side.
363
364 Arguments: context: The WFSClientContext structure
365 packet: Sender packet information
366
367 Returns: The actual packet size.
368 *---------------------------------------------------------------------------*/
WFS_CallClientPacketRecvHook(WFSClientContext * context,const WFSPacketBuffer * packet)369 void WFS_CallClientPacketRecvHook(WFSClientContext *context, const WFSPacketBuffer *packet)
370 {
371 int aid = (int)MATH_CTZ((u32)packet->bitmap);
372 WBT_CallPacketRecvHook(context->wbt, aid, packet->buffer, packet->length);
373 }
374
375 /*---------------------------------------------------------------------------*
376 Name: WFS_InitClient
377
378 Description: Initializes the WFS client context.
379
380 Arguments: context: The WFSClientContext structure
381 userdata: Any user-defined value associated with the context
382 callback: The system event notification callback
383 Specify NULL if not needed.
384 allocator: The allocator used internally
385
386 Returns: None.
387 *---------------------------------------------------------------------------*/
WFS_InitClient(WFSClientContext * context,void * userdata,WFSEventCallback callback,MIAllocator * allocator)388 void WFS_InitClient(WFSClientContext *context,
389 void *userdata, WFSEventCallback callback,
390 MIAllocator *allocator)
391 {
392 int i;
393 context->userdata = userdata;
394 context->callback = callback;
395 context->allocator = allocator;
396 context->fat_ready = FALSE;
397 /* Initialize WBT variables */
398 for (i = 0; i < WBT_NUM_OF_AID; ++i)
399 {
400 context->block_info_table.block_info[i] = &context->block_info[i];
401 context->recv_buf_table.recv_buf[i] = NULL;
402 context->recv_buf_packet_bmp_table.packet_bitmap[i] = NULL;
403 }
404 context->recv_pkt_bmp_buf = NULL;
405 context->max_file_size = 0;
406 context->block_id = 0;
407 context->request_buffer = NULL;
408 context->table->length = 0;
409 context->table->buffer = NULL;
410 context->unmount_callback = NULL;
411 /* Initialize WBT */
412 WBT_InitContext(context->wbt, context, WFSi_WBTSystemCallback);
413 WBT_AddCommandPool(context->wbt, context->wbt_list,
414 sizeof(context->wbt_list) / sizeof(*context->wbt_list));
415 }
416
417 /*---------------------------------------------------------------------------*
418 Name: WFS_EndClient
419
420 Description: Deallocates the WFS client context.
421
422 Arguments: context: The WFSClientContext structure
423
424 Returns: None.
425 *---------------------------------------------------------------------------*/
WFS_EndClient(WFSClientContext * context)426 void WFS_EndClient(WFSClientContext *context)
427 {
428 MI_CallFree(context->allocator, context->recv_pkt_bmp_buf);
429 WBT_ResetContext(context->wbt, NULL);
430 if (context->table->buffer)
431 {
432 MI_CallFree(context->allocator, context->table->buffer);
433 context->table->buffer = NULL;
434 }
435 if (context->request_callback)
436 {
437 (*context->request_callback)(context->request_argument, FALSE, context->request_argument);
438 }
439 if (context->unmount_callback)
440 {
441 (*context->unmount_callback)(context);
442 }
443 }
444
445 /*---------------------------------------------------------------------------*
446 Name: WFS_StartClient
447
448 Description: Starts the WFS client context communication.
449
450 Arguments: context: The WFSClientContext structure
451 peer: The local host's connection information.
452
453 Returns: None.
454 *---------------------------------------------------------------------------*/
WFS_StartClient(WFSClientContext * context,const WFSPeerInfo * peer)455 void WFS_StartClient(WFSClientContext *context, const WFSPeerInfo *peer)
456 {
457 WBT_StartChild(context->wbt, peer->aid);
458 WFSi_ReceiveTableSequence(context, NULL);
459 }
460
461 /*---------------------------------------------------------------------------*
462 Name: WFS_RequestClientRead
463
464 Description: Begins a ROM image read request from the server.
465 When complete, a WFS_EVENT_CLIENT_READ notification occurs.
466
467 Arguments: context: The WFSClientContext structure
468 buffer: Memory where the load data is stored
469 offset: Starting position for the device load
470 length: The load size.
471 callback: Load completion callback
472 NULL if not necessary.
473 arg: Argument passed to the load completion callback
474 Returns: None.
475 *---------------------------------------------------------------------------*/
WFS_RequestClientRead(WFSClientContext * context,void * buffer,u32 offset,u32 length,WFSRequestClientReadDoneCallback callback,void * arg)476 void WFS_RequestClientRead(WFSClientContext *context, void *buffer, u32 offset,
477 u32 length, WFSRequestClientReadDoneCallback callback,
478 void *arg)
479 {
480 if (context->fat_ready)
481 {
482 context->request_buffer = buffer;
483 context->request_region.offset = offset;
484 context->request_region.length = length;
485 context->request_callback = callback;
486 context->request_argument = arg;
487 WFSi_ReallocBitmap(context, (int)length);
488 WFSi_ReadRomSequence(context, NULL);
489 }
490 }
491
492 /*---------------------------------------------------------------------------*
493 Name: WFS_GetClientReadProgress
494
495 Description: Gets the progress of the ROM image read request.
496
497 Arguments: context: The WFSClientContext structure
498 current: Variable that gets the number of received packets
499 total: Variable that gets the total expected number of packets
500
501 Returns: None.
502 *---------------------------------------------------------------------------*/
WFS_GetClientReadProgress(WFSClientContext * context,int * current,int * total)503 void WFS_GetClientReadProgress(WFSClientContext *context,int *current, int *total)
504 {
505 WBT_GetDownloadProgress(context->wbt, context->block_id, 0, current, total);
506 }
507
508
509 /*---------------------------------------------------------------------------*
510 $Log: wfs_client.c,v $
511 Revision 1.2 2007/06/11 06:39:24 yosizaki
512 Changed WFS_RequestClientRead().
513
514 Revision 1.1 2007/04/13 04:12:37 yosizaki
515 Initial upload.
516
517 $NoKeywords: $
518 *---------------------------------------------------------------------------*/
519