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 // Mountand 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