1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - FS - libraries
3   File:     fs_archive_fatfs.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   $Date:: 2009-06-04#$
14   $Rev: 10698 $
15   $Author: okubata_ryoma $
16 
17  *---------------------------------------------------------------------------*/
18 
19 #ifdef SDK_TWL
20 
21 #include <nitro/fs.h>
22 #include <nitro/os/ARM9/tcm.h>
23 #include <nitro/os/ARM9/cache.h>
24 #include <nitro/math/math.h>
25 #include <nitro/std/string.h>
26 #include <nitro/gx/gx_vramcnt.h>
27 #include <nitro/spi/ARM9/pm.h>
28 #include <twl/fatfs.h>
29 #include <twl/mi/common/sharedWram.h>
30 
31 #include "../include/util.h"
32 #include "../include/command.h"
33 #include "../include/rom.h"
34 
35 
36 #if defined(FS_IMPLEMENT)
37 
38 
39 #include <twl/ltdmain_begin.h>
40 
41 
42 /*---------------------------------------------------------------------------*/
43 /* Constants */
44 
45 // Characters that cannot be used in entry names of paths
46 extern const u16  *FSiPathInvalidCharactersW;
47 const u16  *FSiPathInvalidCharactersW = L":*?\"<>|";
48 
49 
50 /*---------------------------------------------------------------------------*/
51 /* Variables */
52 
53 static int                      FSiSwitchableWramSlots = 0;
54 
55 static FSFATFSArchiveContext    FSiFATFSDriveDefault[FS_MOUNTDRIVE_MAX] ATTRIBUTE_ALIGN(32);
56 static FATFSRequestBuffer       FSiFATFSAsyncRequestDefault[FS_MOUNTDRIVE_MAX] ATTRIBUTE_ALIGN(32);
57 static u8                       FSiTemporaryBufferDefault[FS_TEMPORARY_BUFFER_MAX] ATTRIBUTE_ALIGN(32);
58 
59 
60 /*---------------------------------------------------------------------------*/
61 /* Functions */
62 
63 /*---------------------------------------------------------------------------*
64  * Implementation related to customize
65  *---------------------------------------------------------------------------*/
66 
67 /*---------------------------------------------------------------------------*
68   Name:         FSiFATFSDrive
69 
70   Description:  Context array that manages the archive of a FAT base.
71                 Ordinarily, an array size for the quantity of FS_MOUNTDRIVE_MAX is required, and in default, static variables in the LTDMAIN segment are used.
72 
73                 With applications built using a special memory arrangement, it is possible to set the proper buffer by changing this variable internally by calling the FSi_SetupFATBuffers function that was overridden.
74 
75 
76 
77   Arguments:    None.
78 
79   Returns:      Buffer for the amount of the FS_MOUNTDRIVE_MAX of the FSFATFSArchiveContext structure.
80  *---------------------------------------------------------------------------*/
81 FSFATFSArchiveContext *FSiFATFSDrive = NULL;
82 
83 /*---------------------------------------------------------------------------*
84   Name:         FSiFATFSAsyncRequest
85 
86   Description:  Command buffer that is used in asynchronous processing by the FAT base archive.
87                 Ordinarily, an array size for the quantity of FS_MOUNTDRIVE_MAX is required, and in default, static variables in the LTDMAIN segment are used.
88 
89                 With applications built using a special memory arrangement, it is possible to set the proper buffer by changing this variable internally by calling the FSi_SetupFATBuffers function that was overridden.
90 
91 
92 
93   Arguments:    None.
94 
95   Returns:      Static command buffer of FS_TEMPORARY_BUFFER_MAX bytes.
96  *---------------------------------------------------------------------------*/
97 FATFSRequestBuffer *FSiFATFSAsyncRequest = NULL;
98 
99 /*---------------------------------------------------------------------------*
100   Name:         FSiTemporaryBuffer
101 
102   Description:  Pointer to the static temporary buffer for issuing read/write commands.
103                 It must be memory that can be referenced by both ARM9/ARM7, and by default a static variable in the LTDMAIN segment is used.
104 
105                 For applications constructed using a special memory layout, you can change these variables to set the appropriate buffer before calling the FS_Init function.
106 
107 
108 
109   Arguments:    None.
110 
111   Returns:      Static command buffer of FS_TEMPORARY_BUFFER_MAX bytes.
112  *---------------------------------------------------------------------------*/
113 u8 *FSiTemporaryBuffer = NULL;
114 
115 /*---------------------------------------------------------------------------*
116   Name:         FSi_SetupFATBuffers
117 
118   Description:  Initializes various buffers needed by the FAT base archive.
119                 With applications built using a special memory arrangement, it is possible to independently set the various buffers by overriding this variable and suppressing the required memory size.
120 
121 
122 
123   Arguments:    None.
124 
125   Returns:      None.
126  *---------------------------------------------------------------------------*/
FSi_SetupFATBuffers(void)127 SDK_WEAK_SYMBOL void FSi_SetupFATBuffers(void)
128 {
129     FSiFATFSDrive = FSiFATFSDriveDefault;
130     FSiFATFSAsyncRequest = FSiFATFSAsyncRequestDefault;
131     FSiTemporaryBuffer = FSiTemporaryBufferDefault;
132 }
133 
134 /*---------------------------------------------------------------------------*
135   Name:         FSi_IsValidAddressForARM7
136 
137   Description:  Determines whether this is a buffer accessible from ARM7.
138                 With applications built using a special memory layout, it is possible to redefine the proper determination routine by overriding this function.
139 
140 
141 
142   Arguments:    buffer: Buffer to be determined
143                 length: Buffer length
144 
145   Returns:      TRUE if it is a buffer accessible from ARM7.
146  *---------------------------------------------------------------------------*/
FSi_IsValidAddressForARM7(const void * buffer,u32 length)147 SDK_WEAK_SYMBOL BOOL FSi_IsValidAddressForARM7(const void *buffer, u32 length)
148  __attribute__((never_inline))
149 {
150     u32     addr = (u32)buffer;
151     u32     dtcm = OS_GetDTCMAddress();
152     if ((addr + length > dtcm) && (addr < dtcm + HW_DTCM_SIZE))
153     {
154         return FALSE;
155     }
156     if ((addr >= HW_TWL_MAIN_MEM) && (addr + length <= HW_TWL_MAIN_MEM_END))
157     {
158         return TRUE;
159     }
160     if ((addr >= HW_EXT_WRAM_ARM7) && (addr + length <= GX_GetSizeOfARM7()))
161     {
162         return TRUE;
163     }
164     // Allow if it is a switchable WRAM not overlapping the slot boundary
165     if ((addr >= HW_WRAM_AREA) && (addr <= HW_WRAM_AREA_END) &&
166         (MATH_ROUNDDOWN(addr, MI_WRAM_B_SLOT_SIZE) + MI_WRAM_B_SLOT_SIZE ==
167          MATH_ROUNDUP(addr + length, MI_WRAM_B_SLOT_SIZE)))
168     {
169         MIWramPos   type;
170         int         slot = MIi_AddressToWramSlot(buffer, &type);
171         if (slot >= 0)
172         {
173             if ((((FSiSwitchableWramSlots >> ((type == MI_WRAM_B) ? 0 : 8)) & (1 << slot)) != 0) &&
174                 // If success is not always possible by switching, the application guarantees it
175                 ((MI_GetWramBankMaster(type, slot)  == MI_WRAM_ARM7) ||
176                  (MI_SwitchWramSlot(type, slot, MI_WRAM_SIZE_32KB,
177                                     MI_GetWramBankMaster(type, slot), MI_WRAM_ARM7) >= 0)))
178             {
179 
180                 return TRUE;
181             }
182         }
183     }
184     return FALSE;
185 }
186 
187 /*---------------------------------------------------------------------------*
188   Name:         FSi_SetSwitchableWramSlots
189 
190   Description:  Specifies WRAM slot that the FS library can switch to ARM7 depending on the circumstances.
191 
192   Arguments:    bitsB: WRAM-B slot bit collection
193                 bitsC: Bitset of WRAM-C slots
194 
195   Returns:      None.
196  *---------------------------------------------------------------------------*/
FSi_SetSwitchableWramSlots(int bitsB,int bitsC)197 void FSi_SetSwitchableWramSlots(int bitsB, int bitsC)
198 {
199     FSiSwitchableWramSlots = (bitsB << 0) | (bitsC << 8);
200 }
201 
202 /*---------------------------------------------------------------------------*
203   Name:         FSi_AllocUnicodeFullPath
204 
205   Description:  Gets full path linking the archive name and relative path.
206 
207   Arguments:    context: FSFATFSArchiveContext structure
208                 relpath: Relative path under the archive
209 
210   Returns:      Buffer that stores the full Unicode path that begins from the archive name.
211  *---------------------------------------------------------------------------*/
FSi_AllocUnicodeFullPath(FSFATFSArchiveContext * context,const char * relpath)212 static u16* FSi_AllocUnicodeFullPath(FSFATFSArchiveContext *context, const char *relpath)
213 {
214     u16        *dst = FSi_GetUnicodeBuffer(NULL);
215     {
216         int     pos = 0;
217         int     dstlen;
218         // First link the archive name and the relative path
219         dstlen = FS_ARCHIVE_FULLPATH_MAX - pos - 2;
220         (void)FSi_ConvertStringSjisToUnicode(&dst[pos], &dstlen, FS_GetArchiveName(context->arc), NULL, NULL);
221         pos += dstlen;
222         dst[pos++] = L':';
223         dst[pos++] = L'/';
224         dstlen = FS_ARCHIVE_FULLPATH_MAX - pos;
225         (void)FSi_ConvertStringSjisToUnicode(&dst[pos], &dstlen, relpath, NULL, NULL);
226         pos += dstlen;
227         // Remove trailing forward slashes ('/')
228         if ((pos > 0) && ((dst[pos - 1] == L'\\') || (dst[pos - 1] == L'/')))
229         {
230             --pos;
231         }
232         dst[pos] = L'\0';
233     }
234     return dst;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         FSi_DostimeToFstime
239 
240   Description:  Converts FAT DOS time stamp to an FSDateTime format.
241 
242   Arguments:    dst: FSDateTime structure that stores the conversion results
243                 src: DOS time stamp that is the conversion source
244 
245   Returns:      None.
246  *---------------------------------------------------------------------------*/
FSi_DostimeToFstime(FSDateTime * dst,u32 src)247 static void FSi_DostimeToFstime(FSDateTime *dst, u32 src)
248 {
249     dst->year = FATFS_DOSTIME_TO_YEAR(src);
250     dst->month = FATFS_DOSTIME_TO_MON(src);
251     dst->day = FATFS_DOSTIME_TO_MDAY(src);
252     dst->hour = FATFS_DOSTIME_TO_HOUR(src);
253     dst->minute = FATFS_DOSTIME_TO_MIN(src);
254     dst->second = FATFS_DOSTIME_TO_SEC(src);
255 }
256 
257 /*---------------------------------------------------------------------------*
258   Name:         FSi_FstimeToDostime
259 
260   Description:  Converts FSDateTime to a FAT DOS time stamp format.
261 
262   Arguments:    dst: DOS time stamp that stores the conversion results
263                 src: FSDateTime structure that is the conversion source
264 
265   Returns:      None.
266  *---------------------------------------------------------------------------*/
FSi_FstimeToDostime(u32 * dst,const FSDateTime * src)267 static void FSi_FstimeToDostime(u32 *dst, const FSDateTime *src)
268 {
269     *dst = FATFS_DATETIME_TO_DOSTIME(src->year, src->month, src->day,
270                                      src->hour, src->minute, src->second);
271 }
272 
273 /*---------------------------------------------------------------------------*
274   Name:         FSi_CheckFstime
275 
276   Description:  Checks the FSDateTime.
277 
278   Arguments:    src: FSDateTime structure
279 
280   Returns:      TRUE or FALSE.
281  *---------------------------------------------------------------------------*/
FSi_CheckFstime(const FSDateTime * fstime)282 static BOOL FSi_CheckFstime( const FSDateTime *fstime)
283 {
284     if( fstime->month / 13 != 0) { return FALSE;}
285 //    if( fstime->day   / 32 != 0) { return FALSE;}
286     if( fstime->hour  / 24 != 0) { return FALSE;}
287     if( fstime->minute/ 60 != 0) { return FALSE;}
288     if( fstime->second/ 61 != 0) { return FALSE;}
289     return( TRUE);
290 }
291 
292 /*---------------------------------------------------------------------------*
293   Name:         FSi_GetUnicodeSpanExcluding
294 
295   Description:  Gets the string length not including specified characters.
296 
297   Arguments:    src: Scanning target string
298                 pattern: Characters to be searched for
299 
300   Returns:      String length, not including specified characters.
301  *---------------------------------------------------------------------------*/
FSi_GetUnicodeSpanExcluding(const u16 * src,const u16 * pattern)302 static int FSi_GetUnicodeSpanExcluding(const u16 *src, const u16 *pattern)
303 {
304     int     pos = 0;
305     BOOL    found = FALSE;
306     for (; src[pos]; ++pos)
307     {
308         int     i;
309         for (i = 0; pattern[i]; ++i)
310         {
311             if (src[pos] == pattern[i])
312             {
313                 found = TRUE;
314                 break;
315             }
316         }
317         if (found)
318         {
319             break;
320         }
321     }
322     return pos;
323 }
324 
325 /*---------------------------------------------------------------------------*
326   Name:         FSi_UsingInvalidCharacterW
327 
328   Description:  Determines whether an inappropriate character is being used as the path name.
329                 However, the "arcname:/<***>" is allowed as a special path.
330 
331   Arguments:    path: Full path string targeted for scanning
332 
333   Returns:      TRUE if using an inappropriate character.
334  *---------------------------------------------------------------------------*/
FSi_UsingInvalidCharacterW(const u16 * path)335 static BOOL FSi_UsingInvalidCharacterW(const u16 *path)
336 {
337     BOOL        retval = FALSE;
338     const u16  *list = FSiPathInvalidCharactersW;
339     if (list && *list)
340     {
341         BOOL    foundLT = FALSE;
342         int     pos = 0;
343         // Skip archive name
344         while (path[pos] && (path[pos] != L':'))
345         {
346             ++pos;
347         }
348         // Skip archive separation
349         pos += (path[pos] == L':');
350         pos += (path[pos] == L'/');
351         // Search for prohibited characters considering special paths
352         if (path[pos] == L'<')
353         {
354             foundLT = TRUE;
355             ++pos;
356         }
357         // Confirm whether prohibited characters are being used
358         while (path[pos])
359         {
360             pos += FSi_GetUnicodeSpanExcluding(&path[pos], list);
361             if (path[pos])
362             {
363                 if (foundLT && (path[pos] == L'>') && (path[pos + 1] == L'\0'))
364                 {
365                     foundLT = FALSE;
366                     pos += 1;
367                 }
368                 else
369                 {
370                     retval = TRUE;
371                     break;
372                 }
373             }
374         }
375         retval |= foundLT;
376         // Warn if using prohibited characters
377         if (retval)
378         {
379             static BOOL logOnce = FALSE;
380             if (!logOnce)
381             {
382                 OS_TWarning("specified path includes invalid character '%c'\n", (char)path[pos]);
383                 logOnce = TRUE;
384             }
385         }
386     }
387     return retval;
388 }
389 
390 /*---------------------------------------------------------------------------*
391   Name:         FSi_ConvertError
392 
393   Description:  Converts FATFS library error codes to FS library error codes.
394 
395   Arguments:    error: FATFS library error codes
396 
397   Returns:      FS library error codes.
398  *---------------------------------------------------------------------------*/
FSi_ConvertError(u32 error)399 FSResult FSi_ConvertError(u32 error)
400 {
401     if (error == FATFS_RESULT_SUCCESS)
402     {
403         return FS_RESULT_SUCCESS;
404     }
405     else if (error == FATFS_RESULT_BUSY)
406     {
407         return FS_RESULT_BUSY;
408     }
409     else if (error == FATFS_RESULT_FAILURE)
410     {
411         return FS_RESULT_FAILURE;
412     }
413     else if (error == FATFS_RESULT_UNSUPPORTED)
414     {
415         return FS_RESULT_UNSUPPORTED;
416     }
417     else if (error == FATFS_RESULT_INVALIDPARAM)
418     {
419         return FS_RESULT_INVALID_PARAMETER;
420     }
421     else if (error == FATFS_RESULT_ALREADYDONE)
422     {
423         return FS_RESULT_ALREADY_DONE;
424     }
425     else if (error == FATFS_RESULT_PERMISSIONDENIDED)
426     {
427         return FS_RESULT_PERMISSION_DENIED;
428     }
429     else if (error == FATFS_RESULT_NOMORERESOURCE)
430     {
431         return FS_RESULT_NO_MORE_RESOURCE;
432     }
433     else if (error == FATFS_RESULT_MEDIAFATAL)
434     {
435         return FS_RESULT_MEDIA_FATAL;
436     }
437     else if (error == FATFS_RESULT_NOENTRY)
438     {
439         return FS_RESULT_NO_ENTRY;
440     }
441     else if (error == FATFS_RESULT_MEDIANOTHING)
442     {
443         return FS_RESULT_MEDIA_NOTHING;
444     }
445     else if (error == FATFS_RESULT_MEDIAUNKNOWN)
446     {
447         return FS_RESULT_MEDIA_UNKNOWN;
448     }
449     else if (error == FATFS_RESULT_BADFORMAT)
450     {
451         return FS_RESULT_BAD_FORMAT;
452     }
453     else if (error == FATFS_RESULT_CANCELED)
454     {
455         return FS_RESULT_CANCELED;
456     }
457     else
458     {
459         return FS_RESULT_ERROR;
460     }
461 }
462 
463 /*---------------------------------------------------------------------------*
464   Name:         FSi_FATFSAsyncDone
465 
466   Description:  Notifies completion of FATFS asynchronous process.
467 
468   Arguments:    buffer: Request structure
469 
470   Returns:      None.
471  *---------------------------------------------------------------------------*/
FSi_FATFSAsyncDone(FATFSRequestBuffer * buffer)472 static void FSi_FATFSAsyncDone(FATFSRequestBuffer *buffer)
473 {
474     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)buffer->userdata;
475     FS_NotifyArchiveAsyncEnd(context->arc, FSi_ConvertError(buffer->header.result));
476 }
477 
478 /*---------------------------------------------------------------------------*
479   Name:         FSi_FATFS_GetArchiveCaps
480 
481   Description:  The FS_COMMAND_GETARCHIVECAPS command.
482 
483   Arguments:    arc: Calling archive
484                 caps: Location to save the device capability flag
485 
486   Returns:      The processing result for the command.
487  *---------------------------------------------------------------------------*/
FSi_FATFS_GetArchiveCaps(FSArchive * arc,u32 * caps)488 static FSResult FSi_FATFS_GetArchiveCaps(FSArchive *arc, u32 *caps)
489 {
490     (void)arc;
491     *caps = FS_ARCHIVE_CAPS_UNICODE;
492     return FS_RESULT_SUCCESS;
493 }
494 
495 /*---------------------------------------------------------------------------*
496   Name:         FSi_FATFS_GetPathInfo
497 
498   Description:  The FS_COMMAND_GETPATHINFO command.
499 
500   Arguments:    arc: Calling archive
501                 baseid: Base directory ID (0 for the root)
502                 relpath: Path
503                 info: Location to save file information
504 
505   Returns:      The processing result for the command.
506  *---------------------------------------------------------------------------*/
FSi_FATFS_GetPathInfo(FSArchive * arc,u32 baseid,const char * relpath,FSPathInfo * info)507 static FSResult FSi_FATFS_GetPathInfo(FSArchive *arc, u32 baseid, const char *relpath, FSPathInfo *info)
508 {
509     FSResult                result = FS_RESULT_ERROR;
510     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
511     FATFSFileInfoW          stat[1];
512     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
513     FATFSResultBuffer       tls[1];
514     FATFS_RegisterResultBuffer(tls, TRUE);
515     (void)baseid;
516     if (FSi_UsingInvalidCharacterW(path))
517     {
518         result = FS_RESULT_INVALID_PARAMETER;
519     }
520     else if (FATFS_GetFileInfoW(path, stat))
521     {
522         info->attributes = stat->attributes;
523         if ((stat->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0)
524         {
525             info->attributes |= FS_ATTRIBUTE_IS_DIRECTORY;
526         }
527         info->filesize = stat->length;
528         FSi_DostimeToFstime(&info->atime, stat->dos_atime);
529         FSi_DostimeToFstime(&info->mtime, stat->dos_mtime);
530         FSi_DostimeToFstime(&info->ctime, stat->dos_ctime);
531         info->id = FS_INVALID_FILE_ID;
532         result = FS_RESULT_SUCCESS;
533     }
534     else
535     {
536         result = FSi_ConvertError(tls->result);
537     }
538     FSi_ReleaseUnicodeBuffer(path);
539     FATFS_RegisterResultBuffer(tls, FALSE);
540     return result;
541 }
542 
543 /*---------------------------------------------------------------------------*
544   Name:         FSi_FATFS_SetPathInfo
545 
546   Description:  The FS_COMMAND_SETPATHINFO command.
547 
548   Arguments:    arc: Calling archive
549                 baseid: Base directory ID (0 for the root)
550                 relpath: Path
551                 info: Storage source of file information
552 
553   Returns:      The processing result for the command.
554  *---------------------------------------------------------------------------*/
FSi_FATFS_SetPathInfo(FSArchive * arc,u32 baseid,const char * relpath,FSPathInfo * info)555 static FSResult FSi_FATFS_SetPathInfo(FSArchive *arc, u32 baseid, const char *relpath, FSPathInfo *info)
556 {
557     FSResult                result = FS_RESULT_ERROR;
558     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
559     FATFSFileInfoW          stat[1];
560     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
561     FATFSResultBuffer       tls[1];
562     FATFS_RegisterResultBuffer(tls, TRUE);
563     (void)baseid;
564     FSi_FstimeToDostime(&stat->dos_atime, &info->atime);
565     FSi_FstimeToDostime(&stat->dos_mtime, &info->mtime);
566     FSi_FstimeToDostime(&stat->dos_ctime, &info->ctime);
567     stat->attributes = (info->attributes & (FATFS_ATTRIBUTE_DOS_MASK | FATFS_PROPERTY_CTRL_MASK));
568     info->attributes &= ~FATFS_PROPERTY_CTRL_MASK;
569     if (((stat->attributes & FATFS_PROPERTY_CTRL_MASK) != 0) && !FSi_CheckFstime(&info->mtime))
570     {
571         result = FS_RESULT_INVALID_PARAMETER;
572     }
573     else if (FSi_UsingInvalidCharacterW(path))
574     {
575         result = FS_RESULT_INVALID_PARAMETER;
576     }
577     else if (FATFS_SetFileInfoW(path, stat))
578     {
579         result = FS_RESULT_SUCCESS;
580     }
581     else
582     {
583         result = FSi_ConvertError(tls->result);
584     }
585     FSi_ReleaseUnicodeBuffer(path);
586     FATFS_RegisterResultBuffer(tls, FALSE);
587     return result;
588 }
589 
590 /*---------------------------------------------------------------------------*
591   Name:         FSi_FATFS_CreateFile
592 
593   Description:  The FATFS_COMMAND_CREATE_FILE command.
594 
595   Arguments:
596 
597   Returns:      The processing result for the command.
598  *---------------------------------------------------------------------------*/
FSi_FATFS_CreateFile(FSArchive * arc,u32 baseid,const char * relpath,u32 permit)599 static FSResult FSi_FATFS_CreateFile(FSArchive *arc, u32 baseid, const char *relpath, u32 permit)
600 {
601     FSResult                result = FS_RESULT_ERROR;
602     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
603     char                    permitstring[16];
604     char                   *s = permitstring;
605     BOOL                    tranc = TRUE;
606     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
607     FATFSResultBuffer       tls[1];
608     FATFS_RegisterResultBuffer(tls, TRUE);
609     if ((permit & FS_PERMIT_R) != 0)
610     {
611         *s++ = 'r';
612     }
613     if ((permit & FS_PERMIT_W) != 0)
614     {
615         *s++ = 'w';
616     }
617     *s++ = '\0';
618     if (FSi_UsingInvalidCharacterW(path))
619     {
620         result = FS_RESULT_INVALID_PARAMETER;
621     }
622     else if (FATFS_CreateFileW(path, tranc, permitstring))
623     {
624         result = FS_RESULT_SUCCESS;
625     }
626     else
627     {
628         result = FSi_ConvertError(tls->result);
629     }
630     FSi_ReleaseUnicodeBuffer(path);
631     FATFS_RegisterResultBuffer(tls, FALSE);
632     (void)baseid;
633     return result;
634 }
635 
636 /*---------------------------------------------------------------------------*
637   Name:         FSi_FATFS_DeleteFile
638 
639   Description:  The FATFS_COMMAND_DELETE_FILE command.
640 
641   Arguments:
642 
643   Returns:      The processing result for the command.
644  *---------------------------------------------------------------------------*/
FSi_FATFS_DeleteFile(FSArchive * arc,u32 baseid,const char * relpath)645 static FSResult FSi_FATFS_DeleteFile(FSArchive *arc, u32 baseid, const char *relpath)
646 {
647     FSResult                result = FS_RESULT_ERROR;
648     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
649     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
650     FATFSResultBuffer       tls[1];
651     FATFS_RegisterResultBuffer(tls, TRUE);
652     if (FSi_UsingInvalidCharacterW(path))
653     {
654         result = FS_RESULT_INVALID_PARAMETER;
655     }
656     else if (FATFS_DeleteFileW(path))
657     {
658         result = FS_RESULT_SUCCESS;
659     }
660     else
661     {
662         result = FSi_ConvertError(tls->result);
663     }
664     FSi_ReleaseUnicodeBuffer(path);
665     FATFS_RegisterResultBuffer(tls, FALSE);
666     (void)baseid;
667     return result;
668 }
669 
670 /*---------------------------------------------------------------------------*
671   Name:         FSi_FATFS_RenameFile
672 
673   Description:  The FATFS_COMMAND_RENAME_FILE command.
674 
675   Arguments:
676 
677   Returns:      The processing result for the command.
678  *---------------------------------------------------------------------------*/
FSi_FATFS_RenameFile(FSArchive * arc,u32 baseid_src,const char * relpath_src,u32 baseid_dst,const char * relpath_dst)679 static FSResult FSi_FATFS_RenameFile(FSArchive *arc, u32 baseid_src, const char *relpath_src, u32 baseid_dst, const char *relpath_dst)
680 {
681     FSResult                result = FS_RESULT_ERROR;
682     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
683     u16                    *src = FSi_AllocUnicodeFullPath(context, relpath_src);
684     u16                    *dst = FSi_AllocUnicodeFullPath(context, relpath_dst);
685     FATFSResultBuffer       tls[1];
686     FATFS_RegisterResultBuffer(tls, TRUE);
687     if (FSi_UsingInvalidCharacterW(src))
688     {
689         result = FS_RESULT_INVALID_PARAMETER;
690     }
691     else if (FSi_UsingInvalidCharacterW(dst))
692     {
693         result = FS_RESULT_INVALID_PARAMETER;
694     }
695     else if (FATFS_RenameFileW(src, dst))
696     {
697         result = FS_RESULT_SUCCESS;
698     }
699     else
700     {
701         result = FSi_ConvertError(tls->result);
702     }
703     FSi_ReleaseUnicodeBuffer(src);
704     FSi_ReleaseUnicodeBuffer(dst);
705     FATFS_RegisterResultBuffer(tls, FALSE);
706     (void)baseid_src;
707     (void)baseid_dst;
708     return result;
709 }
710 
711 /*---------------------------------------------------------------------------*
712   Name:         FSi_FATFS_CreateDirectory
713 
714   Description:  The FATFS_COMMAND_CREATE_DIRECTORY command.
715 
716   Arguments:
717 
718   Returns:      The processing result for the command.
719  *---------------------------------------------------------------------------*/
FSi_FATFS_CreateDirectory(FSArchive * arc,u32 baseid,const char * relpath,u32 permit)720 static FSResult FSi_FATFS_CreateDirectory(FSArchive *arc, u32 baseid, const char *relpath, u32 permit)
721 {
722     FSResult                result = FS_RESULT_ERROR;
723     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
724     char                    permitstring[16];
725     char                   *s = permitstring;
726     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
727     FATFSResultBuffer       tls[1];
728     FATFS_RegisterResultBuffer(tls, TRUE);
729     if ((permit & FS_PERMIT_R) != 0)
730     {
731         *s++ = 'r';
732     }
733     if ((permit & FS_PERMIT_W) != 0)
734     {
735         *s++ = 'w';
736     }
737     *s++ = '\0';
738     if (FSi_UsingInvalidCharacterW(path))
739     {
740         result = FS_RESULT_INVALID_PARAMETER;
741     }
742     else if (FATFS_CreateDirectoryW(path, permitstring))
743     {
744         result = FS_RESULT_SUCCESS;
745     }
746     else
747     {
748         result = FSi_ConvertError(tls->result);
749     }
750     FSi_ReleaseUnicodeBuffer(path);
751     FATFS_RegisterResultBuffer(tls, FALSE);
752     (void)baseid;
753     return result;
754 }
755 
756 /*---------------------------------------------------------------------------*
757   Name:         FSi_FATFS_DeleteDirectory
758 
759   Description:  The FATFS_COMMAND_DELETE_DIRECTORY command.
760 
761   Arguments:
762 
763   Returns:      The processing result for the command.
764  *---------------------------------------------------------------------------*/
FSi_FATFS_DeleteDirectory(FSArchive * arc,u32 baseid,const char * relpath)765 static FSResult FSi_FATFS_DeleteDirectory(FSArchive *arc, u32 baseid, const char *relpath)
766 {
767     FSResult                result = FS_RESULT_ERROR;
768     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
769     u16                    *path = FSi_AllocUnicodeFullPath(context, relpath);
770     FATFSResultBuffer       tls[1];
771     FATFS_RegisterResultBuffer(tls, TRUE);
772     if (FSi_UsingInvalidCharacterW(path))
773     {
774         result = FS_RESULT_INVALID_PARAMETER;
775     }
776     else if (FATFS_DeleteDirectoryW(path))
777     {
778         result = FS_RESULT_SUCCESS;
779     }
780     else
781     {
782         result = FSi_ConvertError(tls->result);
783     }
784     FSi_ReleaseUnicodeBuffer(path);
785     FATFS_RegisterResultBuffer(tls, FALSE);
786     (void)baseid;
787     return result;
788 }
789 
790 /*---------------------------------------------------------------------------*
791   Name:         FSi_FATFS_RenameDirectory
792 
793   Description:  The FATFS_COMMAND_RENAME_DIRECTORY command.
794 
795   Arguments:
796 
797   Returns:      The processing result for the command.
798  *---------------------------------------------------------------------------*/
FSi_FATFS_RenameDirectory(FSArchive * arc,u32 baseid_src,const char * relpath_src,u32 baseid_dst,const char * relpath_dst)799 static FSResult FSi_FATFS_RenameDirectory(FSArchive *arc, u32 baseid_src, const char *relpath_src, u32 baseid_dst, const char *relpath_dst)
800 {
801     FSResult                result = FS_RESULT_ERROR;
802     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
803     u16                    *src = FSi_AllocUnicodeFullPath(context, relpath_src);
804     u16                    *dst = FSi_AllocUnicodeFullPath(context, relpath_dst);
805     FATFSResultBuffer       tls[1];
806     FATFS_RegisterResultBuffer(tls, TRUE);
807     if (FSi_UsingInvalidCharacterW(src))
808     {
809         result = FS_RESULT_INVALID_PARAMETER;
810     }
811     else if (FSi_UsingInvalidCharacterW(dst))
812     {
813         result = FS_RESULT_INVALID_PARAMETER;
814     }
815     else if (FATFS_RenameDirectoryW(src, dst))
816     {
817         result = FS_RESULT_SUCCESS;
818     }
819     else
820     {
821         result = FSi_ConvertError(tls->result);
822     }
823     FSi_ReleaseUnicodeBuffer(src);
824     FSi_ReleaseUnicodeBuffer(dst);
825     FATFS_RegisterResultBuffer(tls, FALSE);
826     (void)baseid_src;
827     (void)baseid_dst;
828     return result;
829 }
830 
831 /*---------------------------------------------------------------------------*
832   Name:         FSi_FATFS_GetArchiveResource
833 
834   Description:  The FATFS_COMMAND_GETARCHIVERESOURCE command.
835 
836   Arguments:    arc: Calling archive
837                 resource: Storage destination of resource information
838 
839   Returns:      The processing result for the command.
840  *---------------------------------------------------------------------------*/
FSi_FATFS_GetArchiveResource(FSArchive * arc,FSArchiveResource * resource)841 static FSResult FSi_FATFS_GetArchiveResource(FSArchive *arc, FSArchiveResource *resource)
842 {
843     FSResult                result = FS_RESULT_ERROR;
844     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
845     u16                    *path = FSi_AllocUnicodeFullPath(context, "/");
846     FATFSResultBuffer       tls[1];
847     FATFS_RegisterResultBuffer(tls, TRUE);
848     if (FSi_UsingInvalidCharacterW(path))
849     {
850         result = FS_RESULT_INVALID_PARAMETER;
851     }
852     else if (FATFS_GetDriveResourceW(path, context->resource))
853     {
854         resource->totalSize = context->resource->totalSize;
855         resource->availableSize = context->resource->availableSize;
856         resource->maxFileHandles = context->resource->maxFileHandles;
857         resource->currentFileHandles = context->resource->currentFileHandles;
858         resource->maxDirectoryHandles = context->resource->maxDirectoryHandles;
859         resource->currentDirectoryHandles = context->resource->currentDirectoryHandles;
860         // For FAT archives
861         resource->bytesPerSector = context->resource->bytesPerSector;
862         resource->sectorsPerCluster = context->resource->sectorsPerCluster;
863         resource->totalClusters = context->resource->totalClusters;
864         resource->availableClusters = context->resource->availableClusters;
865         result = FS_RESULT_SUCCESS;
866     }
867     else
868     {
869         result = FSi_ConvertError(tls->result);
870     }
871     FSi_ReleaseUnicodeBuffer(path);
872     FATFS_RegisterResultBuffer(tls, FALSE);
873     return result;
874 }
875 
876 /*---------------------------------------------------------------------------*
877   Name:         FSi_FATFS_OpenFile
878 
879   Description:  The FS_COMMAND_OPENFILE command.
880 
881   Arguments:    arc: Calling archive
882                 file: Target file
883                 baseid: Base directory (0 for the root)
884                 path: File path
885                 mode: Access mode
886 
887   Returns:      The processing result for the command.
888  *---------------------------------------------------------------------------*/
FSi_FATFS_OpenFile(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)889 static FSResult FSi_FATFS_OpenFile(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
890 {
891     FSResult                result = FS_RESULT_ERROR;
892     FATFSFileHandle handle = FATFS_INVALID_HANDLE;
893     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
894     char                    modestring[16];
895     char                   *s = modestring;
896     FATFSResultBuffer       tls[1];
897     FATFS_RegisterResultBuffer(tls, TRUE);
898     if ((mode & FS_FILEMODE_R) != 0)
899     {
900         *s++ = 'r';
901         if ((mode & FS_FILEMODE_W) != 0)
902         {
903             *s++ = '+';
904         }
905     }
906     else if ((mode & FS_FILEMODE_W) != 0)
907     {
908         *s++ = 'w';
909     }
910     if ((mode & FS_FILEMODE_L) != 0)
911     {
912         *s++ = 'l';
913     }
914     *s++ = '\0';
915     {
916         const u16  *unipath = NULL;
917         u16        *fpath = NULL;
918         // Store Unicode as it is if the Unicode version structure was passed
919         if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0)
920         {
921             unipath = (const u16 *)path;
922         }
923         // If not, store as Shift_JIS version
924         // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.)
925         //
926         else
927         {
928             fpath = FSi_AllocUnicodeFullPath(context, path);
929             unipath = fpath;
930         }
931         if (FSi_UsingInvalidCharacterW(unipath))
932         {
933             result = FS_RESULT_INVALID_PARAMETER;
934         }
935         else
936         {
937             handle = FATFS_OpenFileW(unipath, modestring);
938             if (handle != FATFS_INVALID_HANDLE)
939             {
940                 FS_SetFileHandle(file, arc, (void*)handle);
941                 result = FS_RESULT_SUCCESS;
942             }
943             else
944             {
945                 result = FSi_ConvertError(tls->result);
946             }
947         }
948         FSi_ReleaseUnicodeBuffer(fpath);
949     }
950     FATFS_RegisterResultBuffer(tls, FALSE);
951     (void)baseid;
952     return result;
953 }
954 
955 /*---------------------------------------------------------------------------*
956   Name:         FSi_FATFS_CloseFile
957 
958   Description:  The FS_COMMAND_CLOSEFILE command.
959 
960   Arguments:    arc: Calling archive
961                 file: Target file
962 
963   Returns:      The processing result for the command.
964  *---------------------------------------------------------------------------*/
FSi_FATFS_CloseFile(FSArchive * arc,FSFile * file)965 static FSResult FSi_FATFS_CloseFile(FSArchive *arc, FSFile *file)
966 {
967     FSResult        result = FS_RESULT_ERROR;
968     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
969     FATFSResultBuffer       tls[1];
970     FATFS_RegisterResultBuffer(tls, TRUE);
971     if (FATFS_CloseFile(handle))
972     {
973         FS_DetachHandle(file);
974         result = FS_RESULT_SUCCESS;
975     }
976     else
977     {
978         result = FSi_ConvertError(tls->result);
979     }
980     FATFS_RegisterResultBuffer(tls, FALSE);
981     (void)arc;
982     return result;
983 }
984 
985 /*---------------------------------------------------------------------------*
986   Name:         FSi_FATFS_ReadFile
987 
988   Description:  The FS_COMMAND_READFILE command.
989 
990   Arguments:    arc: Calling archive
991                 file: Target file
992                 buffer: Memory to transfer to
993                 length: Transfer size
994 
995   Returns:      The processing result for the command.
996  *---------------------------------------------------------------------------*/
FSi_FATFS_ReadFile(FSArchive * arc,FSFile * file,void * buffer,u32 * length)997 static FSResult FSi_FATFS_ReadFile(FSArchive *arc, FSFile *file, void *buffer, u32 *length)
998 {
999     FSResult                result = FS_RESULT_SUCCESS;
1000     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
1001     FATFSFileHandle         handle = (FATFSFileHandle)FS_GetFileUserData(file);
1002     u32                     rest = *length;
1003     BOOL                    async = ((file->stat & FS_FILE_STATUS_BLOCKING) == 0);
1004     FATFSResultBuffer       tls[1];
1005     FATFS_RegisterResultBuffer(tls, TRUE);
1006     while (rest > 0)
1007     {
1008         void   *dst = buffer;
1009         u32     len = rest;
1010         int     read;
1011         // If the ARM7 cannot directly access the specified memory, substitute it with a temporary buffer
1012         if (!FSi_IsValidAddressForARM7(buffer, rest))
1013         {
1014             dst = context->tmpbuf;
1015             len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH);
1016         }
1017         // If the specified memory is not 32-byte aligned, substitute it with a temporary buffer
1018         else if ((((u32)buffer | len) & 31) != 0)
1019         {
1020             // No special adjustment is needed if the next transfer is the last
1021             if (len <= FS_TMPBUF_LENGTH)
1022             {
1023                 dst = context->tmpbuf;
1024                 len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH);
1025             }
1026             // If the start of the buffer is not aligned, align it with the next transfer
1027             else if (((u32)buffer & 31) != 0)
1028             {
1029                 dst = context->tmpbuf;
1030                 len = MATH_ROUNDUP((u32)buffer, 32) - (u32)buffer;
1031             }
1032             // If only the transfer size is not aligned, truncate the end and transfer directly
1033             else
1034             {
1035                 len = MATH_ROUNDDOWN(len, 32);
1036             }
1037         }
1038         // Even if a temporary buffer is not used, write back a dirty cache for main memory
1039         //
1040         if ((dst == buffer) &&
1041             (((u32)dst >= HW_TWL_MAIN_MEM) && ((u32)dst + len <= HW_TWL_MAIN_MEM_END)))
1042         {
1043             DC_FlushRange(dst, len);
1044         }
1045         // If an asynchronous process was requested and an asynchronous process is actually possible
1046         // Set a request buffer here
1047         async &= ((dst == buffer) && (len == rest));
1048         if (async)
1049         {
1050             FATFSi_SetRequestBuffer(&FSiFATFSAsyncRequest[context - FSiFATFSDrive], FSi_FATFSAsyncDone, context);
1051         }
1052         // Actually call
1053         read = FATFS_ReadFile(handle, dst, (int)len);
1054         if (async)
1055         {
1056             rest -= len;
1057             result = FS_RESULT_PROC_ASYNC;
1058             break;
1059         }
1060         // If switched with the temporary buffer, copy here
1061         if ((dst != buffer) && (read > 0))
1062         {
1063             DC_InvalidateRange(dst, (u32)read);
1064             MI_CpuCopy8(dst, buffer, (u32)read);
1065         }
1066         buffer = (u8 *)buffer + read;
1067         rest -= read;
1068         if (read != len)
1069         {
1070             result = FSi_ConvertError(tls->result);
1071             break;
1072         }
1073     }
1074     *length -= rest;
1075     FATFS_RegisterResultBuffer(tls, FALSE);
1076     return result;
1077 }
1078 
1079 /*---------------------------------------------------------------------------*
1080   Name:         FSi_FATFS_WriteFile
1081 
1082   Description:  The FS_COMMAND_WRITEFILE command.
1083 
1084   Arguments:    arc: Calling archive
1085                 file: Target file
1086                 buffer: Memory to transfer from
1087                 length: Transfer size
1088 
1089   Returns:      The processing result for the command.
1090  *---------------------------------------------------------------------------*/
FSi_FATFS_WriteFile(FSArchive * arc,FSFile * file,const void * buffer,u32 * length)1091 static FSResult FSi_FATFS_WriteFile(FSArchive *arc, FSFile *file, const void *buffer, u32 *length)
1092 {
1093     FSResult                result = FS_RESULT_SUCCESS;
1094     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
1095     FATFSFileHandle         handle = (FATFSFileHandle)FS_GetFileUserData(file);
1096     u32                     rest = *length;
1097     BOOL                    async = ((file->stat & FS_FILE_STATUS_BLOCKING) == 0);
1098     FATFSResultBuffer       tls[1];
1099     FATFS_RegisterResultBuffer(tls, TRUE);
1100     while (rest > 0)
1101     {
1102         // If the ARM7 cannot directly access the specified memory, substitute it with a temporary buffer
1103         const void *dst = buffer;
1104         u32         len = rest;
1105         int         written;
1106         if (!FSi_IsValidAddressForARM7(buffer, rest) || ((((u32)buffer | len) & 31) != 0))
1107         {
1108             dst = context->tmpbuf;
1109             len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH);
1110         }
1111         // If the specified memory is not 32-byte aligned, substitute it with a temporary buffer
1112         else if ((((u32)buffer | len) & 31) != 0)
1113         {
1114             // No special adjustment is needed if the next transfer is the last
1115             if (len <= FS_TMPBUF_LENGTH)
1116             {
1117                 dst = context->tmpbuf;
1118                 len = (u32)MATH_MIN(len, FS_TMPBUF_LENGTH);
1119             }
1120             // If the start of the buffer is not aligned, align it with the next transfer
1121             else if (((u32)buffer & 31) != 0)
1122             {
1123                 dst = context->tmpbuf;
1124                 len = MATH_ROUNDUP((u32)buffer, 32) - (u32)buffer;
1125             }
1126             // If only the transfer size is not aligned, truncate the end and transfer directly
1127             else
1128             {
1129                 len = MATH_ROUNDDOWN(len, 32);
1130             }
1131         }
1132         // If a temporary buffer is used, copy data that should be written
1133         if (dst != buffer)
1134         {
1135             MI_CpuCopy8(buffer, context->tmpbuf, len);
1136         }
1137         // If the buffer is in main memory, data write-back is necessary to make it visible from the ARM7
1138         if (((u32)dst >= HW_TWL_MAIN_MEM) && ((u32)dst + len <= HW_TWL_MAIN_MEM_END))
1139         {
1140             DC_StoreRange(dst, len);
1141         }
1142         // If an asynchronous process was requested and an asynchronous process is actually possible
1143         // Set a request buffer here
1144         async &= ((dst == buffer) && (len == rest));
1145         if (async)
1146         {
1147             FATFSi_SetRequestBuffer(&FSiFATFSAsyncRequest[context - FSiFATFSDrive], FSi_FATFSAsyncDone, context);
1148         }
1149         // Actually call
1150         written = FATFS_WriteFile(handle, dst, (int)len);
1151         if (async)
1152         {
1153             rest -= len;
1154             result = FS_RESULT_PROC_ASYNC;
1155             break;
1156         }
1157         buffer = (u8 *)buffer + written;
1158         rest -= written;
1159         if (written != len)
1160         {
1161             result = FSi_ConvertError(tls->result);
1162             break;
1163         }
1164     }
1165     *length -= rest;
1166     FATFS_RegisterResultBuffer(tls, FALSE);
1167     return result;
1168 }
1169 
1170 /*---------------------------------------------------------------------------*
1171   Name:         FSi_FATFS_SetSeekCache
1172 
1173   Description:  The FS_COMMAND_SETSEEKCACHE command.
1174 
1175   Arguments:    arc: Calling archive
1176                 file: Target file
1177                 buf: Cache buffer
1178                 buf_size: Cache buffer size
1179 
1180   Returns:      The processing result for the command.
1181  *---------------------------------------------------------------------------*/
FSi_FATFS_SetSeekCache(FSArchive * arc,FSFile * file,void * buf,u32 buf_size)1182 static FSResult FSi_FATFS_SetSeekCache(FSArchive *arc, FSFile *file, void* buf, u32 buf_size)
1183 {
1184     FSResult        result = FS_RESULT_ERROR;
1185     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
1186     FATFSResultBuffer       tls[1];
1187     FATFS_RegisterResultBuffer(tls, TRUE);
1188 
1189     if ((buf != NULL) &&
1190         (((u32)buf < HW_TWL_MAIN_MEM) || (((u32)buf + buf_size) > HW_TWL_MAIN_MEM_END)))
1191     {
1192         // A buffer that is not in main memory causes a parameter error
1193         result = FS_RESULT_INVALID_PARAMETER;
1194     }
1195     else if ((buf != NULL) && (buf_size < 32))
1196     {
1197         // Fail if memory size is insufficient to share with the ARM7
1198         result = FS_RESULT_FAILURE;
1199     }
1200     else if ((((u32)buf & 31) != 0) && ((buf_size - (32 - ((u32)buf & 31))) < 32))
1201     {
1202         // Also fail if it is too small after being 32-byte aligned
1203         result = FS_RESULT_FAILURE;
1204     }
1205     else
1206     {
1207         void   *cache;
1208         u32     cache_size;
1209 
1210         if (buf != NULL) {
1211             // Flush this because it may have existed in the cache before being used by this function
1212             DC_FlushRange(buf, buf_size);
1213         }
1214 
1215         // Extract a region that is 32-byte aligned to allow sharing with the ARM7
1216         if (((u32)buf & 31) != 0) {
1217             cache = (void *)((u32)buf + (32 - ((u32)buf & 31)));    // 32-byte boundary
1218             cache_size = buf_size - (32 - ((u32)buf & 31));
1219         } else {
1220             cache = buf;
1221             cache_size = buf_size;
1222         }
1223         cache_size = cache_size & ~31;                              // Reduce to 32 bytes
1224 
1225         if( FATFS_SetSeekCache(handle, cache, cache_size) != FALSE)
1226         {
1227             result = FS_RESULT_SUCCESS;
1228         }
1229         else
1230         {
1231             result = FSi_ConvertError(tls->result);
1232         }
1233     }
1234     (void)arc;
1235     FATFS_RegisterResultBuffer(tls, FALSE);
1236     return result;
1237 }
1238 
1239 /*---------------------------------------------------------------------------*
1240   Name:         FSi_FATFS_SeekFile
1241 
1242   Description:  The FS_COMMAND_SEEKFILE command.
1243 
1244   Arguments:    arc: Calling archive
1245                 file: Target file
1246                 offset: Displacement and moved-to position
1247                 from: Starting point to seek from
1248 
1249   Returns:      The processing result for the command.
1250  *---------------------------------------------------------------------------*/
FSi_FATFS_SeekFile(FSArchive * arc,FSFile * file,int * offset,FSSeekFileMode from)1251 static FSResult FSi_FATFS_SeekFile(FSArchive *arc, FSFile *file, int *offset, FSSeekFileMode from)
1252 {
1253     FSResult        result = FS_RESULT_ERROR;
1254     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
1255     FATFSSeekMode   mode = FATFS_SEEK_CUR;
1256     FATFSResultBuffer       tls[1];
1257     FATFS_RegisterResultBuffer(tls, TRUE);
1258     if (from == FS_SEEK_SET)
1259     {
1260         mode = FATFS_SEEK_SET;
1261     }
1262     else if (from == FS_SEEK_CUR)
1263     {
1264         mode = FATFS_SEEK_CUR;
1265     }
1266     else if (from == FS_SEEK_END)
1267     {
1268         mode = FATFS_SEEK_END;
1269     }
1270     *offset = FATFS_SeekFile(handle, *offset, mode);
1271     if (*offset >= 0)
1272     {
1273         result = FS_RESULT_SUCCESS;
1274     }
1275     else
1276     {
1277         result = FSi_ConvertError(tls->result);
1278     }
1279     FATFS_RegisterResultBuffer(tls, FALSE);
1280     (void)arc;
1281     return result;
1282 }
1283 
1284 /*---------------------------------------------------------------------------*
1285   Name:         FSi_FATFS_GetFileLength
1286 
1287   Description:  The FS_COMMAND_GETFILELENGTH command.
1288 
1289   Arguments:    arc: Calling archive
1290                 file: Target file
1291                 length: Location to save the obtained size
1292 
1293   Returns:      The processing result for the command.
1294  *---------------------------------------------------------------------------*/
FSi_FATFS_GetFileLength(FSArchive * arc,FSFile * file,u32 * length)1295 static FSResult FSi_FATFS_GetFileLength(FSArchive *arc, FSFile *file, u32 *length)
1296 {
1297     FSResult        result = FS_RESULT_ERROR;
1298     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
1299     int             n = FATFS_GetFileLength(handle);
1300     FATFSResultBuffer       tls[1];
1301     FATFS_RegisterResultBuffer(tls, TRUE);
1302     if (n >= 0)
1303     {
1304         *length = (u32)n;
1305         result = FS_RESULT_SUCCESS;
1306     }
1307     else
1308     {
1309         result = FSi_ConvertError(tls->result);
1310     }
1311     FATFS_RegisterResultBuffer(tls, FALSE);
1312     (void)arc;
1313     return result;
1314 }
1315 
1316 /*---------------------------------------------------------------------------*
1317   Name:         FSi_FATFS_SetFileLength
1318 
1319   Description:  The FS_COMMAND_SETFILELENGTH command.
1320 
1321   Arguments:    arc: Calling archive
1322                 file: Target file
1323                 length: File size to be set
1324 
1325   Returns:      The processing result for the command.
1326  *---------------------------------------------------------------------------*/
FSi_FATFS_SetFileLength(FSArchive * arc,FSFile * file,u32 length)1327 static FSResult FSi_FATFS_SetFileLength(FSArchive *arc, FSFile *file, u32 length)
1328 {
1329     FSResult        result = FS_RESULT_ERROR;
1330     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
1331     FATFSResultBuffer       tls[1];
1332     FATFS_RegisterResultBuffer(tls, TRUE);
1333     if (FATFS_SetFileLength(handle, (int)length))
1334     {
1335         result = FS_RESULT_SUCCESS;
1336     }
1337     else
1338     {
1339         result = FSi_ConvertError(tls->result);
1340     }
1341     FATFS_RegisterResultBuffer(tls, FALSE);
1342     (void)arc;
1343     return result;
1344 }
1345 
1346 /*---------------------------------------------------------------------------*
1347   Name:         FSi_FATFS_GetFilePosition
1348 
1349   Description:  The FS_COMMAND_GETFILEPOSITION command.
1350 
1351   Arguments:    arc: Calling archive
1352                 file: Target file
1353                 position: Location to store the obtained position
1354 
1355   Returns:      The processing result for the command.
1356  *---------------------------------------------------------------------------*/
FSi_FATFS_GetFilePosition(FSArchive * arc,FSFile * file,u32 * position)1357 static FSResult FSi_FATFS_GetFilePosition(FSArchive *arc, FSFile *file, u32 *position)
1358 {
1359     *position = 0;
1360     return FSi_FATFS_SeekFile(arc, file, (int*)position, FS_SEEK_CUR);
1361 }
1362 
1363 /*---------------------------------------------------------------------------*
1364   Name:         FSi_FATFS_FlushFile
1365 
1366   Description:  The FS_COMMAND_FLUSHFILE command.
1367 
1368   Arguments:    arc: Calling archive
1369                 file: Target file
1370 
1371   Returns:      The processing result for the command.
1372  *---------------------------------------------------------------------------*/
FSi_FATFS_FlushFile(FSArchive * arc,FSFile * file)1373 static FSResult FSi_FATFS_FlushFile(FSArchive *arc, FSFile *file)
1374 {
1375     FSResult        result = FS_RESULT_ERROR;
1376     FATFSFileHandle handle = (FATFSFileHandle)FS_GetFileUserData(file);
1377     FATFSResultBuffer       tls[1];
1378     FATFS_RegisterResultBuffer(tls, TRUE);
1379     if (FATFS_FlushFile(handle))
1380     {
1381         result = FS_RESULT_SUCCESS;
1382     }
1383     else
1384     {
1385         result = FSi_ConvertError(tls->result);
1386     }
1387     FATFS_RegisterResultBuffer(tls, FALSE);
1388     (void)arc;
1389     return result;
1390 }
1391 
1392 /*---------------------------------------------------------------------------*
1393   Name:         FSi_FATFS_OpenDirectory
1394 
1395   Description:  The FS_COMMAND_OPENDIRECTORY command.
1396 
1397   Arguments:    arc: Calling archive
1398                 file: Target file
1399                 baseid: Base directory ID (0 for the root)
1400                 path: Path
1401                 mode: Access mode
1402 
1403   Returns:      The processing result for the command.
1404  *---------------------------------------------------------------------------*/
FSi_FATFS_OpenDirectory(FSArchive * arc,FSFile * file,u32 baseid,const char * path,u32 mode)1405 static FSResult FSi_FATFS_OpenDirectory(FSArchive *arc, FSFile *file, u32 baseid, const char *path, u32 mode)
1406 {
1407     FSResult                result = FS_RESULT_ERROR;
1408     FSFATFSArchiveContext  *context = (FSFATFSArchiveContext *)FS_GetArchiveUserData(arc);
1409     FATFSDirectoryHandle    handle = FATFS_INVALID_HANDLE;
1410     char                    modestring[16];
1411     char                   *s = modestring;
1412     FATFSResultBuffer       tls[1];
1413     FATFS_RegisterResultBuffer(tls, TRUE);
1414     if ((mode & FS_FILEMODE_R) != 0)
1415     {
1416         *s++ = 'r';
1417     }
1418     if ((mode & FS_FILEMODE_W) != 0)
1419     {
1420         *s++ = 'w';
1421     }
1422     if ((mode & FS_DIRMODE_SHORTNAME_ONLY) != 0)
1423     {
1424         *s++ = 's';
1425     }
1426     *s++ = '\0';
1427     {
1428         u16    *unipath = NULL;
1429         u16    *fpath = NULL;
1430         // Store Unicode as it is if the Unicode version structure was passed
1431         if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0)
1432         {
1433             unipath = (u16 *)path;
1434         }
1435         // If not, store as Shift_JIS version
1436         // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.)
1437         //
1438         else
1439         {
1440             fpath = FSi_AllocUnicodeFullPath(context, path);
1441             unipath = fpath;
1442         }
1443         // Disable last special wildcard specifications
1444         // Because the path always normalizes and passes the FS library, the possibility of changes to the buffer content is guaranteed.
1445         //
1446         if (*unipath)
1447         {
1448             int     pos;
1449             for (pos = 0; unipath[pos]; ++pos)
1450             {
1451             }
1452             for (--pos; (pos > 0) && (unipath[pos] == L'*'); --pos)
1453             {
1454             }
1455             if (unipath[pos] != L'/')
1456             {
1457                 unipath[++pos] = L'/';
1458             }
1459             unipath[++pos] = L'*';
1460             unipath[++pos] = L'\0';
1461         }
1462         handle = FATFS_OpenDirectoryW(unipath, modestring);
1463         if (handle != FATFS_INVALID_HANDLE)
1464         {
1465             FS_SetDirectoryHandle(file, arc, (void*)handle);
1466             result = FS_RESULT_SUCCESS;
1467         }
1468         else
1469         {
1470             result = FSi_ConvertError(tls->result);
1471         }
1472         FSi_ReleaseUnicodeBuffer(fpath);
1473     }
1474     FATFS_RegisterResultBuffer(tls, FALSE);
1475     (void)baseid;
1476     return result;
1477 }
1478 
1479 /*---------------------------------------------------------------------------*
1480   Name:         FSi_FATFS_CloseDirectory
1481 
1482   Description:  The FS_COMMAND_CLOSEDIRECTORY command.
1483 
1484   Arguments:    arc: Calling archive
1485                 file: Target file
1486 
1487   Returns:      The processing result for the command.
1488  *---------------------------------------------------------------------------*/
FSi_FATFS_CloseDirectory(FSArchive * arc,FSFile * file)1489 static FSResult FSi_FATFS_CloseDirectory(FSArchive *arc, FSFile *file)
1490 {
1491     FSResult                result = FS_RESULT_ERROR;
1492     FATFSDirectoryHandle    handle = (FATFSDirectoryHandle)FS_GetFileUserData(file);
1493     FATFSResultBuffer       tls[1];
1494     FATFS_RegisterResultBuffer(tls, TRUE);
1495     if (FATFS_CloseDirectory(handle))
1496     {
1497         FS_DetachHandle(file);
1498         result = FS_RESULT_SUCCESS;
1499     }
1500     else
1501     {
1502         result = FSi_ConvertError(tls->result);
1503     }
1504     FATFS_RegisterResultBuffer(tls, FALSE);
1505     (void)arc;
1506     return result;
1507 }
1508 
1509 /*---------------------------------------------------------------------------*
1510   Name:         FSi_FATFS_ReadDirectory
1511 
1512   Description:  The FS_COMMAND_READDIR command.
1513 
1514   Arguments:    arc: Calling archive
1515                 file: Target file
1516                 info: Location to store the information
1517 
1518   Returns:      The processing result for the command.
1519  *---------------------------------------------------------------------------*/
FSi_FATFS_ReadDirectory(FSArchive * arc,FSFile * file,FSDirectoryEntryInfo * info)1520 static FSResult FSi_FATFS_ReadDirectory(FSArchive *arc, FSFile *file, FSDirectoryEntryInfo *info)
1521 {
1522     FSResult                result = FS_RESULT_ERROR;
1523     FATFSDirectoryHandle    handle = (FATFSDirectoryHandle)FS_GetFileUserData(file);
1524     FATFSFileInfoW          tmp[1];
1525     FATFSResultBuffer       tls[1];
1526     FATFS_RegisterResultBuffer(tls, TRUE);
1527     if (FATFS_ReadDirectoryW(handle, tmp))
1528     {
1529         // Store Unicode as is if the Unicode version structure was passed
1530         if ((file->stat & FS_FILE_STATUS_UNICODE_MODE) != 0)
1531         {
1532             FSDirectoryEntryInfoW  *infow = (FSDirectoryEntryInfoW *)info;
1533             infow->shortname_length = (u32)STD_GetStringLength(tmp->shortname);
1534             (void)STD_CopyLString(infow->shortname, tmp->shortname, sizeof(infow->shortname));
1535             {
1536                 int     n;
1537                 for (n = 0; (n < FS_ENTRY_LONGNAME_MAX - 1) && tmp->longname[n]; ++n)
1538                 {
1539                     infow->longname[n] = tmp->longname[n];
1540                 }
1541                 infow->longname[n] = L'\0';
1542                 infow->longname_length = (u32)n;
1543             }
1544             infow->attributes = tmp->attributes;
1545             if ((tmp->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0)
1546             {
1547                 infow->attributes |= FS_ATTRIBUTE_IS_DIRECTORY;
1548             }
1549             infow->filesize = tmp->length;
1550             FSi_DostimeToFstime(&infow->atime, tmp->dos_atime);
1551             FSi_DostimeToFstime(&infow->mtime, tmp->dos_mtime);
1552             FSi_DostimeToFstime(&infow->ctime, tmp->dos_ctime);
1553         }
1554         // If not, store as Shift_JIS version
1555         // (However, this is a tentative implementation; in the future, nothing other than the Unicode version will be passed to archives that declare CAPS_UNICODE.)
1556         //
1557         else
1558         {
1559             FSDirectoryEntryInfo   *infoa = (FSDirectoryEntryInfo *)info;
1560             infoa->shortname_length = (u32)STD_GetStringLength(tmp->shortname);
1561             (void)STD_CopyLString(infoa->shortname, tmp->shortname, sizeof(infoa->shortname));
1562             {
1563                 int     dstlen = sizeof(infoa->longname) - 1;
1564                 int     srclen = 0;
1565                 (void)FSi_ConvertStringUnicodeToSjis(infoa->longname, &dstlen, tmp->longname, NULL, NULL);
1566                 infoa->longname[dstlen] = L'\0';
1567                 infoa->longname_length = (u32)dstlen;
1568             }
1569             infoa->attributes = tmp->attributes;
1570             if ((tmp->attributes & FATFS_ATTRIBUTE_DOS_DIRECTORY) != 0)
1571             {
1572                 infoa->attributes |= FS_ATTRIBUTE_IS_DIRECTORY;
1573             }
1574             infoa->filesize = tmp->length;
1575             FSi_DostimeToFstime(&infoa->atime, tmp->dos_atime);
1576             FSi_DostimeToFstime(&infoa->mtime, tmp->dos_mtime);
1577             FSi_DostimeToFstime(&infoa->ctime, tmp->dos_ctime);
1578         }
1579         result = FS_RESULT_SUCCESS;
1580     }
1581     else
1582     {
1583         result = FSi_ConvertError(tls->result);
1584     }
1585     FATFS_RegisterResultBuffer(tls, FALSE);
1586     (void)arc;
1587     return result;
1588 }
1589 
1590 static PMSleepCallbackInfo  FSiPreSleepInfo;
1591 static PMExitCallbackInfo   FSiPostExitInfo;
FSi_SleepProcedure(void * arg)1592 static void FSi_SleepProcedure(void *arg)
1593 {
1594     (void)arg;
1595     (void)FATFS_FlushAll();
1596 }
1597 
FSi_ShutdownProcedure(void * arg)1598 static void FSi_ShutdownProcedure(void *arg)
1599 {
1600     (void)arg;
1601     (void)FATFS_UnmountAll();
1602 }
1603 
1604 /*---------------------------------------------------------------------------*
1605   Name:         FSi_MountFATFSArchive
1606 
1607   Description:  Mounts the FATFS archive.
1608 
1609   Arguments:    None.
1610 
1611   Returns:      None.
1612  *---------------------------------------------------------------------------*/
FSi_MountFATFSArchive(FSFATFSArchiveContext * context,const char * arcname,u8 * tmpbuf)1613 static void FSi_MountFATFSArchive(FSFATFSArchiveContext *context, const char *arcname, u8 *tmpbuf)
1614 {
1615     static const FSArchiveInterface FSiArchiveFATFSInterface =
1616     {
1617         // Commands that are compatible with the old specifications
1618         FSi_FATFS_ReadFile,
1619         FSi_FATFS_WriteFile,
1620         NULL,               // SeekDirectory
1621         FSi_FATFS_ReadDirectory,
1622         NULL,               // FindPath
1623         NULL,               // GetPath
1624         NULL,               // OpenFileFast
1625         NULL,               // OpenFileDirect
1626         FSi_FATFS_CloseFile,
1627         NULL,               // Activate
1628         NULL,               // Idle
1629         NULL,               // Suspend
1630         NULL,               // Resume
1631         // New commands that are compatible with the old specifications
1632         FSi_FATFS_OpenFile,
1633         FSi_FATFS_SeekFile,
1634         FSi_FATFS_GetFileLength,
1635         FSi_FATFS_GetFilePosition,
1636         // Commands extended by the new specifications (UNSUPPORTED if NULL)
1637         NULL,               // Mount
1638         NULL,               // Unmount
1639         FSi_FATFS_GetArchiveCaps,
1640         FSi_FATFS_CreateFile,
1641         FSi_FATFS_DeleteFile,
1642         FSi_FATFS_RenameFile,
1643         FSi_FATFS_GetPathInfo,
1644         FSi_FATFS_SetPathInfo,
1645         FSi_FATFS_CreateDirectory,
1646         FSi_FATFS_DeleteDirectory,
1647         FSi_FATFS_RenameDirectory,
1648         FSi_FATFS_GetArchiveResource,
1649         NULL,               // 29UL
1650         FSi_FATFS_FlushFile,
1651         FSi_FATFS_SetFileLength,
1652         FSi_FATFS_OpenDirectory,
1653         FSi_FATFS_CloseDirectory,
1654         FSi_FATFS_SetSeekCache,
1655     };
1656     u32     arcnamelen = (u32)STD_GetStringLength(arcname);
1657     context->tmpbuf = tmpbuf;
1658     FS_InitArchive(context->arc);
1659     if (FS_RegisterArchiveName(context->arc, arcname, arcnamelen))
1660     {
1661         (void)FS_MountArchive(context->arc, context, &FSiArchiveFATFSInterface, 0);
1662     }
1663 }
1664 
1665 /*---------------------------------------------------------------------------*
1666   Name:         FSi_MountDefaultArchives
1667 
1668   Description:  Mounts the default archive by referencing a startup argument given to IPL.
1669 
1670   Arguments:    None.
1671 
1672   Returns:      None.
1673  *---------------------------------------------------------------------------*/
FSi_MountDefaultArchives(void)1674 void FSi_MountDefaultArchives(void)
1675 {
1676     // Wait until FATFS mounts various physical media
1677     FATFS_Init();
1678     FSi_SetupFATBuffers();
1679     // Set the callback to set flash before sleep and before shutdown
1680     FSiPreSleepInfo.callback = FSi_SleepProcedure;
1681     FSiPostExitInfo.callback = FSi_ShutdownProcedure;
1682     PMi_InsertPreSleepCallbackEx(&FSiPreSleepInfo, PM_CALLBACK_PRIORITY_FS);
1683     PMi_InsertPostExitCallbackEx(&FSiPostExitInfo, PM_CALLBACK_PRIORITY_FS);
1684     // Mount to FS only the physical drive that actually has access rights
1685     if (FSiFATFSDrive && FSiTemporaryBuffer)
1686     {
1687         int                 index = 0;
1688         static const int    max = FS_MOUNTDRIVE_MAX;
1689         const char         *arcname = FATFSi_GetArcnameList();
1690         while ((index < max) && *arcname)
1691         {
1692             FSi_MountFATFSArchive(&FSiFATFSDrive[index], arcname, &FSiTemporaryBuffer[FS_TMPBUF_LENGTH * index]);
1693             arcname += STD_GetStringLength(arcname) + 1;
1694             ++index;
1695         }
1696     }
1697 }
1698 
1699 /*---------------------------------------------------------------------------*
1700   Name:         FSi_MountSpecialArchive
1701 
1702   Description:  Directly mounts a special archive.
1703 
1704   Arguments:    param: Mounting target
1705                 arcname: Archive name to mount
1706                           "otherPub" or "otherPrv" can be specified; when NULL is specified, unmount the previous archive
1707 
1708                 pWork: Work region used for mounting
1709                           It is necessary to retain while mounted
1710 
1711   Returns:      FS_RESULT_SUCCESS if processing was successful.
1712  *---------------------------------------------------------------------------*/
FSi_MountSpecialArchive(u64 param,const char * arcname,FSFATFSArchiveWork * pWork)1713 FSResult FSi_MountSpecialArchive(u64 param, const char *arcname, FSFATFSArchiveWork* pWork)
1714 {
1715     FSResult    result = FS_RESULT_ERROR;
1716     FATFSResultBuffer       tls[1];
1717     FATFS_RegisterResultBuffer(tls, TRUE);
1718     if (!FATFS_MountSpecial(param, arcname, &pWork->slot))
1719     {
1720         result = FSi_ConvertError(tls->result);
1721     }
1722     else
1723     {
1724         if (arcname && *arcname)
1725         {
1726             FSi_MountFATFSArchive(&pWork->context, arcname, pWork->tmpbuf);
1727         }
1728         else
1729         {
1730             (void)FS_UnmountArchive(pWork->context.arc);
1731             (void)FS_ReleaseArchiveName(pWork->context.arc);
1732         }
1733         result = FS_RESULT_SUCCESS;
1734     }
1735     FATFS_RegisterResultBuffer(tls, FALSE);
1736     return result;
1737 }
1738 
1739 /*---------------------------------------------------------------------------*
1740   Name:         FSi_FormatSpecialArchive
1741 
1742   Description:  Formats content of special archive that satisfies the following conditions.
1743                   - Currently mounted
1744                   - Hold your own ownership rights (dataPub, dataPrv, share*)
1745 
1746   Arguments:    path: Path name that includes the archive name
1747 
1748   Returns:      FS_RESULT_SUCCESS if processing was successful.
1749  *---------------------------------------------------------------------------*/
FSi_FormatSpecialArchive(const char * path)1750 FSResult FSi_FormatSpecialArchive(const char *path)
1751 {
1752     FSResult    result = FS_RESULT_ERROR;
1753     FATFSResultBuffer       tls[1];
1754     FATFS_RegisterResultBuffer(tls, TRUE);
1755     if (!FATFS_FormatSpecial(path))
1756     {
1757         result = FSi_ConvertError(tls->result);
1758     }
1759     else
1760     {
1761         result = FS_RESULT_SUCCESS;
1762     }
1763     FATFS_RegisterResultBuffer(tls, FALSE);
1764     return result;
1765 }
1766 
1767 
1768 #include <twl/ltdmain_end.h>
1769 
1770 
1771 #endif /* FS_IMPLEMENT */
1772 
1773 #endif /* SDK_TWL */
1774 
1775 /*---------------------------------------------------------------------------*
1776   Name:         FS_ForceToEnableLatencyEmulation
1777 
1778   Description:  Pseudo-reproduction of random driver latency generated when accessing a degraded NAND device.
1779 
1780 
1781   Arguments:    None.
1782 
1783   Returns:      None.
1784  *---------------------------------------------------------------------------*/
FS_ForceToEnableLatencyEmulation(void)1785 void FS_ForceToEnableLatencyEmulation(void)
1786 {
1787 #if defined(SDK_TWL)
1788     if (OS_IsRunOnTwl())
1789     {
1790         (void)FATFS_SetLatencyEmulation(TRUE);
1791     }
1792 #endif
1793 }
1794