1 /*---------------------------------------------------------------------------*
2   Project:  CARD utilities
3   File:     cardutil.c
4 
5   Copyright 2000-2001 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   $Log: cardutil.c,v $
14   Revision 1.2  02/20/2006 04:13:08  mitu
15   changed include path from dolphin/ to revolution/.
16 
17   Revision 1.1  01/31/2006 10:48:30  mitu
18   (none)
19 
20 
21     6     11/26/01 11:54 Shiki
22     Modified DoSave() to add CARD_XFER_WRITE bytes to CardControl.length.
23 
24     5     9/25/01 18:27 Shiki
25     Fixed DoList() to perform the same CARD_STAT_ICON_NONE animation as IPL
26     does.
27 
28     4     5/18/01 5:24p Shiki
29     Added CardUtilGetProgress().
30 
31     3     01/04/26 10:29 Shiki
32     Fixed CardUtilDrawIcon() to setup TexGen.
33 
34     2     01/04/25 14:32 Shiki
35     Added size param to CardUtilDrawIcon().
36 
37     1     01/04/23 17:15 Shiki
38     Initial check-in.
39   $NoKeywords: $
40  *---------------------------------------------------------------------------*/
41 
42 #include <string.h>
43 #include <demo.h>
44 #include <revolution/card.h>
45 #include "cardutil.h"
46 
47 typedef struct ControlBlock
48 {
49     OSMutex         mutex;          // mutex for control block
50     OSCond          cond;
51 
52     s32             slot;
53     s32             command;
54     s32             fileNo;
55     void*           param;
56     s32             result;
57 
58     s32             byteNotUsed;
59     s32             filesNotUsed;
60     u32             sectorSize;
61 
62     s32             xferred;        // the initial transferred bytes for the current command
63     s32             length;         // the total transfer bytes for the current command
64 
65     OSMutex         mutexDirectory; // mutex for directory and numFiles
66     CardUtilDirent* directory;
67     s32             numFiles;
68 } ControlBlock;
69 
70 static OSThread      CardThread;
71 static ControlBlock  CardControl;
72 
73 /*---------------------------------------------------------------------------*
74   Name:         CardUtilNumFiles
75 
76   Description:  Returns the current number of own game files in the directory
77 
78   Arguments:    None.
79 
80   Returns:      The current number of own game files in the directory
81  *---------------------------------------------------------------------------*/
CardUtilNumFiles(void)82 s32 CardUtilNumFiles(void)
83 {
84     return CardControl.numFiles;
85 }
86 
87 /*---------------------------------------------------------------------------*
88   Name:         CardUtilLockDirectory
89 
90   Description:  Locks the directory and returns the current number of own
91                 game files in the directory. Card utility thread waits
92                 updating the directory until CardUtilUnlockDirectory() is
93                 called.
94 
95   Arguments:    None.
96 
97   Returns:      The current number of own game files in the directory.
98  *---------------------------------------------------------------------------*/
CardUtilLockDirectory(void)99 s32 CardUtilLockDirectory(void)
100 {
101     OSLockMutex(&CardControl.mutexDirectory);
102     return CardControl.numFiles;
103 }
104 
105 /*---------------------------------------------------------------------------*
106   Name:         CardUtilUnlockDirectory
107 
108   Description:  Unlocks the directory
109 
110   Arguments:    None.
111 
112   Returns:      None.
113  *---------------------------------------------------------------------------*/
CardUtilUnlockDirectory(void)114 void CardUtilUnlockDirectory(void)
115 {
116     OSUnlockMutex(&CardControl.mutexDirectory);
117 }
118 
119 /*---------------------------------------------------------------------------*
120   Name:         CardUtilByteNotUsed
121 
122   Description:  Returns the number of free bytes available in the current
123                 memory card
124 
125   Arguments:    None.
126 
127   Returns:      The number of free bytes available in the current
128                 memory card
129  *---------------------------------------------------------------------------*/
CardUtilByteNotUsed(void)130 s32 CardUtilByteNotUsed(void)
131 {
132     return CardControl.byteNotUsed;
133 }
134 
135 /*---------------------------------------------------------------------------*
136   Name:         CardUtilBlocksNotUsed
137 
138   Description:  Returns the number of free blocks available in the current
139                 memory card
140 
141   Arguments:    None.
142 
143   Returns:      The number of free blocks available in the current
144                 memory card
145  *---------------------------------------------------------------------------*/
CardUtilBlocksNotUsed(void)146 s32 CardUtilBlocksNotUsed(void)
147 {
148     if (CardControl.sectorSize)
149     {
150         return (s32) (CardControl.byteNotUsed / CardControl.sectorSize);
151     }
152     return 0;
153 }
154 
155 /*---------------------------------------------------------------------------*
156   Name:         CardUtilFilesNotUsed
157 
158   Description:  Returns the number of free directory entries available in the
159                 current memory card
160 
161   Arguments:    None.
162 
163   Returns:      The number of free directory entries available in the
164                 current memory card
165  *---------------------------------------------------------------------------*/
CardUtilFilesNotUsed(void)166 s32 CardUtilFilesNotUsed(void)
167 {
168     return CardControl.filesNotUsed;
169 }
170 
171 /*---------------------------------------------------------------------------*
172   Name:         CardUtilSectorSize
173 
174   Description:  Returns the sector size of the current memory card
175 
176   Arguments:    None.
177 
178   Returns:      The sector size of the current memory card
179  *---------------------------------------------------------------------------*/
CardUtilSectorSize(void)180 s32 CardUtilSectorSize(void)
181 {
182     return (s32) CardControl.sectorSize;
183 }
184 
185 /*---------------------------------------------------------------------------*
186   Name:         DoMount
187 
188   Description:  Performs the mount operation
189  *---------------------------------------------------------------------------*/
DoMount(s32 slot,void * workArea)190 static s32 DoMount(s32 slot, void* workArea)
191 {
192     s32 result;
193     s32 resultSectorSize;
194 
195     CardUtilLockDirectory();
196         CardControl.numFiles = 0;
197     CardUtilUnlockDirectory();
198 
199     CardControl.byteNotUsed = CardControl.filesNotUsed = 0;
200 
201     // Mount and check
202     CardControl.length = CARD_XFER_MOUNT;
203     result = CARDMount(slot, workArea, 0);
204     switch (result)
205     {
206       case CARD_RESULT_READY:
207       case CARD_RESULT_BROKEN:
208         resultSectorSize = CARDGetSectorSize(slot, &CardControl.sectorSize);
209         if (resultSectorSize < 0)
210         {
211             return resultSectorSize;
212         }
213         result = CARDCheck(slot);
214         break;
215       case CARD_RESULT_ENCODING:
216         resultSectorSize = CARDGetSectorSize(slot, &CardControl.sectorSize);
217         if (resultSectorSize < 0)
218         {
219             return resultSectorSize;
220         }
221         break;
222       default:
223         // Memory card is not mounted.
224         break;
225     }
226 
227     // Free blocks
228     if (result == CARD_RESULT_READY)
229     {
230         result = CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed);
231     }
232     return result;
233 }
234 
235 /*---------------------------------------------------------------------------*
236   Name:         DoMount
237 
238   Description:  Performs the unmount operation
239  *---------------------------------------------------------------------------*/
DoUnmount(s32 slot)240 static s32 DoUnmount(s32 slot)
241 {
242     CardUtilLockDirectory();
243         CardControl.numFiles  = 0;
244     CardUtilUnlockDirectory();
245 
246     return CARDUnmount(slot);
247 }
248 
249 /*---------------------------------------------------------------------------*
250   Name:         DoFormat
251 
252   Description:  Performs the format operation
253  *---------------------------------------------------------------------------*/
DoFormat(s32 slot)254 static s32 DoFormat(s32 slot)
255 {
256     s32 result;
257 
258     CardUtilLockDirectory();
259         CardControl.numFiles  = 0;
260     CardUtilUnlockDirectory();
261 
262     // Format
263     CardControl.length = CARD_XFER_FORMAT;
264     result = CARDFormat(slot);
265 
266     // FreeBlocks
267     if (result == CARD_RESULT_READY)
268     {
269         result = CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed);
270     }
271     return result;
272 }
273 
274 /*---------------------------------------------------------------------------*
275   Name:         DoErase
276 
277   Description:  Performs the erase operation and updates the directory
278  *---------------------------------------------------------------------------*/
DoErase(s32 slot,s32 fileNo)279 static s32 DoErase(s32 slot, s32 fileNo)
280 {
281     s32 result;
282 
283     // Delete
284     CardControl.length = CARD_XFER_DELETE;
285     result = CARDFastDelete(slot, fileNo);
286     if (result < 0)
287     {
288         return result;
289     }
290 
291     // Update directory
292     if (CardControl.directory)
293     {
294         CardUtilDirent* ent;
295 
296         for (ent = CardControl.directory;
297              ent < &CardControl.directory[CardControl.numFiles];
298              ++ent)
299         {
300             if (ent->fileNo == fileNo)
301             {
302                 CardUtilLockDirectory();
303                     memmove(ent, ent + 1, (u32) &CardControl.directory[CardControl.numFiles] - (u32) (ent + 1));
304                     --CardControl.numFiles;
305                     DCStoreRange(ent, (u32) &CardControl.directory[CardControl.numFiles] - (u32) ent);
306                 CardUtilUnlockDirectory();
307             }
308         }
309     }
310 
311     // FreeBlocks
312     return CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed);
313 }
314 
315 /*---------------------------------------------------------------------------*
316   Name:         DoList
317 
318   Description:  Updates the directory.
319 
320   Note:         DoList() works with DoSave() to support reliable file
321                 save. If temporary files, whose name begin with '~', remains,
322                 DoList() rescues and/or erases temporary files if possible.
323 
324                 If the memory card becomes unavailable here due to power
325                 failure, etc. while saving the data, the following scenario
326                 can happen.
327 
328                 1. Both temp file and original file exist.
329 
330                    -> DoList() removes the temp file.
331 
332                 2. Only temp file exits.
333 
334                    -> If the temp file is valid, DoList() renames the temp
335                       file to the original file name.
336                    -> If the temp file data is invalid, DoList removes the
337                       temp file. Probably, the player copied the broken
338                       temp file to another memory card.
339  *---------------------------------------------------------------------------*/
DoList(s32 slot,CardUtilDirent * directory)340 static s32 DoList(s32 slot, CardUtilDirent* directory)
341 {
342     s32          fileNo;
343     CARDFileInfo fileInfo;
344     s32          result;
345     s32          offset;
346     s32          length;
347 
348     int          i;
349     int          j;
350     int          cIcon;
351     int          speed;
352 
353     DVDDiskID*   diskID = DVDGetCurrentDiskID();
354 
355     result = CARD_RESULT_READY;
356 
357     CardUtilLockDirectory();
358         CardControl.directory = directory;
359         CardControl.numFiles  = 0;
360     CardUtilUnlockDirectory();
361 
362     if (directory == 0)
363     {
364         return result;
365     }
366 
367     memset(directory, 0, CARD_MAX_FILE * sizeof(CardUtilDirent));
368     for (fileNo = 0; fileNo < CARD_MAX_FILE; ++fileNo)
369     {
370         CardUtilDirent* ent = &directory[CardControl.numFiles];
371 
372         // Skip open entries and other game entries.
373         if (CARDGetStatus(slot, fileNo, &ent->stat) < 0 ||
374             memcmp(ent->stat.gameName, diskID->gameName, sizeof(diskID->gameName)) != 0 ||
375             memcmp(ent->stat.company,  diskID->company,  sizeof(diskID->company))  != 0)
376         {
377             continue;
378         }
379 
380         // Rescue/erase temp file
381         if (ent->stat.fileName[0] == '~')
382         {
383             char fileName[CARD_FILENAME_MAX + 1];
384             char tempName[CARD_FILENAME_MAX + 1];
385 
386             strncpy(tempName, ent->stat.fileName, CARD_FILENAME_MAX);
387             tempName[CARD_FILENAME_MAX] = '\0';
388             strncpy(fileName, &tempName[1],       CARD_FILENAME_MAX);
389             fileName[CARD_FILENAME_MAX] = '\0';
390 
391             if (ent->stat.commentAddr <= ent->stat.length - CARD_COMMENT_SIZE &&    // Comment available?
392                 CARDRename(slot, tempName, fileName) == CARD_RESULT_READY)
393             {
394                 // Temp file was rescued as save data.
395                 --fileNo;   // Retry with the current fileNo.
396             }
397             else if (// Original file still exists or file is invalid
398                      (result = CARDFastDelete(slot, fileNo)) < 0 ||
399                      // Update free blocks
400                      (result = CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed)) < 0)
401             {
402                 return result;
403             }
404             continue;
405             // NOT REACHED HERE
406         }
407 
408         // Read comment
409         memset(ent->comment, 0, CARD_COMMENT_SIZE);
410         if (ent->stat.commentAddr <= ent->stat.length - CARD_COMMENT_SIZE)
411         {
412             result = CARDFastOpen(slot, fileNo, &fileInfo);
413             if (result < 0)
414             {
415                 return result;
416             }
417 
418             offset = (s32) ent->stat.commentAddr & ~(CARD_READ_SIZE - 1);
419             length = (s32) (ent->stat.commentAddr + CARD_COMMENT_SIZE - offset);
420             length = (length + (CARD_READ_SIZE - 1)) & ~(CARD_READ_SIZE - 1);
421             result = CARDRead(&fileInfo, ent, length, offset);
422             CARDClose(&fileInfo);
423             if (result < 0)
424             {
425                 return result;
426             }
427 
428             offset = (s32) (ent->stat.commentAddr & (CARD_READ_SIZE - 1));
429             memmove(ent->comment, (u8*) ent + offset, CARD_COMMENT_SIZE);
430         }
431 
432         // Read banner and icon data
433         if ((ent->stat.bannerFormat || ent->stat.iconFormat) &&
434             ent->stat.offsetData <= ent->stat.length &&
435             ent->stat.iconAddr < ent->stat.offsetData)
436         {
437             result = CARDFastOpen(slot, fileNo, &fileInfo);
438             if (result < 0)
439             {
440                 return result;
441             }
442 
443             offset = (s32) ent->stat.iconAddr & ~(CARD_READ_SIZE - 1);
444             length = (s32) (ent->stat.offsetData - offset);
445             length = (length + (CARD_READ_SIZE - 1)) & ~(CARD_READ_SIZE - 1);
446             result = CARDRead(&fileInfo, ent, length, offset);
447             CARDClose(&fileInfo);
448             if (result < 0)
449             {
450                 return result;
451             }
452 
453             offset = (s32) (ent->stat.iconAddr & (CARD_READ_SIZE - 1));
454             memmove(ent, (u8*) ent + offset, ent->stat.offsetData - ent->stat.iconAddr);
455             DCFlushRange(ent, ent->stat.offsetData - ent->stat.iconAddr);
456 
457             j = 0;
458             ent->cFrame = 0;
459             for (cIcon = 0; cIcon < CARD_ICON_MAX; ++cIcon, ++j)
460             {
461                 speed = CARDGetIconSpeed(&ent->stat, cIcon);
462                 if (speed == CARD_STAT_SPEED_END)
463                 {
464                     break;
465                 }
466                 ent->nFrame[j] = ent->cFrame;
467                 ent->cFrame += 4 * speed;
468                 if (CARDGetIconFormat(&ent->stat, cIcon) != CARD_STAT_ICON_NONE)
469                 {
470                     ent->iIcon[j] = cIcon;
471                 }
472                 else
473                 {
474                     // Pick up next one
475                     ent->iIcon[j] = 0;
476                     for (i = cIcon; i < CARD_ICON_MAX; ++i)
477                     {
478                         if (CARDGetIconFormat(&ent->stat, i) != CARD_STAT_ICON_NONE)
479                         {
480                             ent->iIcon[j] = i;
481                             break;
482                         }
483                     }
484                 }
485             }
486             if (CARDGetIconAnim(&ent->stat) == CARD_STAT_ANIM_BOUNCE && 2 < cIcon)
487             {
488                 for (i = cIcon - 2; 0 < i; --i, ++j)
489                 {
490                     speed = CARDGetIconSpeed(&ent->stat, i);
491                     ASSERT(speed != CARD_STAT_SPEED_END);
492                     ent->nFrame[j] = ent->cFrame;
493                     ent->iIcon[j] = ent->iIcon[i];
494                     ent->cFrame += 4 * speed;
495                 }
496             }
497         }
498 
499         ent->fileNo = fileNo;
500 
501         CardUtilLockDirectory();
502             ++CardControl.numFiles;
503         CardUtilUnlockDirectory();
504     }
505     return result;
506 }
507 
508 /*---------------------------------------------------------------------------*
509   Name:         DoOpen
510 
511   Description:  Reads the specified file.
512  *---------------------------------------------------------------------------*/
DoOpen(s32 slot,s32 fileNo,void * buffer)513 static s32 DoOpen(s32 slot, s32 fileNo, void* buffer)
514 {
515     s32          result;
516     CARDStat     stat;
517     CARDFileInfo fileInfo;
518 
519     result = CARDGetStatus(slot, fileNo, &stat);
520     if (result < 0)
521     {
522         return result;
523     }
524 
525     result = CARDFastOpen(slot, fileNo, &fileInfo);
526     if (result < 0)
527     {
528         return result;
529     }
530 
531     CardControl.length = (s32) stat.length;
532     result = CARDRead(&fileInfo, buffer, (s32) stat.length, 0);
533     CARDClose(&fileInfo);
534     return result;
535 }
536 
537 /*---------------------------------------------------------------------------*
538   Name:         DoSave
539 
540   Description:  Saves the specified file.
541 
542   Note:         This function performs reliable file save by saving data
543                 into temporary file first. Thus it requires the same number
544                 of temporary free blocks as the number of saved
545                 file consumes, and also one free file directory entry.
546                 Note temporary file name begins with '~', and thus the game
547                 program should choose filenames that not begin with '~'.
548  *---------------------------------------------------------------------------*/
DoSave(s32 slot,CARDStat * stat,void * buffer)549 static s32 DoSave(s32 slot, CARDStat* stat, void* buffer)
550 {
551     CARDFileInfo    fileInfo;
552     char            fileName[CARD_FILENAME_MAX + 1];
553     char            tempName[CARD_FILENAME_MAX + 1];
554     s32             result;
555     s32             fileNo;
556     s32             oldNo;
557     CardUtilDirent* ent;
558 
559     strncpy(fileName, stat->fileName, CARD_FILENAME_MAX);
560     fileName[CARD_FILENAME_MAX] = '\0';
561     if (CARD_FILENAME_MAX <= strlen(fileName))
562     {
563         return CARD_RESULT_NAMETOOLONG;
564     }
565     if (fileName[0] == '~')
566     {
567         return CARD_RESULT_FATAL_ERROR;
568     }
569 
570     // Creates temporary file name from fileName by attaching '~' at
571     // the beginning.
572     tempName[0] = '~';
573     strncpy(&tempName[1], stat->fileName, CARD_FILENAME_MAX - 1);
574     tempName[CARD_FILENAME_MAX] = '\0';
575 
576     // To perform overwrite, verifies if the original file exists.
577     oldNo = -1;
578     result = CARDOpen(slot, fileName, &fileInfo);
579     if (result == CARD_RESULT_READY)
580     {
581         // Gets original file number
582         oldNo = CARDGetFileNo(&fileInfo);
583         CARDClose(&fileInfo);
584     }
585 
586     CardControl.length = (s32) stat->length + CARD_XFER_CREATE + CARD_XFER_WRITE + CARD_XFER_SETSTATUS + CARD_XFER_RENAME;
587     if (0 <= oldNo && oldNo < CARD_MAX_FILE)
588     {
589         CardControl.length += CARD_XFER_DELETE;
590     }
591 
592     // Tries to create temporary file
593     result = CARDCreate(slot, tempName, stat->length, &fileInfo);
594     if (result < 0)
595     {
596         return result;
597     }
598 
599     // Saves the data to the temporary file.
600     // Performs CARDSetStatus() at very last so the program can assume
601     // the temporary file has valid save data if its comment and
602     // other directory infomation is valid. Note CARD API guarantees the
603     // system block integrity.
604     fileNo = CARDGetFileNo(&fileInfo);
605     result = CARDWrite(&fileInfo, buffer, (s32) stat->length, 0);
606     CARDClose(&fileInfo);
607     if (result < 0 || (result = CARDSetStatus(slot, fileNo, stat)) < 0)
608     {
609         return result;
610     }
611 
612     // To perform overwrite, deletes the original file if exists.
613     if (0 <= oldNo && oldNo < CARD_MAX_FILE)
614     {
615         // Delete original file
616         result = CARDFastDelete(slot, oldNo);
617         if (result < 0)
618         {
619             return result;
620         }
621     }
622 
623     // If the memory card becomes unavailable here due to power failure, etc.
624     // DoList() renames the temp file to the original file name as it has the
625     // valid data. If both temp file and original file exist in the same
626     // memory card, DoList() removes the temp file.
627 
628     // Renames the temp file name to the final name
629     result = CARDRename(slot, tempName, fileName);
630     if (result < 0)
631     {
632         return result;
633     }
634 
635     if (CardControl.directory == 0)
636     {
637         // FreeBlocks
638         return CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed);
639         // NOT REACHED HERE
640     }
641 
642     // Locks and updates directory
643     CardUtilLockDirectory();
644 
645         if (oldNo == -1)
646         {
647             ent = &CardControl.directory[CardControl.numFiles];
648             ++CardControl.numFiles;
649         }
650         else
651         {
652             for (ent = CardControl.directory;
653                  ent < &CardControl.directory[CardControl.numFiles];
654                  ++ent)
655             {
656                 if (ent->fileNo == oldNo)
657                 {
658                     break;
659                 }
660             }
661             if (ent == &CardControl.directory[CardControl.numFiles])
662             {
663                 ++CardControl.numFiles;
664             }
665         }
666         ASSERT(CardControl.numFiles <= CARD_MAX_FILE);
667 
668         // Read comment
669         memset(ent->comment, 0, CARD_COMMENT_SIZE);
670         if (stat->commentAddr <= stat->length - CARD_COMMENT_SIZE)
671         {
672             memmove(ent->comment, (u8*) buffer + stat->commentAddr, CARD_COMMENT_SIZE);
673         }
674 
675         // Read banner and icon data
676         ent->cFrame = 0;
677         if (stat->bannerFormat || stat->iconFormat)
678         {
679             int i;
680             int j;
681             int cIcon;
682             int speed;
683 
684             ASSERT(stat->iconAddr < stat->length);
685             ASSERT(stat->offsetData < stat->length);
686             ASSERT(stat->iconAddr < stat->offsetData);
687             memmove(ent, (u8*) buffer + stat->iconAddr, stat->offsetData - stat->iconAddr);
688             DCFlushRange(ent, stat->offsetData - stat->iconAddr);
689 
690             j = 0;
691             for (cIcon = 0, i = 0; cIcon < CARD_ICON_MAX; ++cIcon, ++j)
692             {
693                 speed = CARDGetIconSpeed(stat, cIcon);
694                 if (speed == CARD_STAT_SPEED_END)
695                 {
696                     break;
697                 }
698                 ent->nFrame[j] = ent->cFrame;
699                 ent->iIcon[j] = i;
700                 ent->cFrame += 4 * speed;
701                 if (CARDGetIconFormat(stat, i) != CARD_STAT_ICON_NONE)
702                 {
703                     ++i;
704                 }
705             }
706             if (CARDGetIconAnim(stat) == CARD_STAT_ANIM_BOUNCE && 2 < cIcon)
707             {
708                 for (i = cIcon - 2; 0 < i; --i, ++j)
709                 {
710                     speed = CARDGetIconSpeed(stat, i);
711                     ASSERT(speed != CARD_STAT_SPEED_END);
712                     ent->nFrame[j] = ent->cFrame;
713                     ent->iIcon[j] = ent->iIcon[i];
714                     ent->cFrame += 4 * speed;
715                 }
716             }
717         }
718 
719         memcpy(&ent->stat, stat, sizeof(CARDStat));
720         ent->fileNo = fileNo;
721 
722     CardUtilUnlockDirectory();
723 
724     // FreeBlocks
725     return CARDFreeBlocks(slot, &CardControl.byteNotUsed, &CardControl.filesNotUsed);
726 }
727 
728 /*---------------------------------------------------------------------------*
729   Name:         CardUtilCommand
730 
731   Description:  Issues a command to the card utility thread.
732 
733                 The game threads communicate to the card utility thread via
734                 the CardControl block, which is guarded by a mutex.
735  *---------------------------------------------------------------------------*/
CardUtilCommand(s32 slot,s32 command,s32 fileNo,void * param)736 static s32 CardUtilCommand(s32 slot, s32 command, s32 fileNo, void* param)
737 {
738     s32 result;
739 
740     OSLockMutex(&CardControl.mutex);
741 
742     // CardUtil accepts one command at a time
743     ASSERT(CardControl.slot == -1);
744 
745     if (CardControl.slot != -1)
746     {
747         // Card utility thread is busy
748         result = CardControl.result;
749     }
750     else
751     {
752         // Card utility thread is idle. Save command infomation and
753         // wakes up card utility threads.
754         CardControl.slot    = slot;
755         CardControl.command = command;
756         CardControl.fileNo  = fileNo;
757         CardControl.param   = param;
758         CardControl.result  = CARD_RESULT_BUSY;
759         if (command != CARDUTIL_CMD_LIST)
760         {
761             CardControl.xferred = CARDGetXferredBytes(slot);
762         }
763         result = CARD_RESULT_READY;
764         OSSignalCond(&CardControl.cond);
765     }
766     OSUnlockMutex(&CardControl.mutex);
767     return result;
768 }
769 
770 /*---------------------------------------------------------------------------*
771   Name:         CardUtilResultCode
772 
773   Description:  Gets the last result code
774 
775   Arguments:    None.
776 
777   Returns:      The last result code
778  *---------------------------------------------------------------------------*/
CardUtilResultCode(void)779 s32 CardUtilResultCode(void)
780 {
781     return CardControl.result;
782 }
783 
784 /*---------------------------------------------------------------------------*
785   Name:         CardUtilMount
786 
787   Description:  Requests the mount operation to the card utility thread.
788                 The implementation is in DoMount().
789 
790   Arguments:    slot        Memory card slot number
791                 workArea    Work area for CARDMount()
792 
793   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
794  *---------------------------------------------------------------------------*/
CardUtilMount(s32 slot,void * workArea)795 s32 CardUtilMount(s32 slot, void* workArea)
796 {
797     return CardUtilCommand(slot, CARDUTIL_CMD_MOUNT, 0, workArea);
798 }
799 
800 /*---------------------------------------------------------------------------*
801   Name:         CardUtilUnmount
802 
803   Description:  Requests the unmount operation to the card utility thread
804                 The implementation is in DoUnmount().
805 
806   Arguments:    slot        Memory card slot number
807 
808   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
809  *---------------------------------------------------------------------------*/
CardUtilUnmount(s32 slot)810 s32 CardUtilUnmount(s32 slot)
811 {
812     return CardUtilCommand(slot, CARDUTIL_CMD_UNMOUNT, 0, 0);
813 }
814 
815 /*---------------------------------------------------------------------------*
816   Name:         CardUtilList
817 
818   Description:  Requests the list operation to the card utility thread
819                 The implementation is in DoList().
820 
821   Arguments:    slot        Memory card slot number
822                 directory   Pointer to directory
823 
824   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
825  *---------------------------------------------------------------------------*/
CardUtilList(s32 slot,CardUtilDirent * directory)826 s32 CardUtilList(s32 slot, CardUtilDirent* directory)
827 {
828     return CardUtilCommand(slot, CARDUTIL_CMD_LIST, 0, directory);
829 }
830 
831 /*---------------------------------------------------------------------------*
832   Name:         CardUtilFormat
833 
834   Description:  Requests the format operation to the card utility thread
835                 The implementation is in DoFormat().
836 
837   Arguments:    slot        Memory card slot number
838 
839   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
840  *---------------------------------------------------------------------------*/
CardUtilFormat(s32 slot)841 s32 CardUtilFormat(s32 slot)
842 {
843     return CardUtilCommand(slot, CARDUTIL_CMD_FORMAT, 0, 0);
844 }
845 
846 /*---------------------------------------------------------------------------*
847   Name:         CardUtilErase
848 
849   Description:  Requests the erase operation to the card utility thread
850                 The implementation is in DoErase().
851 
852   Arguments:    slot        Memory card slot number
853 
854   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
855  *---------------------------------------------------------------------------*/
CardUtilErase(s32 slot,s32 fileNo)856 s32 CardUtilErase(s32 slot, s32 fileNo)
857 {
858     return CardUtilCommand(slot, CARDUTIL_CMD_ERASE, fileNo, 0);
859 }
860 
861 /*---------------------------------------------------------------------------*
862   Name:         CardUtilOpen
863 
864   Description:  Requests the open operation to the card utility thread
865                 The implementation is in DoOpen().
866 
867   Arguments:    slot        Memory card slot number
868                 fileNo      File number to open
869                 buffer      Pointer to read data buffer
870 
871   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
872  *---------------------------------------------------------------------------*/
CardUtilOpen(s32 slot,s32 fileNo,void * buffer)873 s32 CardUtilOpen(s32 slot, s32 fileNo, void* buffer)
874 {
875     return CardUtilCommand(slot, CARDUTIL_CMD_OPEN, fileNo, buffer);
876 }
877 
878 /*---------------------------------------------------------------------------*
879   Name:         CardUtilSave
880 
881   Description:  Requests the save operation to the card utility thread
882                 The implementation is in DoOpen().
883 
884   Arguments:    slot        Memory card slot number
885                 stat        pointer to CARDStat. The following members must
886                             be initialized properly.
887                                 fileName, length, iconAddr, commentAddr.
888                 buffer      Pointer to save data buffer. Banner, icon,
889                             comment data must be properly set up in the
890                             buffer.
891 
892   Returns:      CARD_RESULT_READY if succeeded. Otherwise CARD_RESULT_BUSY.
893  *---------------------------------------------------------------------------*/
CardUtilSave(s32 slot,CARDStat * stat,void * buffer)894 s32 CardUtilSave(s32 slot, CARDStat* stat, void* buffer)
895 {
896     return CardUtilCommand(slot, CARDUTIL_CMD_SAVE, (s32) stat, buffer);
897 }
898 
899 /*---------------------------------------------------------------------------*
900   Name:         CardUtilMain
901 
902   Description:  The main program for the card utility thread. It takes the
903                 next command from CardControl and execute the specified
904                 operation.
905  *---------------------------------------------------------------------------*/
CardUtilMain(void * param)906 static void* CardUtilMain(void* param)
907 {
908     s32 slot;
909     s32 command;
910     s32 result;
911     s32 fileNo;
912 
913     for (;;)
914     {
915         OSLockMutex(&CardControl.mutex);
916         while (CardControl.slot == -1)
917         {
918             // No command is issued so far. Waits until any command
919             // is issued.
920             OSWaitCond(&CardControl.cond, &CardControl.mutex);
921         }
922         slot    = CardControl.slot;
923         command = CardControl.command;
924         fileNo  = CardControl.fileNo;
925         param   = CardControl.param;
926         OSUnlockMutex(&CardControl.mutex);
927 
928         switch (command)
929         {
930           case CARDUTIL_CMD_MOUNT:
931             result = DoMount(slot, param);
932             break;
933           case CARDUTIL_CMD_UNMOUNT:
934             result = DoUnmount(slot);
935             break;
936           case CARDUTIL_CMD_FORMAT:
937             result = DoFormat(slot);
938             break;
939           case CARDUTIL_CMD_LIST:
940             result = DoList(slot, param);
941             break;
942           case CARDUTIL_CMD_ERASE:
943             result = DoErase(slot, fileNo);
944             break;
945           case CARDUTIL_CMD_OPEN:
946             result = DoOpen(slot, fileNo, param);
947             break;
948           case CARDUTIL_CMD_SAVE:
949             result = DoSave(slot, (CARDStat*) fileNo, param);
950             break;
951         }
952 
953         OSLockMutex(&CardControl.mutex);
954         CardControl.result = result;
955         CardControl.slot = -1;
956         OSUnlockMutex(&CardControl.mutex);
957     }
958     return NULL;
959 }
960 
961 /*---------------------------------------------------------------------------*
962   Name:         CardUtilInit
963 
964   Description:  The card utility functions executes the requested command
965                 concurrently using thread. CardUtilInit() initializes the
966                 card utility thread.
967 
968   Arguments:    stackBase   Address of initial stack pointer. Note that
969                             stacks grow DOWN, so this should be the highest
970                             addressable location in the stack
971                 stackSize   Size of the stack
972                 priority    Base scheduling priority for card utility thread
973 
974   Returns:      None.
975  *---------------------------------------------------------------------------*/
CardUtilInit(void * stackBase,u32 stackSize,OSPriority priority)976 void CardUtilInit(void* stackBase, u32 stackSize, OSPriority priority)
977 {
978     ASSERT(sizeof(CardUtilDirent) % 32 == 0);
979     CARDInit();
980     OSInitMutex(&CardControl.mutex);
981     OSInitMutex(&CardControl.mutexDirectory);
982     OSInitCond(&CardControl.cond);
983     OSCreateThread(
984         &CardThread,
985         CardUtilMain,
986         0,
987         stackBase,
988         stackSize,
989         priority,
990         OS_THREAD_ATTR_DETACH);
991     OSResumeThread(&CardThread);
992 }
993 
994 /*---------------------------------------------------------------------------*
995   Name:         CardUtilDrawIcon
996 
997   Description:  Simple utility function to draw banner and icon texture
998                 image to the screen.
999 
1000   Arguments:    x           screen x pos
1001                 y           screen y pos
1002                 size        pixel width of image
1003                 image       texture image
1004                 tlut        tlut
1005                 width       texel width of image
1006                 height      texel height of image
1007                 format      texture format
1008 
1009   Returns:      None.
1010  *---------------------------------------------------------------------------*/
CardUtilDrawIcon(int x,int y,int size,void * image,void * tlut,u16 width,u16 height,int format)1011 void CardUtilDrawIcon(int x, int y, int size, void* image, void* tlut, u16 width, u16 height, int format)
1012 {
1013     GXTexObj  texObj;
1014     GXTlutObj tlutObj;
1015     Mtx       m;
1016     s16       posLeft   = (s16) x;
1017     s16       posRight  = (s16) (posLeft + size * width / width);
1018     s16       posTop    = (s16) y;
1019     s16       posBottom = (s16) (y + (height * size / width) * height / height);
1020 
1021     if (format == CARD_STAT_ICON_RGB5A3)
1022     {
1023         GXInitTexObj(&texObj,           // obj
1024                      image,             // image
1025                      width,             // weight
1026                      height,            // height
1027                      GX_TF_RGB5A3,      // format
1028                      GX_CLAMP,          // wrap_s      (don't care)
1029                      GX_CLAMP,          // wrap_t (don't care)
1030                      GX_FALSE);         // mipmap (don't care)
1031     }
1032     else if (format == CARD_STAT_ICON_C8)
1033     {
1034         ASSERT(format == CARD_STAT_ICON_C8);
1035         GXInitTlutObj(&tlutObj,
1036                       tlut,
1037                       GX_TL_RGB5A3,
1038                       256);
1039 
1040         GXInitTexObjCI(&texObj,         // obj
1041                        image,           // image
1042                        width,           // weight
1043                        height,          // height
1044                        GX_TF_C8,        // format
1045                        GX_CLAMP,        // wrap_s      (don't care)
1046                        GX_CLAMP,        // wrap_t (don't care)
1047                        GX_FALSE,        // mipmap (don't care)
1048                        GX_TLUT0);
1049 
1050         GXLoadTlut(&tlutObj, GX_TLUT0);
1051     }
1052     else
1053     {
1054         return;
1055     }
1056 
1057     GXLoadTexObj(&texObj, GX_TEXMAP0);
1058     MTXScale(m, 1.0f / width, 1.0f / height, 1.0f);
1059     GXLoadTexMtxImm(m, GX_TEXMTX0, GX_MTX2x4);
1060     GXSetNumTexGens(1);
1061     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
1062 
1063     GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
1064 
1065     // Set up vertex descriptors
1066     GXClearVtxDesc();
1067     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
1068     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
1069     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS,  GX_POS_XYZ, GX_S16, 0);
1070     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST,  GX_S16, 0);
1071 
1072     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
1073 
1074     GXPosition3s16(posLeft , posTop   , 0);
1075     GXTexCoord2s16((s16) 0,           (s16) 0);
1076 
1077     GXPosition3s16(posRight, posTop   , 0);
1078     GXTexCoord2s16((s16) width,       (s16) 0);
1079 
1080     GXPosition3s16(posRight, posBottom, 0);
1081     GXTexCoord2s16((s16) width,       (s16) height);
1082 
1083     GXPosition3s16(posLeft , posBottom, 0);
1084     GXTexCoord2s16((s16) 0,           (s16) height);
1085 
1086     GXEnd();
1087 }
1088 
1089 /*---------------------------------------------------------------------------*
1090   Name:         CardUtilDrawIcon
1091 
1092   Description:  Simple utility function to draw animated icon texture.
1093 
1094   Arguments:    ent         pointer to directory entry to draw icon
1095                 x           screen x pos
1096                 y           screen y pos
1097                 size        pixel width of image
1098 
1099   Returns:      None.
1100  *---------------------------------------------------------------------------*/
CardUtilDrawAnimatedIcon(CardUtilDirent * ent,int x,int y,int size)1101 void CardUtilDrawAnimatedIcon(CardUtilDirent* ent, int x, int y, int size)
1102 {
1103     int i;
1104     u32 curr;
1105 
1106     if (ent->cFrame)
1107     {
1108         curr = VIGetRetraceCount() % ent->cFrame;
1109         for (i = 0; i < 2 * CARD_ICON_MAX - 2; ++i)
1110         {
1111             if (curr < ent->nFrame[i])
1112             {
1113                 break;
1114             }
1115         }
1116         i = ent->iIcon[i];
1117         if (CARDGetIconFormat(&ent->stat, i) != CARD_STAT_ICON_NONE)
1118         {
1119             CardUtilDrawIcon(x, y, size,
1120                      (u8*) ent + ent->stat.offsetIcon[i]  - ent->stat.iconAddr,
1121                      (u8*) ent + ent->stat.offsetIconTlut - ent->stat.iconAddr,
1122                      CARD_ICON_WIDTH, CARD_ICON_HEIGHT,
1123                      CARDGetIconFormat(&ent->stat, i));
1124         }
1125     }
1126 }
1127 
1128 /*---------------------------------------------------------------------------*
1129   Name:         CardUtilGetProgress
1130 
1131   Description:  Returns current command progress in percent (only for
1132                 mount, format, save and erase commands).
1133 
1134   Arguments:    slot        Memory card slot number
1135 
1136   Returns:      current command progress in percent (0 to 100)
1137  *---------------------------------------------------------------------------*/
CardUtilGetProgress(s32 slot)1138 s32 CardUtilGetProgress(s32 slot)
1139 {
1140     s32 percent;
1141 
1142     percent = CARDGetXferredBytes(slot) - CardControl.xferred;
1143     if (CardControl.length)
1144     {
1145         percent = (100 * percent) / CardControl.length;
1146     }
1147     if (100 < percent)
1148     {
1149         percent = 100;
1150     }
1151     return percent;
1152 }
1153