1 /*---------------------------------------------------------------------------*
2   Project:  NitroSDK - WFS - libraries
3   File:     wfs_archive.c
4 
5   Copyright 2007-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  *---------------------------------------------------------------------------*/
14 
15 
16 #include <nitro/wfs/client.h>
17 
18 
19 /*---------------------------------------------------------------------------*/
20 /* Functions */
21 
22 /*---------------------------------------------------------------------------*
23   Name:         WFSi_ArchiveReadCallback
24 
25   Description:  Child WFS archive read access callback.
26 
27   Arguments:    archive: FSArchive structure
28                 buffer: Transfer destination
29                 offset: Transfer source
30                 length: Transfer size
31 
32   Returns:      Process result.
33  *---------------------------------------------------------------------------*/
WFSi_ArchiveReadCallback(FSArchive * archive,void * buffer,u32 offset,u32 length)34 static FSResult WFSi_ArchiveReadCallback(FSArchive *archive, void *buffer, u32 offset, u32 length)
35 {
36     FSResult    result = FS_RESULT_ERROR;
37     WFSClientContext * const context = (WFSClientContext*)FS_GetArchiveBase(archive);
38     const WFSTableFormat * const table = WFS_GetTableFormat(context);
39     if (table)
40     {
41         MI_CpuCopy8(&table->buffer[offset], buffer, length);
42         result = FS_RESULT_SUCCESS;
43     }
44     return result;
45 }
46 
47 /*---------------------------------------------------------------------------*
48   Name:         WFSi_ArchiveReadDoneCallback
49 
50   Description:  Child WFS archive read completion callback.
51 
52   Arguments:    context: WFSClientContext structure
53                 succeeded: TRUE if the read succeeded, FALSE if it failed
54                 arg: Argument specified in the callback
55 
56   Returns:      None.
57  *---------------------------------------------------------------------------*/
WFSi_ArchiveReadDoneCallback(WFSClientContext * context,BOOL succeeded,void * arg)58 static void WFSi_ArchiveReadDoneCallback(WFSClientContext *context, BOOL succeeded, void *arg)
59 {
60     FSFile * const      file = (FSFile*)arg;
61     FSResult            result = FS_RESULT_ERROR;
62     if (succeeded)
63     {
64         file->prop.file.pos += file->arg.readfile.len;
65         result = FS_RESULT_SUCCESS;
66     }
67     FS_NotifyArchiveAsyncEnd(FS_GetAttachedArchive(file), result);
68     (void)context;
69 }
70 
71 /*---------------------------------------------------------------------------*
72   Name:         WFSi_RomArchiveProc
73 
74   Description:  User procedure for a child ROM archive.
75 
76   Arguments:    file: FSFile structure
77                 command: Command
78 
79   Returns:      Process result.
80  *---------------------------------------------------------------------------*/
WFSi_RomArchiveProc(FSFile * file,FSCommandType command)81 static FSResult WFSi_RomArchiveProc(FSFile *file, FSCommandType command)
82 {
83     FSResult    result = FS_RESULT_ERROR;
84     switch (command)
85     {
86     case FS_COMMAND_READFILE:
87         {
88             void   *buffer = file->arg.readfile.dst;
89             u32     offset = file->prop.file.pos;
90             u32     length = file->arg.readfile.len;
91             if (length == 0)
92             {
93                 result = FS_RESULT_SUCCESS;
94             }
95             else
96             {
97                 FSArchive * const archive = FS_GetAttachedArchive(file);
98                 WFSClientContext * const context = (WFSClientContext*)FS_GetArchiveBase(archive);
99                 const WFSTableFormat * const table = WFS_GetTableFormat(context);
100                 if (table != NULL)
101                 {
102                     WFS_RequestClientRead(context, buffer, offset, length,
103                                           WFSi_ArchiveReadDoneCallback, file);
104                     result = FS_RESULT_PROC_ASYNC;
105                 }
106             }
107         }
108         break;
109     case FS_COMMAND_WRITEFILE:
110         result = FS_RESULT_UNSUPPORTED;
111         break;
112     default:
113         result = FS_RESULT_PROC_UNKNOWN;
114         break;
115     }
116     return result;
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         WFSi_EmptyArchiveProc
121 
122   Description:  This is an empty procedure that follows a call to WFS_EndClient().
123 
124   Arguments:    file: FSFile structure
125                 command: Command
126 
127   Returns:      Processing result.
128  *---------------------------------------------------------------------------*/
WFSi_EmptyArchiveProc(FSFile * file,FSCommandType command)129 static FSResult WFSi_EmptyArchiveProc(FSFile *file, FSCommandType command)
130 {
131     FSResult    result = FS_RESULT_PROC_UNKNOWN;
132     // Output a warning message and generate an error for commands that cannot be ignored without causing a problem.
133     if ((command != FS_COMMAND_CLOSEFILE) &&
134         ((command < FS_COMMAND_STATUS_BEGIN) || (command >= FS_COMMAND_STATUS_END)))
135     {
136         static BOOL once = FALSE;
137         if (!once)
138         {
139             once = TRUE;
140             OS_TWarning("WFS-Client has been finalized. (all the commands will fail)\n");
141         }
142         result = FS_RESULT_ERROR;
143     }
144     (void)file;
145     return result;
146 }
147 
148 
149 /*---------------------------------------------------------------------------*
150   Name:         WFSi_SubThreadForEndClient
151 
152   Description:  Archive configuration thread in line with WFS_EndClient.
153 
154   Arguments:    arg: Unused
155 
156   Returns:      None.
157  *---------------------------------------------------------------------------*/
158 #define WFSi_STACK_SIZE         512
159 #define WFSi_STACK_PRIORITY     0
160 #define WFSi_MESG_QUEUE_DEPTH   1
161 
162 static OSThread       WFSi_SubThread;
163 static OSMessageQueue WFSi_MesgQueue;
164 static OSMessage      WFSi_MesgArray[ WFSi_MESG_QUEUE_DEPTH ];
165 static u64            WFSi_Stack[ WFSi_STACK_SIZE / sizeof(u64) ];
166 
167 static void WFSi_SubThreadForEndClient(void* arg);
WFSi_SubThreadForEndClient(void * arg)168 static void WFSi_SubThreadForEndClient(void* arg)
169 {
170 #pragma unused(arg)
171     FSArchive* archive;
172     OSMessage mesg;
173 
174     (void)OS_ReceiveMessage(&WFSi_MesgQueue, &mesg, OS_MESSAGE_BLOCK);
175     archive = (FSArchive*)mesg;
176 
177     (void)FS_SuspendArchive(archive);
178     FS_SetArchiveProc(archive, WFSi_EmptyArchiveProc, (u32)FS_ARCHIVE_PROC_ALL);
179     (void)FS_ResumeArchive(archive);
180 
181     OS_ExitThread();
182 }
183 
184 /*---------------------------------------------------------------------------*
185   Name:         WFSi_SetThreadForEndClient
186 
187   Description:  WFSi_SubThreadForEndClient thread settings.
188 
189   Arguments:    archive:          ROM archive WFSClientContext structure
190 
191   Returns:      None.
192  *---------------------------------------------------------------------------*/
WFSi_SetThreadForEndClient(FSArchive * archive)193 static void WFSi_SetThreadForEndClient(FSArchive* archive)
194 {
195     OSMessage mesg = (OSMessage)archive;
196 
197     OS_InitMessageQueue( &WFSi_MesgQueue, &WFSi_MesgArray[0], WFSi_MESG_QUEUE_DEPTH );
198     OS_CreateThread( &WFSi_SubThread,
199                      WFSi_SubThreadForEndClient,
200                      (void*)0,
201                      WFSi_Stack+WFSi_STACK_SIZE/sizeof(u64),
202                      WFSi_STACK_SIZE,
203                      WFSi_STACK_PRIORITY );
204     OS_WakeupThreadDirect( &WFSi_SubThread );
205     (void)OS_SendMessage( &WFSi_MesgQueue, mesg, OS_MESSAGE_BLOCK );
206 }
207 
208 
209 /*---------------------------------------------------------------------------*
210   Name:         WFSi_RestoreRomArchive
211 
212   Description:  This is an unmount callback invoked when WFS_EndClient() is called.
213 
214   Arguments:    context: WFSClientContext structure.
215 
216   Returns:      None.
217  *---------------------------------------------------------------------------*/
WFSi_RestoreRomArchive(WFSClientContext * context)218 static void WFSi_RestoreRomArchive(WFSClientContext *context)
219 {
220     FSArchive *archive = FS_FindArchive("rom", 3);
221 
222     //Only create thread and send message
223     WFSi_SetThreadForEndClient(archive);
224 
225     (void)context;
226 }
227 
228 /*---------------------------------------------------------------------------*
229   Name:         WFS_ReplaceRomArchive
230 
231   Description:  Mounts the WFS archive.
232 
233   Arguments:    context: WFSClientContext structure
234 
235   Returns:      None.
236  *---------------------------------------------------------------------------*/
WFS_ReplaceRomArchive(WFSClientContext * context)237 void    WFS_ReplaceRomArchive(WFSClientContext *context)
238 {
239     const WFSTableFormat * const table = WFS_GetTableFormat(context);
240     if (table != NULL)
241     {
242         FSArchive *archive = FS_FindArchive("rom", 3);
243         if (FS_IsArchiveLoaded(archive))
244         {
245             (void)FS_UnloadArchive(archive);
246         }
247         FS_SetArchiveProc(archive, WFSi_RomArchiveProc, (u32)FS_ARCHIVE_PROC_ALL);
248         context->unmount_callback = WFSi_RestoreRomArchive;
249         (void)FS_LoadArchive(archive, (u32)context,
250                              table->region[WFS_TABLE_REGION_FAT].offset,
251                              table->region[WFS_TABLE_REGION_FAT].length,
252                              table->region[WFS_TABLE_REGION_FNT].offset,
253                              table->region[WFS_TABLE_REGION_FNT].length,
254                              WFSi_ArchiveReadCallback, NULL);
255         FS_AttachOverlayTable(MI_PROCESSOR_ARM9,
256                               table->buffer +
257                               table->region[WFS_TABLE_REGION_OV9].offset,
258                               table->region[WFS_TABLE_REGION_OV9].length);
259         FS_AttachOverlayTable(MI_PROCESSOR_ARM7,
260                               table->buffer +
261                               table->region[WFS_TABLE_REGION_OV7].offset,
262                               table->region[WFS_TABLE_REGION_OV7].length);
263     }
264 }
265 
266 
267 /*---------------------------------------------------------------------------*
268   $Log: wfs_archive.c,v $
269   Revision 1.1  2007/06/11 06:38:39  yosizaki
270   Initial upload.
271 
272   $NoKeywords: $
273  *---------------------------------------------------------------------------*/
274