- head deinitialization removed from sdio_Deintialize. Only close the file descriptor.
[libogc.git] / libogc / card.c
blobcf8e4da6222a9ad7cb9214f5e38d192b29e58111
1 /*-------------------------------------------------------------
3 card.c -- Memory card subsystem
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any
11 damages arising from the use of this software.
13 Permission is granted to anyone to use this software for any
14 purpose, including commercial applications, and to alter it and
15 redistribute it freely, subject to the following restrictions:
17 1. The origin of this software must not be misrepresented; you
18 must not claim that you wrote the original software. If you use
19 this software in a product, an acknowledgment in the product
20 documentation would be appreciated but is not required.
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source
26 distribution.
28 -------------------------------------------------------------*/
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <malloc.h>
35 #include <time.h>
36 #include <gcutil.h>
37 #include "asm.h"
38 #include "processor.h"
39 #include "system.h"
40 #include "ogcsys.h"
41 #include "cache.h"
42 #include "dsp.h"
43 #include "lwp.h"
44 #include "exi.h"
45 #include "card.h"
47 //#define _CARD_DEBUG
49 #define CARD_SYSAREA 5
50 #define CARD_SYSDIR 0x2000
51 #define CARD_SYSDIR_BACK 0x4000
52 #define CARD_SYSBAT 0x6000
53 #define CARD_SYSBAT_BACK 0x8000
55 #define _SHIFTL(v, s, w) \
56 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
57 #define _SHIFTR(v, s, w) \
58 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
59 #define _ROTL(v,s) \
60 (((u32)v<<s)|((u32)v>>(0x20-s)))
62 #define CARD_STATUS_UNLOCKED 0x40
64 struct card_header {
65 u32 serial[0x08];
66 u16 device_id;
67 u16 size;
68 u16 encoding;
69 u8 padding[0x1d6];
70 u16 chksum1;
71 u16 chksum2;
72 } ATTRIBUTE_PACKED;
74 struct card_direntry {
75 u8 gamecode[4];
76 u8 company[2];
77 u8 pad_00;
78 u8 bannerfmt;
79 u8 filename[CARD_FILENAMELEN];
80 u32 lastmodified;
81 u32 iconaddr;
82 u16 iconfmt;
83 u16 iconspeed;
84 u8 permission;
85 u8 copytimes;
86 u16 block;
87 u16 length;
88 u16 pad_01;
89 u32 commentaddr;
90 } ATTRIBUTE_PACKED;
92 struct card_dat { // dir allocation table
93 struct card_direntry entries[CARD_MAXFILES];
96 struct card_dircntrl {
97 u8 pad[58];
98 u16 updated;
99 u16 chksum1;
100 u16 chksum2;
101 } ATTRIBUTE_PACKED;
103 struct card_bat {
104 u16 chksum1;
105 u16 chksum2;
106 u16 updated;
107 u16 freeblocks;
108 u16 lastalloc;
109 u16 fat[0xffc];
110 } ATTRIBUTE_PACKED;
112 typedef struct _card_block {
113 u8 cmd[9];
114 u32 cmd_len;
115 u32 cmd_mode;
116 u32 cmd_blck_cnt;
117 u32 cmd_sector_addr;
118 u32 cmd_retries;
119 u32 attached;
120 s32 result;
121 u32 cid;
122 u16 card_size;
123 u32 mount_step;
124 u32 format_step;
125 u32 sector_size;
126 u16 blocks;
127 u32 latency;
128 u32 cipher;
129 u32 key[3];
130 u32 transfer_cnt;
131 u16 curr_fileblock;
132 card_file *curr_file;
133 struct card_dat *curr_dir;
134 struct card_bat *curr_fat;
135 void *workarea;
136 void *cmd_usr_buf;
137 lwpq_t wait_sync_queue;
138 syswd_t timeout_svc;
139 dsptask_t dsp_task;
141 cardcallback card_ext_cb;
142 cardcallback card_tx_cb;
143 cardcallback card_exi_cb;
144 cardcallback card_api_cb;
145 cardcallback card_xfer_cb;
146 cardcallback card_erase_cb;
147 cardcallback card_unlock_cb;
148 } card_block;
150 static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) =
152 0x00000000,0x00000000,0x00000000,0x00000000,
153 0x00000000,0x00000000,0x00000021,0x02ff0021,
154 0x13061203,0x12041305,0x009200ff,0x0088ffff,
155 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf,
156 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf,
157 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e,
158 0x1fdf24ff,0x02400fff,0x00980400,0x009a0010,
159 0x00990000,0x8e0002bf,0x009402bf,0x864402bf,
160 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00,
161 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380,
162 0x00010295,0x005a0380,0x00020295,0x8000029f,
163 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e,
164 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff,
165 0x03400fff,0x1c9f02bf,0x008e00c7,0xffff02bf,
166 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf,
167 0x008e20ff,0x03400fff,0x1f5f02bf,0x008e21ff,
168 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021,
169 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0,
170 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd,
171 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d,
172 0x009c02df,0x00000000,0x00000000,0x00000000,
173 0x00000000,0x00000000,0x00000000,0x00000000
176 static u32 card_sector_size[] =
178 0x0002000,
179 0x0004000,
180 0x0008000,
181 0x0010000,
182 0x0020000,
183 0x0040000,
184 0x0000000,
185 0x0000000
188 static u32 card_latency[] =
190 0x00000004,
191 0x00000008,
192 0x00000010,
193 0x00000020,
194 0x00000030,
195 0x00000080,
196 0x00000100,
197 0x00000200
200 static u32 card_inited = 0;
201 static u32 crand_next = 1;
203 static u8 card_gamecode[4] = {0xff,0xff,0xff,0xff};
204 static u8 card_company[2] = {0xff,0xff};
205 static card_block cardmap[2];
207 static void __card_mountcallback(s32 chn,s32 result);
208 static void __erase_callback(s32 chn,s32 result);
209 static s32 __dounlock(s32 chn,u32 *key);
210 static s32 __card_readsegment(s32 chn,cardcallback callback);
211 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
212 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback);
213 static s32 __card_updatedir(s32 chn,cardcallback callback);
214 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
215 static s32 __card_writepage(s32 chn,cardcallback callback);
216 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback);
217 static s32 __card_onreset(s32 final);
219 static sys_resetinfo card_resetinfo = {
221 __card_onreset,
225 extern unsigned long gettick();
226 extern long long gettime();
227 extern syssram* __SYS_LockSram();
228 extern syssramex* __SYS_LockSramEx();
229 extern u32 __SYS_UnlockSram(u32 write);
230 extern u32 __SYS_UnlockSramEx(u32 write);
232 static vu16* const _viReg = (u16*)0xCC002000;
234 /* new api */
235 static s32 __card_onreset(s32 final)
237 if(final==FALSE) {
238 if(CARD_Unmount(CARD_SLOTA)==-1) return 0;
239 if(CARD_Unmount(CARD_SLOTB)==-1) return 0;
241 return 1;
244 static void __card_checksum(u16 *buff,u32 len,u16 *cs1,u16 *cs2)
246 u32 i;
247 #ifdef _CARD_DEBUG
248 printf("__card_checksum(%p,%d,%p,%p)\n",buff,len,cs1,cs2);
249 #endif
250 *cs1 = 0;
251 *cs2 = 0;
252 len /= 2;
253 for (i = 0; i < len; ++i) {
254 *cs1 += buff[i];
255 *cs2 += (buff[i] ^ 0xffff);
257 if (*cs1 == 0xffff) *cs1 = 0;
258 if (*cs2 == 0xffff) *cs2 = 0;
261 static s32 __card_putcntrlblock(card_block *card,s32 result)
263 u32 level;
265 _CPU_ISR_Disable(level);
266 if(card->attached) card->result = result;
267 else if(card->result==CARD_ERROR_BUSY) card->result = result;
268 _CPU_ISR_Restore(level);
269 return result;
272 static s32 __card_getcntrlblock(s32 chn,card_block **card)
274 s32 ret;
275 u32 level;
276 card_block *rcard = NULL;
278 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
280 _CPU_ISR_Disable(level);
281 rcard = &cardmap[chn];
282 if(!rcard->attached) {
283 _CPU_ISR_Restore(level);
284 return CARD_ERROR_NOCARD;
287 ret = CARD_ERROR_BUSY;
288 if(rcard->result!=CARD_ERROR_BUSY) {
289 rcard->result = CARD_ERROR_BUSY;
290 rcard->card_api_cb = NULL;
291 *card = rcard;
292 ret = CARD_ERROR_READY;
294 _CPU_ISR_Restore(level);
295 return ret;
298 static __inline__ struct card_dat* __card_getdirblock(card_block *card)
300 return card->curr_dir;
303 static __inline__ struct card_bat* __card_getbatblock(card_block *card)
305 return card->curr_fat;
308 static s32 __card_sync(s32 chn)
310 s32 ret;
311 u32 level;
312 card_block *card = &cardmap[chn];
314 _CPU_ISR_Disable(level);
315 while((ret=CARD_GetErrorCode(chn))==CARD_ERROR_BUSY) {
316 LWP_ThreadSleep(card->wait_sync_queue);
318 _CPU_ISR_Restore(level);
319 return ret;
322 static void __card_synccallback(s32 chn,s32 result)
324 u32 level;
325 card_block *card = &cardmap[chn];
326 #ifdef _CARD_DEBUG
327 printf("__card_synccallback(%d,%d,%d)\n",chn,result,card->result);
328 #endif
329 _CPU_ISR_Disable(level);
330 LWP_ThreadBroadcast(card->wait_sync_queue);
331 _CPU_ISR_Restore(level);
334 static void __card_updateiconoffsets(struct card_direntry *entry,card_stat *stats)
336 s32 i;
337 u8 bnrfmt,nicons;
338 u32 iconaddr,iconbase;
340 iconaddr = entry->iconaddr;
341 if(iconaddr==-1) {
342 stats->banner_fmt = 0;
343 stats->icon_fmt = 0;
344 stats->icon_speed = 0;
345 iconaddr = 0;
348 if(entry->bannerfmt&CARD_BANNER_MASK) {
349 if(!(entry->bannerfmt&0x10)) {
350 bnrfmt = (entry->bannerfmt&CARD_BANNER_MASK);
351 if(bnrfmt==CARD_BANNER_CI) {
352 stats->banner_fmt = bnrfmt;
353 stats->offset_banner = iconaddr;
354 stats->offset_banner_tlut = iconaddr+3072;
355 iconaddr += (3072+512);
356 } else if(bnrfmt==CARD_BANNER_RGB) {
357 stats->banner_fmt = bnrfmt;
358 stats->offset_banner = iconaddr;
359 stats->offset_banner_tlut = -1;
360 iconaddr += 6144;
362 } else {
363 stats->offset_banner = -1;
364 stats->offset_banner_tlut = -1;
368 nicons = 0;
369 for(i=0;i<CARD_MAXICONS;i++) {
370 stats->iconfmt[i] = ((entry->iconfmt>>(i<<1))&CARD_ICON_MASK);
371 stats->iconspeed[i] = ((entry->iconspeed>>(i<<1))&CARD_SPEED_MASK);
372 if(stats->iconspeed[i]==0) stats->iconfmt[i] = 0;
373 if(stats->iconfmt[i]) nicons++;
376 iconbase = iconaddr;
377 for(i=0;i<CARD_MAXICONS;i++) {
378 switch(stats->iconfmt[i]) {
379 case 1: //CARD_ICON_CI with shared palette
380 stats->offset_icon[i] = iconaddr;
381 stats->offset_icon_tlut[i] = iconbase + (nicons*1024);
382 iconaddr += 1024;
383 break;
384 case 2: //CARD_ICON_RGB
385 stats->offset_icon[i] = iconaddr;
386 stats->offset_icon_tlut[i] = -1;
387 iconaddr += 3072;
388 break;
389 case 3: //CARD_ICON_CI with own palette
390 stats->offset_icon[i] = iconaddr;
391 stats->offset_icon_tlut[i] = iconaddr + 1024;
392 iconaddr += 1536;
393 break;
394 default: //CARD_ICON_NONE
395 stats->offset_icon[i] = -1;
396 stats->offset_icon_tlut[i] = -1;
397 break;
402 // stats->offset_data = iconaddr;
405 static s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry)
407 s32 ret;
408 card_block *card = NULL;
409 struct card_dat *dirblock = NULL;
411 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
412 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
413 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
415 ret = CARD_ERROR_BROKEN;
416 dirblock = __card_getdirblock(card);
417 if(dirblock) {
418 ret = CARD_ERROR_READY;
419 memcpy(entry,&dirblock->entries[fileno],sizeof(struct card_direntry));
421 return __card_putcntrlblock(card,ret);
424 static s32 __card_setstatusexasync(s32 chn,s32 fileno,struct card_direntry *entry,cardcallback callback)
426 s32 ret,i,bend;
427 card_block *card = NULL;
428 struct card_dat *dirblock = NULL;
429 struct card_direntry *entries = NULL;
431 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
432 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
433 if(entry->filename[0]==0xff || entry->filename[0]==0) return CARD_ERROR_FATAL_ERROR;
434 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
436 ret = CARD_ERROR_BROKEN;
437 dirblock = __card_getdirblock(card);
438 if(dirblock) {
439 i = 0; bend = 0;
440 ret = CARD_ERROR_READY;
441 entries = dirblock->entries;
442 while(i<CARD_FILENAMELEN) {
443 if(bend || entry->filename[i]==0) {
444 entry->filename[i] = 0;
445 bend = 1;
447 i++;
450 if(memcmp(entries[fileno].filename,entry->filename,CARD_FILENAMELEN)
451 || memcmp(entries[fileno].gamecode,entry->gamecode,4)
452 || memcmp(entries[fileno].company,entry->company,2)) {
453 i = 0;
454 while(i<CARD_MAXFILES) {
455 if(i!=fileno && entries[i].gamecode[0]!=0xff
456 && memcmp(entries[i].gamecode,entry->gamecode,4)==0
457 && memcmp(entries[i].company,entry->company,2)==0
458 && memcmp(entries[i].filename,entry->filename,CARD_FILENAMELEN)==0) {
459 return __card_putcntrlblock(card,CARD_ERROR_EXIST);
461 i++;
463 memcpy(entries[fileno].filename,entry->filename,CARD_FILENAMELEN);
464 memcpy(entries[fileno].gamecode,entry->gamecode,4);
465 memcpy(entries[fileno].company,entry->company,2);
468 entries[fileno].lastmodified = entry->lastmodified;
469 entries[fileno].bannerfmt = entry->bannerfmt;
470 entries[fileno].iconaddr = entry->iconaddr;
471 entries[fileno].iconfmt = entry->iconfmt;
472 entries[fileno].iconspeed = entry->iconspeed;
473 entries[fileno].commentaddr = entry->commentaddr;
474 entries[fileno].permission = entry->permission;
475 entries[fileno].copytimes = entry->copytimes;
477 if((ret=__card_updatedir(chn,callback))>=0) return ret;
479 return __card_putcntrlblock(card,ret);
482 static s32 __card_setstatusex(s32 chn,s32 fileno,struct card_direntry *entry)
484 s32 ret;
486 if((ret=__card_setstatusexasync(chn,fileno,entry,__card_synccallback))>=0) {
487 ret = __card_sync(chn);
489 return ret;
492 static s32 __card_getfilenum(card_block *card,const char *filename,const char *gamecode,const char *company,s32 *fileno)
494 u32 i = 0;
495 struct card_direntry *entries = NULL;
496 struct card_dat *dirblock = NULL;
497 #ifdef _CARD_DEBUG
498 printf("__card_getfilenum(%p,%s,%s,%s)\n",card,filename,gamecode,company);
499 #endif
500 if(!card->attached) return CARD_ERROR_NOCARD;
501 dirblock = __card_getdirblock(card);
503 entries = dirblock->entries;
504 for(i=0;i<CARD_MAXFILES;i++) {
505 if(entries[i].gamecode[0]!=0xff) {
506 if(strnicmp((const char*)entries[i].filename,filename,strlen(filename))==0) {
507 if((gamecode && gamecode[0]!=0xff && memcmp(entries[i].gamecode,gamecode,4)!=0)
508 || (company && company[0]!=0xff && memcmp(entries[i].company,company,2)!=0)) continue;
510 *fileno = i;
511 break;
515 if(i>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
516 return CARD_ERROR_READY;
519 static s32 __card_seek(card_file *file,s32 len,s32 offset,card_block **rcard)
521 s32 ret;
522 s32 i,entry_len;
523 card_block *card = NULL;
524 struct card_direntry *entry = NULL;
525 struct card_dat *dirblock = NULL;
526 struct card_bat *fatblock = NULL;
527 #ifdef _CARD_DEBUG
528 printf("__card_seek(%d,%p,%d,%d)\n",file->filenum,file,len,offset);
529 #endif
530 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
531 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
532 #ifdef _CARD_DEBUG
533 printf("__card_seek(%d)\n",file->iblock);
534 #endif
535 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
536 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
537 return CARD_ERROR_FATAL_ERROR;
540 dirblock = __card_getdirblock(card);
541 entry = &dirblock->entries[file->filenum];
542 #ifdef _CARD_DEBUG
543 printf("__card_seek(%p,%d)\n",entry,file->filenum);
544 #endif
545 if(entry->gamecode[0]!=0xff) {
546 entry_len = entry->length*card->sector_size;
547 if(entry_len<offset || entry_len<(offset+len)) {
548 __card_putcntrlblock(card,CARD_ERROR_LIMIT);
549 return CARD_ERROR_LIMIT;
551 card->curr_file = file;
552 file->len = len;
554 if(offset<file->offset) {
555 file->offset = 0;
556 file->iblock = entry->block;
557 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
558 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
559 return CARD_ERROR_BROKEN;
563 fatblock = __card_getbatblock(card);
564 for(i=file->iblock;i<card->blocks && file->offset<(offset&~(card->sector_size-1));i=file->iblock) {
565 file->offset += card->sector_size;
566 file->iblock = fatblock->fat[i-CARD_SYSAREA];
567 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
568 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
569 return CARD_ERROR_BROKEN;
572 file->offset = offset;
573 *rcard = card;
575 return CARD_ERROR_READY;
578 static u32 __card_checkdir(card_block *card,u32 *currdir)
580 u32 dir,bad,bad_dir;
581 u16 chksum0,chksum1;
582 struct card_dircntrl *dircntrl[2];
583 struct card_dat *dirblock[2];
584 #ifdef _CARD_DEBUG
585 printf("__card_checkdir(%p,%p)\n",card,currdir);
586 #endif
587 dir = 0;
588 bad = 0;
589 bad_dir = 0;
590 while(dir<2) {
591 dirblock[dir] = card->workarea+((dir+1)<<13);
592 dircntrl[dir] = (card->workarea+((dir+1)<<13))+8128;
593 __card_checksum((u16*)dirblock[dir],0x1ffc,&chksum0,&chksum1);
594 if(chksum0!=dircntrl[dir]->chksum1 || chksum1!=dircntrl[dir]->chksum2) {
595 #ifdef _CARD_DEBUG
596 printf("__card_checkdir(bad checksums: (%04x : %04x),(%04x : %04x)\n",chksum0,dircntrl[dir]->chksum1,chksum1,dircntrl[dir]->chksum2);
597 #endif
598 card->curr_dir = NULL;
599 bad_dir = dir;
600 bad++;
602 dir++;
605 dir = bad_dir;
606 if(!bad) {
607 if(dircntrl[0]->updated<dircntrl[1]->updated) dir = 0;
608 else dir = 1;
610 if(card->curr_dir==NULL) {
611 card->curr_dir = dirblock[dir];
612 memcpy(dirblock[dir],dirblock[dir^1],8192);
614 else if(card->curr_dir==dirblock[0]) dir = 0;
615 else dir = 1;
617 if(currdir) *currdir = dir;
618 return bad;
621 static u32 __card_checkfat(card_block *card,u32 *currfat)
623 u32 fat,bad,bad_fat;
624 u16 chksum0,chksum1;
625 struct card_bat *fatblock[2];
626 #ifdef _CARD_DEBUG
627 printf("__card_checkfat(%p,%p)\n",card,currfat);
628 #endif
629 fat = 0;
630 bad = 0;
631 bad_fat = 0;
632 while(fat<2) {
633 fatblock[fat] = card->workarea+((fat+3)<<13);
634 __card_checksum((u16*)(((u32)fatblock[fat])+4),0x1ffc,&chksum0,&chksum1);
635 if(chksum0!=fatblock[fat]->chksum1 || chksum1!=fatblock[fat]->chksum2) {
636 #ifdef _CARD_DEBUG
637 printf("__card_checkfat(bad checksums: (%04x : %04x),(%04x : %04x)\n",chksum0,fatblock[fat]->chksum1,chksum1,fatblock[fat]->chksum2);
638 #endif
639 card->curr_fat = NULL;
640 bad_fat = fat;
641 bad++;
642 } else {
643 u16 curblock = CARD_SYSAREA;
644 u16 freeblocks = 0;
645 while(curblock<card->blocks) {
646 if(!fatblock[fat]->fat[curblock-CARD_SYSAREA]) freeblocks++;
647 curblock++;
649 if(freeblocks!=fatblock[fat]->freeblocks) {
650 #ifdef _CARD_DEBUG
651 printf("__card_checkfat(freeblocks!=fatblock[fat]->freeblocks (%d : %d))\n",freeblocks,fatblock[fat]->freeblocks);
652 #endif
653 card->curr_fat = NULL;
654 bad_fat = fat;
655 bad++;
658 fat++;
661 fat = bad_fat;
662 if(!bad) {
663 if(fatblock[0]->updated<fatblock[1]->updated) fat = 0;
664 else fat = 1;
666 if(card->curr_fat==NULL) {
667 card->curr_fat = fatblock[fat];
668 memcpy(fatblock[fat],fatblock[fat^1],8192);
670 else if(card->curr_fat==fatblock[0]) fat = 0;
671 else fat = 1;
673 if(currfat) *currfat = fat;
674 return bad;
677 static s32 __card_verify(card_block *card)
679 u32 ret = 0;
681 ret += __card_checkdir(card,NULL);
682 ret += __card_checkfat(card,NULL);
683 #ifdef _CARD_DEBUG
684 printf("__card_verify(%d)\n",ret);
685 #endif
686 if(ret<=2) {
687 if(card->curr_dir && card->curr_fat) return CARD_ERROR_READY;
689 return CARD_ERROR_BROKEN;
692 static u32 __card_iscard(u32 id)
694 u32 ret;
695 u32 idx,tmp,secsize;
697 if(id&~0xffff) return 0;
698 if(id&0x03) return 0;
700 ret = 0;
701 tmp = id&0xfc;
702 if(tmp==EXI_MEMCARD59 || tmp==EXI_MEMCARD123
703 || tmp==EXI_MEMCARD251 || tmp==EXI_MEMCARD507
704 || tmp==EXI_MEMCARD1019 || tmp==EXI_MEMCARD2043) {
705 idx = _ROTL(id,23)&0x1c;
706 if((secsize=card_sector_size[idx>>2])==0) return 0;
707 tmp = ((tmp<<20)&0x1FFE0000)/secsize;
708 if(tmp>8) ret = 1;
710 return ret;
713 static s32 __card_allocblock(s32 chn,u32 blocksneed,cardcallback callback)
715 s32 ret;
716 u16 block,currblock = 0,prevblock = 0;
717 u32 i,count;
718 card_block *card = NULL;
719 struct card_bat *fatblock = NULL;
720 #ifdef _CARD_DEBUG
721 printf("__card_allocblock(%d,%d,%p)\n",chn,blocksneed,callback);
722 #endif
723 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
724 card = &cardmap[chn];
726 if(!card->attached) return CARD_ERROR_NOCARD;
727 fatblock = __card_getbatblock(card);
728 #ifdef _CARD_DEBUG
729 printf("__card_allocblock(%p,%d)\n",fatblock,fatblock->freeblocks);
730 #endif
732 if(fatblock->freeblocks<blocksneed) return CARD_ERROR_INSSPACE;
734 // Add which blocks this file will take up into the FAT
735 count = 0;
736 block = 0xffff;
737 currblock = fatblock->lastalloc;
738 i = blocksneed;
739 while(1) {
740 if(i==0) {
741 // Done allocating blocks
742 #ifdef _CARD_DEBUG
743 printf("__card_allocblock(%d : %d)\n",block,currblock);
744 #endif
745 fatblock->freeblocks -= blocksneed;
746 fatblock->lastalloc = currblock;
747 card->curr_fileblock = block;
748 ret = __card_updatefat(chn,fatblock,callback);
749 break;
753 Since testing free space has already been done, if all the blocks
754 the file takes up cannot be entered into the FAT, something is
755 wrong.
757 count++;
758 if(count>=(card->blocks-CARD_SYSAREA)) return CARD_ERROR_BROKEN;
760 currblock++;
761 if(currblock<CARD_SYSAREA || currblock>=card->blocks) currblock = CARD_SYSAREA;
762 if(fatblock->fat[currblock-CARD_SYSAREA]==0) {
763 if(block!=0xffff)
764 fatblock->fat[prevblock-CARD_SYSAREA] = currblock;
765 else
766 block = currblock;
768 fatblock->fat[currblock-CARD_SYSAREA] = 0xffff;
769 prevblock = currblock;
770 i--;
773 return ret;
776 static s32 __card_freeblock(s32 chn,u16 block,cardcallback callback)
778 u16 next = 0xffff,prev = 0xffff;
779 card_block *card = NULL;
780 struct card_bat *fatblock = NULL;
781 #ifdef _CARD_DEBUG
782 printf("__card_freeblock(%d,%d,%p)\n",chn,block,callback);
783 #endif
784 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
785 card = &cardmap[chn];
787 if(!card->attached) return CARD_ERROR_NOCARD;
789 fatblock = __card_getbatblock(card);
790 next = fatblock->fat[block-CARD_SYSAREA];
791 while(1) {
792 if(next==0xffff) break;
793 if(next<CARD_SYSAREA || next>=card->blocks) return CARD_ERROR_BROKEN;
795 // Get the file's next block and clear the previous one from the fat
796 prev = next;
797 next = fatblock->fat[prev-CARD_SYSAREA];
798 fatblock->fat[prev-CARD_SYSAREA] = 0;
799 fatblock->freeblocks++;
801 return __card_updatefat(chn,fatblock,callback);
804 static s32 __card_unlockedhandler(s32 chn,s32 dev)
806 s32 ret;
807 cardcallback cb = NULL;
808 card_block *card = NULL;
810 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
811 card = &cardmap[chn];
813 ret = CARD_ERROR_READY;
814 cb = card->card_unlock_cb;
815 if(cb) {
816 card->card_unlock_cb = NULL;
817 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
818 cb(chn,ret);
820 return CARD_ERROR_UNLOCKED;
823 static s32 __card_readstatus(s32 chn,u8 *pstatus)
825 u8 val[2];
826 u32 err;
827 s32 ret;
829 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
830 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
832 err = 0;
833 val[0] = 0x83; val[1] = 0x00;
834 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
835 if(EXI_Sync(chn)==0) err |= 0x02;
836 if(EXI_Imm(chn,pstatus,1,EXI_READ,NULL)==0) err |= 0x04;
837 if(EXI_Sync(chn)==0) err |= 0x08;
838 if(EXI_Deselect(chn)==0) err |= 0x10;
840 if(err) ret = CARD_ERROR_NOCARD;
841 else ret = CARD_ERROR_READY;
842 #ifdef _CARD_DEBUG
843 printf("__card_readstatus(%d,%08x)\n",chn,*pstatus);
844 #endif
845 return ret;
848 static s32 __card_clearstatus(s32 chn)
850 u8 val;
851 u32 err;
852 s32 ret;
853 #ifdef _CARD_DEBUG
854 printf("__card_clearstatus(%d)\n",chn);
855 #endif
856 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
857 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
859 err = 0;
860 val = 0x89;
861 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
862 if(EXI_Sync(chn)==0) err |= 0x02;
863 if(EXI_Deselect(chn)==0) err |= 0x04;
865 if(err) ret = CARD_ERROR_NOCARD;
866 else ret = CARD_ERROR_READY;
868 return ret;
871 static s32 __card_sleep(s32 chn)
873 u8 val;
874 u32 err;
875 s32 ret;
876 #ifdef _CARD_DEBUG
877 printf("__card_sleep(%d)\n",chn);
878 #endif
879 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
880 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
882 err = 0;
883 val = 0x88;
884 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
885 if(EXI_Sync(chn)==0) err |= 0x02;
886 if(EXI_Deselect(chn)==0) err |= 0x04;
888 if(err) ret = CARD_ERROR_NOCARD;
889 else ret = CARD_ERROR_READY;
891 return ret;
894 static s32 __card_wake(s32 chn)
896 u8 val;
897 u32 err;
898 s32 ret;
899 #ifdef _CARD_DEBUG
900 printf("__card_wake(%d)\n",chn);
901 #endif
903 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
904 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
906 err = 0;
907 val = 0x87;
908 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
909 if(EXI_Sync(chn)==0) err |= 0x02;
910 if(EXI_Deselect(chn)==0) err |= 0x04;
912 if(err) ret = CARD_ERROR_NOCARD;
913 else ret = CARD_ERROR_READY;
915 return ret;
918 static s32 __card_enableinterrupt(s32 chn,u32 enable)
920 u8 val[2];
921 u32 err;
922 s32 ret;
923 #ifdef _CARD_DEBUG
924 printf("__card_enableinterrupt(%d,%d)\n",chn,enable);
925 #endif
927 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
928 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
930 err = 0;
931 val[0] = 0x81;
932 if(enable) val[1] = 0x01;
933 else val[1] = 0x00;
934 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
935 if(EXI_Sync(chn)==0) err |= 0x02;
936 if(EXI_Deselect(chn)==0) err |= 0x04;
938 if(err) ret = CARD_ERROR_BUSY;
939 else ret = CARD_ERROR_READY;
941 return ret;
944 static s32 __card_txhandler(s32 chn,s32 dev)
946 u32 err;
947 s32 ret = CARD_ERROR_READY;
948 cardcallback cb = NULL;
949 card_block *card = NULL;
950 #ifdef _CARD_DEBUG
951 printf("__card_txhandler(%d,%d)\n",chn,dev);
952 #endif
953 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
954 card = &cardmap[chn];
956 err = 0;
957 if(EXI_Deselect(chn)==0) ret |= err;
958 if(EXI_Unlock(chn)==0) ret |= err;
960 cb = card->card_tx_cb;
961 if(cb) {
962 card->card_tx_cb = NULL;
963 if(!err) {
964 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
965 } else ret = CARD_ERROR_NOCARD;
966 cb(chn,ret);
968 return 1;
971 static void __timeouthandler(syswd_t alarm)
973 u32 chn;
974 s32 ret = CARD_ERROR_READY;
975 cardcallback cb;
976 card_block *card = NULL;
977 #ifdef _CARD_DEBUG
978 printf("__timeouthandler(%p)\n",alarm);
979 #endif
980 chn = 0;
981 while(chn<EXI_CHANNEL_2) {
982 card = &cardmap[chn];
983 if(card->timeout_svc==alarm) break;
984 chn++;
986 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
989 if(card->attached) {
990 EXI_RegisterEXICallback(chn,NULL);
991 cb = card->card_exi_cb;
992 if(cb) {
993 card->card_exi_cb = NULL;
994 ret = CARD_ERROR_IOERROR;
995 cb(chn,ret);
1000 static void __setuptimeout(card_block *card)
1002 struct timespec tb;
1003 #ifdef _CARD_DEBUG
1004 printf("__setuptimeout(%p)\n",&card->timeout_svc);
1005 #endif
1006 SYS_CancelAlarm(card->timeout_svc);
1008 if(card->cmd[0]==0xf1 || card->cmd[0]==0xf4) {
1009 #ifdef _CARD_DEBUG
1010 printf("__setuptimeout(%02x, %dsec)\n",card->cmd[0],1*(card->sector_size/8192));
1011 #endif
1012 tb.tv_sec = 1*(card->sector_size/8192);
1013 tb.tv_nsec = 0;
1014 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler);
1015 } else if(card->cmd[0]==0xf2) {
1016 #ifdef _CARD_DEBUG
1017 printf("__setuptimeout(0xf2, 100ms)\n");
1018 #endif
1019 tb.tv_sec = 0;
1020 tb.tv_nsec = 100*TB_NSPERMS;
1021 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler);
1025 static s32 __retry(s32 chn)
1027 u32 len;
1028 card_block *card = NULL;
1030 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1031 card = &cardmap[chn];
1032 #ifdef _CARD_DEBUG
1033 printf("__retry(%d)\n",chn);
1034 #endif
1035 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
1036 EXI_Unlock(chn);
1037 return CARD_ERROR_NOCARD;
1040 __setuptimeout(card);
1042 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
1043 EXI_Deselect(chn);
1044 EXI_Unlock(chn);
1045 return CARD_ERROR_NOCARD;
1048 if(card->cmd[0]==0x52) {
1049 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) {
1050 EXI_Deselect(chn);
1051 EXI_Unlock(chn);
1052 return CARD_ERROR_NOCARD;
1056 if(card->cmd_mode==-1) {
1057 EXI_Deselect(chn);
1058 EXI_Unlock(chn);
1059 return CARD_ERROR_READY;
1062 len = 128;
1063 if(card->cmd[0]==0x52) len = CARD_READSIZE;
1064 if(EXI_Dma(chn,card->cmd_usr_buf,len,card->cmd_mode,__card_txhandler)==0) {
1065 EXI_Deselect(chn);
1066 EXI_Unlock(chn);
1067 return CARD_ERROR_NOCARD;
1069 return CARD_ERROR_READY;
1072 static void __card_defaultapicallback(s32 chn,s32 result)
1074 #ifdef _CARD_DEBUG
1075 printf("__card_defaultapicallback(%d,%d)\n",chn,result);
1076 #endif
1077 return;
1080 static s32 __card_exihandler(s32 chn,s32 dev)
1082 u8 status;
1083 s32 ret = CARD_ERROR_READY;
1084 card_block *card = NULL;
1085 cardcallback cb;
1086 #ifdef _CARD_DEBUG
1087 printf("__card_exihandler(%d,%d)\n",chn,dev);
1088 #endif
1089 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 1;
1090 card = &cardmap[chn];
1092 SYS_CancelAlarm(card->timeout_svc);
1093 if(card->attached) {
1094 if(EXI_Lock(chn,EXI_DEVICE_0,NULL)==1) {
1095 if((ret=__card_readstatus(chn,&status))>=0
1096 && (ret=__card_clearstatus(chn))>=0) {
1097 if(status&0x18) ret = CARD_ERROR_IOERROR;
1098 else ret = CARD_ERROR_READY;
1100 if(ret==CARD_ERROR_IOERROR) {
1101 if((--card->cmd_retries)>0) {
1102 ret = __retry(chn);
1103 if(ret<0) goto exit;
1104 return 1;
1108 EXI_Unlock(chn);
1109 } else ret = CARD_ERROR_FATAL_ERROR;
1110 exit:
1111 cb = card->card_exi_cb;
1112 if(cb) {
1113 card->card_exi_cb = NULL;
1114 cb(chn,ret);
1117 return 1;
1120 static s32 __card_exthandler(s32 chn,s32 dev)
1122 cardcallback cb;
1123 card_block *card = NULL;
1124 #ifdef _CARD_DEBUG
1125 printf("__card_exthandler(%d,%d)\n",chn,dev);
1126 #endif
1127 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
1128 card = &cardmap[chn];
1130 if(card->attached) {
1131 if(card->card_tx_cb) {
1132 printf("error: card->card_tx_cb!=NULL\n");
1134 card->attached = 0;
1135 EXI_RegisterEXICallback(chn,NULL);
1136 SYS_CancelAlarm(card->timeout_svc);
1138 cb = card->card_exi_cb;
1139 if(cb) {
1140 card->card_exi_cb = NULL;
1141 cb(chn,CARD_ERROR_NOCARD);
1144 cb = card->card_ext_cb;
1145 if(cb) {
1146 card->card_ext_cb = NULL;
1147 cb(chn,CARD_ERROR_NOCARD);
1151 return 1;
1154 static void __write_callback(s32 chn,s32 result)
1156 s32 ret;
1157 cardcallback cb = NULL;
1158 card_file *file = NULL;
1159 struct card_bat *fatblock = NULL;
1160 struct card_dat *dirblock = NULL;
1161 struct card_direntry *entry = NULL;
1162 card_block *card = &cardmap[chn];
1163 #ifdef _CARD_DEBUG
1164 printf("__write_callback(%d,%d)\n",chn,result);
1165 #endif
1166 ret = result;
1167 if(ret>=0) {
1168 file = card->curr_file;
1169 if(file->len>=0) {
1170 file->len = (card->sector_size-file->len);
1171 if(file->len<=0) {
1172 dirblock = __card_getdirblock(card);
1173 entry = &dirblock->entries[file->filenum];
1174 entry->lastmodified = time(NULL);
1175 cb = card->card_api_cb;
1176 card->card_api_cb = NULL;
1177 if((ret=__card_updatedir(chn,cb))>=0) return;
1178 } else {
1179 fatblock = __card_getbatblock(card);
1180 file->offset += card->sector_size;
1181 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1182 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1183 ret = CARD_ERROR_BROKEN;
1184 goto exit;
1186 if((ret=__card_sectorerase(chn,(file->iblock*card->sector_size),__erase_callback))>=0) return;
1188 } else
1189 ret = CARD_ERROR_CANCELED;
1192 exit:
1193 cb = card->card_api_cb;
1194 card->card_api_cb = NULL;
1195 __card_putcntrlblock(card,ret);
1196 if(cb) cb(chn,ret);
1199 static void __erase_callback(s32 chn,s32 result)
1201 s32 ret;
1202 cardcallback cb = NULL;
1203 card_file *file = NULL;
1204 card_block *card = &cardmap[chn];
1205 #ifdef _CARD_DEBUG
1206 printf("__erase_callback(%d,%d)\n",chn,result);
1207 #endif
1208 ret = result;
1209 if(ret>=0) {
1210 file = card->curr_file;
1211 if((ret=__card_write(chn,(file->iblock*card->sector_size),card->sector_size,card->cmd_usr_buf,__write_callback))>=0) return;
1214 cb = card->card_api_cb;
1215 card->card_api_cb = NULL;
1216 __card_putcntrlblock(card,ret);
1217 if(cb) cb(chn,ret);
1220 static void __read_callback(s32 chn,s32 result)
1222 s32 ret;
1223 s32 len;
1224 cardcallback cb = NULL;
1225 card_file *file = NULL;
1226 card_block *card = 0;
1227 struct card_bat *fatblock = NULL;
1228 #ifdef _CARD_DEBUG
1229 printf("__read_callback(%d,%d)\n",chn,result);
1230 #endif
1231 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1232 card = &cardmap[chn];
1234 ret = result;
1235 file = card->curr_file;
1236 #ifdef _CARD_DEBUG
1237 printf("__read_callback(file->len = %d,file->iblock = %d)\n",file->len,file->iblock);
1238 #endif
1239 if(ret>=0) {
1240 if(file->len>=0) {
1241 file->len = file->len-(((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1242 #ifdef _CARD_DEBUG
1243 printf("__read_callback(file->len = %d)\n",file->len);
1244 #endif
1245 if(file->len>0) {
1246 fatblock = __card_getbatblock(card);
1247 file->offset += (((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1248 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1249 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1250 ret = CARD_ERROR_BROKEN;
1251 goto exit;
1253 len = file->len<card->sector_size?card->sector_size:file->len;
1254 if(__card_read(chn,(file->iblock*card->sector_size),len,card->cmd_usr_buf,__read_callback)>=0) return;
1257 } else
1258 ret = CARD_ERROR_CANCELED;
1261 exit:
1262 cb = card->card_api_cb;
1263 card->card_api_cb = NULL;
1264 __card_putcntrlblock(card,ret);
1265 if(cb) cb(chn,ret);
1268 static void __delete_callback(s32 chn,s32 result)
1270 s32 ret;
1271 cardcallback cb = NULL;
1272 card_block *card = &cardmap[chn];
1273 #ifdef _CARD_DEBUG
1274 printf("__delete_callback(%d,%d)\n",chn,result);
1275 #endif
1276 cb = card->card_api_cb;
1277 card->card_api_cb = NULL;
1279 ret = result;
1280 if(ret>=0 && (ret=__card_freeblock(chn,card->curr_fileblock,cb))>=0) return;
1282 __card_putcntrlblock(card,ret);
1283 if(cb) cb(chn,ret);
1286 static void __format_callback(s32 chn,s32 result)
1288 s32 ret;
1289 cardcallback cb = NULL;
1290 card_block *card = &cardmap[chn];
1292 ret = result;
1293 if(ret>=0) {
1294 if((++card->format_step)<CARD_SYSAREA) {
1295 if((ret=__card_sectorerase(chn,(card->format_step*card->sector_size),__format_callback))>=0) return;
1296 goto exit;
1298 if(card->format_step<10) {
1299 if((ret=__card_write(chn,((card->format_step-CARD_SYSAREA)*card->sector_size),8192,card->workarea+((card->format_step-CARD_SYSAREA)<<13),__format_callback))>=0) return;
1300 goto exit;
1303 card->curr_dir = card->workarea+CARD_SYSDIR;
1304 memcpy(card->curr_dir,card->workarea+CARD_SYSDIR_BACK,8192);
1306 card->curr_fat = card->workarea+CARD_SYSBAT;
1307 memcpy(card->curr_fat,card->workarea+CARD_SYSBAT_BACK,8192);
1309 exit:
1310 cb = card->card_api_cb;
1311 card->card_api_cb = NULL;
1312 __card_putcntrlblock(card,ret);
1313 if(cb) cb(chn,ret);
1316 static void __blockwritecallback(s32 chn,s32 result)
1318 s32 ret = CARD_ERROR_READY;
1319 cardcallback cb = NULL;
1320 card_block *card = &cardmap[chn];
1321 #ifdef _CARD_DEBUG
1322 printf("__blockwritecallback(%d,%d)\n",chn,result);
1323 #endif
1324 ret = result;
1325 if(ret>=0) {
1326 card->transfer_cnt += 128;
1327 card->cmd_sector_addr += 128;
1328 card->cmd_usr_buf += 128;
1329 if((--card->cmd_blck_cnt)>0) {
1330 if((ret=__card_writepage(chn,__blockwritecallback))>=CARD_ERROR_READY) return;
1334 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1336 cb = card->card_xfer_cb;
1337 if(cb) {
1338 card->card_xfer_cb = NULL;
1339 cb(chn,ret);
1343 static void __blockreadcallback(s32 chn,s32 result)
1345 s32 ret = CARD_ERROR_READY;
1346 cardcallback cb = NULL;
1347 card_block *card = &cardmap[chn];
1348 #ifdef _CARD_DEBUG
1349 printf("__blockreadcallback(%d,%d)\n",chn,result);
1350 #endif
1351 ret = result;
1352 if(ret>=0) {
1353 card->transfer_cnt += CARD_READSIZE;
1354 card->cmd_sector_addr += CARD_READSIZE;
1355 card->cmd_usr_buf += CARD_READSIZE;
1356 if((--card->cmd_blck_cnt)>0) {
1357 if((ret=__card_readsegment(chn,__blockreadcallback))>=CARD_ERROR_READY) return;
1361 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1362 cb = card->card_xfer_cb;
1363 if(cb) {
1364 card->card_xfer_cb = NULL;
1365 cb(chn,ret);
1369 static void __unlocked_callback(s32 chn,s32 result)
1371 s32 ret;
1372 card_block *card;
1373 cardcallback cb;
1374 #ifdef _CARD_DEBUG
1375 printf("__unlocked_callback(%d,%d)\n",chn,result);
1376 #endif
1377 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1378 card = &cardmap[chn];
1380 ret = result;
1381 if(ret>=0) {
1382 card->card_unlock_cb = __unlocked_callback;
1383 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==1) {
1384 card->card_unlock_cb = NULL;
1385 ret = __retry(chn);
1386 } else
1387 ret = 0;
1389 if(ret<0) {
1390 if(card->cmd[0]==0xf3 || card->cmd[0]>=0xf5) return;
1391 else if(card->cmd[0]==0x52) {
1392 cb = card->card_tx_cb;
1393 if(cb) {
1394 card->card_tx_cb = NULL;
1395 cb(chn,ret);
1397 } else if(card->cmd[0]>=0xf1) {
1398 cb = card->card_exi_cb;
1399 if(cb) {
1400 card->card_exi_cb = NULL;
1401 cb(chn,ret);
1407 static s32 __card_start(s32 chn,cardcallback tx_cb,cardcallback exi_cb)
1409 u32 level;
1410 card_block *card = NULL;
1411 #ifdef _CARD_DEBUG
1412 printf("__card_start(%d,%p,%p)\n",chn,tx_cb,exi_cb);
1413 #endif
1414 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1415 card = &cardmap[chn];
1417 _CPU_ISR_Disable(level);
1418 if(tx_cb) card->card_tx_cb = tx_cb;
1419 if(exi_cb) card->card_exi_cb = exi_cb;
1421 card->card_unlock_cb = __unlocked_callback;
1422 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) {
1423 _CPU_ISR_Restore(level);
1424 #ifdef _CARD_DEBUG
1425 printf("__card_start(done CARD_ERROR_BUSY)\n");
1426 #endif
1427 return CARD_ERROR_BUSY;
1429 card->card_unlock_cb = NULL;
1431 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
1432 EXI_Unlock(chn);
1433 _CPU_ISR_Restore(level);
1434 #ifdef _CARD_DEBUG
1435 printf("__card_start(done CARD_ERROR_NOCARD)\n");
1436 #endif
1437 return CARD_ERROR_NOCARD;
1440 __setuptimeout(card);
1441 _CPU_ISR_Restore(level);
1443 #ifdef _CARD_DEBUG
1444 printf("__card_start(done CARD_ERROR_READY)\n");
1445 #endif
1446 return CARD_ERROR_READY;
1449 static s32 __card_writepage(s32 chn,cardcallback callback)
1451 s32 ret;
1452 card_block *card = NULL;
1453 #ifdef _CARD_DEBUG
1454 printf("__card_writepage(%d,%p)\n",chn,callback);
1455 #endif
1456 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1457 card = &cardmap[chn];
1459 card->cmd[0] = 0xf2;
1460 card->cmd[1] = (card->cmd_sector_addr>>17)&0x3f;
1461 card->cmd[2] = (card->cmd_sector_addr>>9)&0xff;
1462 card->cmd[3] = (card->cmd_sector_addr>>7)&3;
1463 card->cmd[4] = card->cmd_sector_addr&0x7f;
1464 card->cmd_len = 5;
1465 card->cmd_mode = EXI_WRITE;
1466 card->cmd_retries = 3;
1468 ret = __card_start(chn,NULL,callback);
1469 if(ret<0) return ret;
1471 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==1
1472 && EXI_Dma(chn,card->cmd_usr_buf,128,card->cmd_mode,__card_txhandler)==1) return CARD_ERROR_READY;
1474 card->card_exi_cb = NULL;
1475 EXI_Deselect(chn);
1476 EXI_Unlock(chn);
1477 return CARD_ERROR_NOCARD;
1480 static s32 __card_readsegment(s32 chn,cardcallback callback)
1482 u32 err;
1483 s32 ret;
1484 card_block *card = NULL;
1485 #ifdef _CARD_DEBUG
1486 printf("__card_readsegment(%d,%p)\n",chn,callback);
1487 #endif
1488 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1489 card = &cardmap[chn];
1491 card->cmd[0] = 0x52;
1492 card->cmd[1] = (card->cmd_sector_addr&0xFE0000)>>17;
1493 card->cmd[2] = (card->cmd_sector_addr&0x01FE00)>>9;
1494 card->cmd[3] = (card->cmd_sector_addr&0x000180)>>7;
1495 card->cmd[4] = (card->cmd_sector_addr&0x00007F);
1496 card->cmd_len = 5;
1497 card->cmd_mode = EXI_READ;
1498 card->cmd_retries = 0;
1500 ret = __card_start(chn,callback,NULL);
1501 if(ret<0) return ret;
1503 err = 0;
1504 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) err |= 0x01;
1505 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
1506 if(EXI_Dma(chn,card->cmd_usr_buf,CARD_READSIZE,card->cmd_mode,__card_txhandler)==0) err |= 0x04;
1508 if(err) {
1509 card->card_tx_cb = NULL;
1510 EXI_Deselect(chn);
1511 EXI_Unlock(chn);
1512 return CARD_ERROR_NOCARD;
1514 return CARD_ERROR_READY;
1517 static void __card_fatwritecallback(s32 chn,s32 result)
1519 s32 ret;
1520 cardcallback cb = NULL;
1521 struct card_bat *fat1,*fat2;
1522 card_block *card = &cardmap[chn];
1523 #ifdef _CARD_DEBUG
1524 printf("__card_fatwritecallback(%d,%d)\n",chn,result);
1525 #endif
1526 ret = result;
1527 if(ret>=0) {
1528 fat1 = (card->workarea+0x6000);
1529 fat2 = (card->workarea+0x8000);
1530 if(card->curr_fat==fat1) {
1531 card->curr_fat = fat2;
1532 memcpy(fat2,fat1,8192);
1533 } else {
1534 card->curr_fat = fat1;
1535 memcpy(fat1,fat2,8192);
1538 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1539 #ifdef _CARD_DEBUG
1540 printf("__card_fatwritecallback(%p,%p)\n",card->card_api_cb,card->card_erase_cb);
1541 #endif
1542 cb = card->card_erase_cb;
1543 if(cb) {
1544 card->card_erase_cb = NULL;
1545 cb(chn,ret);
1549 static void __card_dirwritecallback(s32 chn,s32 result)
1551 s32 ret;
1552 cardcallback cb = NULL;
1553 struct card_dat *dir1,*dir2;
1554 card_block *card = &cardmap[chn];
1555 #ifdef _CARD_DEBUG
1556 printf("__card_dirwritecallback(%d,%d)\n",chn,result);
1557 #endif
1558 ret = result;
1559 if(ret>=0) {
1560 dir1 = (card->workarea+0x2000);
1561 dir2 = (card->workarea+0x4000);
1562 if(card->curr_dir==dir1) {
1563 card->curr_dir = dir2;
1564 memcpy(dir2,dir1,8192);
1565 } else {
1566 card->curr_dir = dir1;
1567 memcpy(dir1,dir2,8192);
1570 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1571 #ifdef _CARD_DEBUG
1572 printf("__card_dirwritecallback(%p,%p)\n",card->card_api_cb,card->card_erase_cb);
1573 #endif
1574 cb = card->card_erase_cb;
1575 if(cb) {
1576 card->card_erase_cb = NULL;
1577 cb(chn,ret);
1581 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1583 s32 ret;
1584 card_block *card = NULL;
1585 #ifdef _CARD_DEBUG
1586 printf("__card_write(%d,%08x,%d,%p,%p)\n",chn,address,block_len,buffer,callback);
1587 #endif
1588 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1589 card = &cardmap[chn];
1591 if(!card->attached) return CARD_ERROR_NOCARD;
1593 card->cmd_blck_cnt = block_len>>7;
1594 card->cmd_sector_addr = address;
1595 card->cmd_usr_buf = buffer;
1596 card->card_xfer_cb = callback;
1597 ret = __card_writepage(chn,__blockwritecallback);
1599 return ret;
1602 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1604 s32 ret;
1605 card_block *card = NULL;
1606 #ifdef _CARD_DEBUG
1607 printf("__card_read(%d,%08x,%d,%p,%p)\n",chn,address,block_len,buffer,callback);
1608 #endif
1609 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1610 card = &cardmap[chn];
1612 card->cmd_sector_addr = address;
1613 card->cmd_blck_cnt = block_len>>9;
1614 card->cmd_usr_buf = buffer;
1615 card->card_xfer_cb = callback;
1616 ret = __card_readsegment(chn,__blockreadcallback);
1618 return ret;
1621 static s32 __card_formatregion(s32 chn,u32 encode,cardcallback callback)
1623 s32 ret;
1624 u16 tmp;
1625 u32 cnt;
1626 u64 time;
1627 u64 rnd_val;
1628 void *workarea,*memblock;
1629 cardcallback cb = NULL;
1630 card_block *card = NULL;
1631 struct card_header *header;
1632 struct card_bat *fatblock = NULL;
1633 struct card_dircntrl *dircntrl = NULL;
1634 syssram *sram;
1635 syssramex *sramex;
1636 #ifdef _CARD_DEBUG
1637 printf("__card_formatregion(%d,%d,%p)\n",chn,encode,callback);
1638 #endif
1639 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1641 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
1643 header = workarea = card->workarea;
1644 memset(header,0xff,8192);
1646 tmp = _viReg[55];
1647 header->encoding = encode;
1649 sram = __SYS_LockSram();
1650 header->serial[5] = sram->counter_bias;
1651 header->serial[6] = sram->lang;
1652 __SYS_UnlockSram(0);
1654 cnt = 0;
1655 rnd_val = time = gettime();
1656 sramex = __SYS_LockSramEx();
1657 while(cnt<12) {
1658 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1659 ((u8*)header->serial)[cnt] = (sramex->flash_id[chn][cnt]+(u32)rnd_val);
1661 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1662 rnd_val &= (u64)0x0000000000007fff;
1664 cnt++;
1666 __SYS_UnlockSramEx(0);
1668 *(u64*)&(header->serial[3]) = time;
1669 header->serial[7] = tmp;
1670 header->device_id = 0;
1671 header->size = card->card_size;
1672 __card_checksum((u16*)header,508,&header->chksum1,&header->chksum2);
1674 cnt = 0;
1675 while(cnt<2) {
1676 memblock = workarea+((cnt+1)<<13);
1677 dircntrl = memblock+8128;
1678 memset(memblock,0xff,8192);
1679 __card_checksum(memblock,8188,&dircntrl->chksum1,&dircntrl->chksum2);
1680 cnt++;
1683 cnt = 0;
1684 while(cnt<2) {
1685 memblock = workarea+((cnt+3)<<13);
1686 fatblock = memblock;
1687 memset(memblock,0,8192);
1688 fatblock->updated = cnt;
1689 fatblock->freeblocks = card->blocks-CARD_SYSAREA;
1690 fatblock->lastalloc = 4;
1691 __card_checksum(memblock+4,8188,&fatblock->chksum1,&fatblock->chksum2);
1692 cnt++;
1695 cb = callback;
1696 if(!cb) cb = __card_defaultapicallback;
1697 card->card_api_cb = cb;
1699 DCStoreRange(card->workarea,0xA000);
1701 card->format_step = 0;
1702 if((ret=__card_sectorerase(chn,(card->sector_size*card->format_step),__format_callback))>=0) return ret;
1704 __card_putcntrlblock(card,ret);
1705 return ret;
1708 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback)
1710 s32 ret;
1711 card_block *card = NULL;
1712 #ifdef _CARD_DEBUG
1713 printf("__card_sectorerase(%d,%08x,%p)\n",chn,sector,callback);
1714 #endif
1715 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1716 card = &cardmap[chn];
1718 if(sector%card->sector_size) return CARD_ERROR_FATAL_ERROR;
1720 card->cmd[0] = 0xf1;
1721 card->cmd[1] = (sector>>17)&0x7f;
1722 card->cmd[2] = (sector>>9)&0xff;
1723 card->cmd_len = 3;
1724 card->cmd_mode = -1;
1725 card->cmd_retries = 3;
1727 ret = __card_start(chn,NULL,callback);
1728 if(ret<0) return ret;
1730 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
1731 card->card_exi_cb = NULL;
1732 return CARD_ERROR_NOCARD;
1735 EXI_Deselect(chn);
1736 EXI_Unlock(chn);
1737 return ret;
1740 static void __card_faterasecallback(s32 chn,s32 result)
1742 s32 ret;
1743 cardcallback cb = NULL;
1744 struct card_bat *fatblock = NULL;
1745 card_block *card = &cardmap[chn];
1746 #ifdef _CARD_DEBUG
1747 printf("__card_faterasecallback(%d,%d)\n",chn,result);
1748 #endif
1749 ret = result;
1750 if(ret>=0) {
1751 fatblock = __card_getbatblock(card);
1752 if((ret=__card_write(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,8192,fatblock,__card_fatwritecallback))>=0) return;
1754 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1756 cb = card->card_erase_cb;
1757 if(cb) {
1758 card->card_erase_cb = NULL;
1759 cb(chn,ret);
1763 static void __card_direrasecallback(s32 chn,s32 result)
1765 s32 ret;
1766 cardcallback cb = NULL;
1767 struct card_dat *dirblock = NULL;
1768 card_block *card = &cardmap[chn];
1769 #ifdef _CARD_DEBUG
1770 printf("__card_direrasecallback(%d,%d)\n",chn,result);
1771 #endif
1772 ret = result;
1773 if(ret>=0) {
1774 dirblock = __card_getdirblock(card);
1775 if((ret=__card_write(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,8192,dirblock,__card_dirwritecallback))>=0) return;
1777 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1779 cb = card->card_erase_cb;
1780 if(cb) {
1781 card->card_erase_cb = NULL;
1782 cb(chn,ret);
1786 static void __card_createfatcallback(s32 chn,s32 result)
1788 s32 ret;
1789 cardcallback cb = NULL;
1790 card_file *file = NULL;
1791 struct card_direntry *entry = NULL;
1792 struct card_dat *dirblock = NULL;
1793 card_block *card = &cardmap[chn];
1794 #ifdef _CARD_DEBUG
1795 printf("__card_createfatcallback(%d,%d)\n",chn,result);
1796 #endif
1797 cb = card->card_api_cb;
1798 card->card_api_cb = NULL;
1800 dirblock = __card_getdirblock(card);
1802 file = card->curr_file;
1803 entry = &dirblock->entries[file->filenum];
1805 memset(entry->gamecode,0,4);
1806 memset(entry->company,0,2);
1807 if(card_gamecode[0]!=0xff) memcpy(entry->gamecode,card_gamecode,4);
1808 if(card_gamecode[0]!=0xff) memcpy(entry->company,card_company,2);
1809 entry->block = card->curr_fileblock;
1810 entry->permission = CARD_ATTRIB_PUBLIC;
1811 entry->pad_00 = 0xff;
1812 entry->copytimes = 0;
1813 entry->iconaddr = -1;
1814 entry->iconfmt = 0;
1815 entry->iconspeed = 0;
1816 entry->pad_01 = 0xffff;
1817 entry->iconspeed = (entry->iconspeed&~CARD_SPEED_MASK)|CARD_SPEED_FAST;
1818 entry->lastmodified = time(NULL);
1820 file->offset = 0;
1821 file->iblock = card->curr_fileblock;
1823 if((ret=__card_updatedir(chn,cb))<0) {
1824 __card_putcntrlblock(card,ret);
1825 if(cb) cb(chn,ret);
1829 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback)
1831 card_block *card = NULL;
1832 #ifdef _CARD_DEBUG
1833 printf("__card_updatefat(%d,%p,%p)\n",chn,fatblock,callback);
1834 #endif
1835 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1836 card = &cardmap[chn];
1838 if(!card->attached) return CARD_ERROR_NOCARD;
1840 ++fatblock->updated;
1841 __card_checksum((u16*)(((u32)fatblock)+4),0x1ffc,&fatblock->chksum1,&fatblock->chksum2);
1842 DCStoreRange(fatblock,8192);
1843 card->card_erase_cb = callback;
1845 return __card_sectorerase(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,__card_faterasecallback);
1848 static s32 __card_updatedir(s32 chn,cardcallback callback)
1850 card_block *card = NULL;
1851 void *dirblock = NULL;
1852 struct card_dircntrl *dircntrl = NULL;
1853 #ifdef _CARD_DEBUG
1854 printf("__card_updatedir(%d,%p)\n",chn,callback);
1855 #endif
1856 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1857 card = &cardmap[chn];
1859 if(!card->attached) return CARD_ERROR_NOCARD;
1861 dirblock = __card_getdirblock(card);
1862 dircntrl = dirblock+8128;
1863 ++dircntrl->updated;
1864 __card_checksum((u16*)dirblock,0x1ffc,&dircntrl->chksum1,&dircntrl->chksum2);
1865 DCStoreRange(dirblock,0x2000);
1866 card->card_erase_cb = callback;
1868 return __card_sectorerase(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,__card_direrasecallback);
1871 static void __card_dounmount(s32 chn,s32 result)
1873 u32 level;
1874 card_block *card;
1876 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1877 card = &cardmap[chn];
1879 _CPU_ISR_Disable(level);
1880 if(card->attached) {
1881 card->attached = 0;
1882 card->mount_step = 0;
1883 card->result = result;
1884 EXI_RegisterEXICallback(chn,NULL);
1885 EXI_Detach(chn);
1886 SYS_CancelAlarm(card->timeout_svc);
1888 _CPU_ISR_Restore(level);
1891 static s32 __card_domount(s32 chn)
1893 u8 status,kval;
1894 s32 ret = CARD_ERROR_READY;
1895 u32 sum;
1896 u32 id,idx,cnt;
1897 card_block *card;
1898 syssramex *sramex;
1900 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1901 card = &cardmap[chn];
1902 #ifdef _CARD_DEBUG
1903 printf("__card_domount(%d,%d)\n",chn,card->mount_step);
1904 #endif
1905 if(card->mount_step==0) {
1906 ret = 0;
1907 id = 0;
1908 if(EXI_GetID(chn,EXI_DEVICE_0,&id)==0) ret = CARD_ERROR_NOCARD;
1909 else if(!__card_iscard(id)) ret = CARD_ERROR_WRONGDEVICE;
1911 if(ret<0) goto exit;
1912 card->cid = id;
1913 card->card_size = (id&0xfc);
1914 #ifdef _CARD_DEBUG
1915 printf("__card_domount(card_type = %08x,%08x,%08x)\n",card->card_size,card->cid,id);
1916 #endif
1917 if(card->card_size) {
1918 idx = _ROTL(id,23)&0x1c;
1919 card->sector_size = card_sector_size[idx>>2];
1920 card->blocks = ((card->card_size<<20)>>3)/card->sector_size;
1922 if(card->blocks>0x0008) {
1923 idx = _ROTL(id,26)&0x1c;
1924 card->latency = card_latency[idx>>2];
1926 if((ret=__card_clearstatus(chn))<0) goto exit;
1927 if((ret=__card_readstatus(chn,&status))<0) goto exit;
1929 if(EXI_Probe(chn)==0) {
1930 ret = CARD_ERROR_NOCARD;
1931 goto exit;
1933 if(!(status&CARD_STATUS_UNLOCKED)) {
1934 #ifdef _CARD_DEBUG
1935 printf("__card_domount(card locked)\n");
1936 #endif
1937 if((ret=__dounlock(chn,card->key))<0) goto exit;
1939 cnt = 0;
1940 sum = 0;
1941 sramex = __SYS_LockSramEx();
1942 while(cnt<12) {
1943 kval = ((u8*)card->key)[cnt];
1944 sramex->flash_id[chn][cnt] = kval;
1945 sum += kval;
1946 cnt++;
1948 sum = (sum^-1)&0xff;
1949 sramex->flashID_chksum[chn] = (sum<<8)|sum;
1950 __SYS_UnlockSramEx(1);
1951 return ret;
1953 card->mount_step = 1;
1955 cnt = 0;
1956 sum = 0;
1957 sramex = __SYS_LockSramEx();
1958 while(cnt<12) {
1959 sum += sramex->flash_id[chn][cnt];
1960 cnt++;
1962 cnt = sramex->flashID_chksum[chn];
1963 __SYS_UnlockSramEx(0);
1965 sum = (sum^-1)&0xff;
1966 sum |= (sum<<8);
1967 if(cnt!=sum) {
1968 ret = CARD_ERROR_IOERROR;
1969 goto exit;
1974 if(card->mount_step==1) {
1975 card->mount_step = 2;
1976 if((ret=__card_enableinterrupt(chn,1))<0) goto exit;
1977 EXI_RegisterEXICallback(chn,__card_exihandler);
1978 EXI_Unlock(chn);
1980 DCInvalidateRange(card->workarea,0xA000);
1983 if((ret=__card_read(chn,(card->sector_size*(card->mount_step-2)),card->sector_size,card->workarea+((card->mount_step-2)<<13),__card_mountcallback))<0) goto exit;
1984 return ret;
1986 exit:
1987 EXI_Unlock(chn);
1988 __card_dounmount(chn,ret);
1990 return ret;
1993 static void __card_mountcallback(s32 chn,s32 result)
1995 s32 ret;
1996 cardcallback cb;
1997 card_block *card = &cardmap[chn];
1999 ret = result;
2000 if(ret==CARD_ERROR_NOCARD || ret==CARD_ERROR_IOERROR) {
2001 __card_dounmount(chn,ret);
2002 __card_putcntrlblock(card,ret);
2003 }else if(ret==CARD_ERROR_UNLOCKED) {
2004 if((ret=__card_domount(chn))>=0) return;
2005 } else {
2006 if((++card->mount_step)<7) {
2007 if((ret=__card_domount(chn))>=0) return;
2008 } else {
2009 ret = __card_verify(card);
2010 __card_putcntrlblock(card,ret);
2014 cb = card->card_api_cb;
2015 card->card_api_cb = NULL;
2016 if(cb) cb(chn,ret);
2019 static __inline__ void __card_srand(u32 val)
2021 crand_next = val;
2024 static __inline__ u32 __card_rand()
2026 crand_next = (crand_next*0x41C64E6D)+12345;
2027 return _SHIFTR(crand_next,16,15);
2030 static u32 __card_initval()
2032 u32 ticks = gettick();
2034 __card_srand(ticks);
2035 return ((0x7FEC8000|__card_rand())&~0x00000fff);
2038 static u32 __card_dummylen()
2040 u32 ticks = gettick();
2041 u32 val = 0,cnt = 0,shift = 1;
2043 __card_srand(ticks);
2044 val = (__card_rand()&0x1f)+1;
2046 do {
2047 ticks = gettick();
2048 val = ticks<<shift;
2049 shift++;
2050 if(shift>16) shift = 1;
2051 __card_srand(val);
2052 val = (__card_rand()&0x1f)+1;
2053 cnt++;
2054 }while(val<4 && cnt<10);
2055 if(val<4) val = 4;
2057 return val;
2061 static u32 exnor_1st(u32 a,u32 b)
2063 u32 c,d,e,f,r1,r2,r3,r4;
2065 c = 0;
2066 while(c<b) {
2067 d = (a>>23);
2068 e = (a>>15);
2069 f = (a>>7);
2070 r1 = (a^f);
2071 r2 = (e^r1);
2072 r3 = ~(d^r2); //eqv(d,r2)
2073 e = (a>>1);
2074 r4 = ((r3<<30)&0x40000000);
2075 a = (e|r4);
2076 c++;
2078 return a;
2081 static u32 exnor(u32 a,u32 b)
2083 u32 c,d,e,f,r1,r2,r3,r4;
2085 c = 0;
2086 while(c<b) {
2087 d = (a<<23);
2088 e = (a<<15);
2089 f = (a<<7);
2090 r1 = (a^f);
2091 r2 = (e^r1);
2092 r3 = ~(d^r2); //eqv(d,r2)
2093 e = (a<<1);
2094 r4 = ((r3>>30)&0x02);
2095 a = (e|r4);
2096 c++;
2098 return a;
2101 static u32 bitrev(u32 val)
2103 u32 cnt,val1,ret,shift,shift1;
2105 cnt = 0;
2106 ret = 0;
2107 shift = 1;
2108 shift1 = 0;
2109 while(cnt<32) {
2110 if(cnt<=15) {
2111 val1 = val&(1<<cnt);
2112 val1 <<= ((31-cnt)-shift1);
2113 ret |= val1;
2114 shift1++;
2115 } else if(cnt==31) {
2116 val1 = val>>31;
2117 ret |= val1;
2118 } else {
2119 val1 = 1;
2120 val1 = val&(1<<cnt);
2121 val1 >>= shift;
2122 ret |= val1;
2123 shift += 2;
2125 cnt++;
2127 return ret;
2130 static s32 __card_readarrayunlock(s32 chn,u32 address,void *buffer,u32 len,u32 flag)
2132 s32 ret;
2133 u32 err;
2134 u8 regbuf[5];
2135 card_block *card = &cardmap[chn];
2136 #ifdef _CARD_DEBUG
2137 printf("__card_readarrayunlock(%d,%d,%p,%d,%d)\n",chn,address,buffer,len,flag);
2138 #endif
2139 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
2141 address &= 0xFFFFF000;
2142 memset(regbuf,0,5);
2144 regbuf[0] = 0x52;
2145 if(!flag) {
2146 regbuf[1] = ((address&0x60000000)>>29)&0xff;
2147 regbuf[2] = ((address&0x1FE00000)>>21)&0xff;
2148 regbuf[3] = ((address&0x00180000)>>19)&0xff;
2149 regbuf[4] = ((address&0x0007F000)>>12)&0xff;
2150 } else {
2151 regbuf[1] = (address>>24)&0xff;
2152 regbuf[2] = ((address&0x00FF0000)>>16)&0xff;
2155 err = 0;
2156 if(EXI_ImmEx(chn,regbuf,5,EXI_WRITE)==0) err |= 0x01;
2157 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
2158 if(EXI_ImmEx(chn,buffer,len,EXI_READ)==0) err |= 0x04;
2159 if(EXI_Deselect(chn)==0) err |= 0x08;
2161 if(err) ret = CARD_ERROR_NOCARD;
2162 else ret = CARD_ERROR_READY;
2164 return ret;
2167 static void __dsp_initcallback(dsptask_t *task)
2169 u32 chn;
2170 card_block *card = NULL;
2171 #ifdef _CARD_DEBUG
2172 printf("__dsp_initcallback(%p)\n",task);
2173 #endif
2174 chn = 0;
2175 while(chn<EXI_CHANNEL_2) {
2176 card = &cardmap[chn];
2177 if(&card->dsp_task==task) break;
2178 chn++;
2180 if(chn>=EXI_CHANNEL_2) return;
2182 DSP_SendMailTo(0xFF000000);
2183 while(DSP_CheckMailTo());
2184 DSP_SendMailTo((u32)card->workarea);
2185 while(DSP_CheckMailTo());
2188 static u8 tmp_buffer[64] ATTRIBUTE_ALIGN(32);
2189 static void __dsp_donecallback(dsptask_t *task)
2192 u8 status;
2193 s32 ret;
2194 u32 chn,len,key;
2195 u32 workarea,val;
2196 card_block *card = NULL;
2197 #ifdef _CARD_DEBUG
2198 printf("__dsp_donecallback(%p)\n",task);
2199 #endif
2200 chn = 0;
2201 while(chn<EXI_CHANNEL_2) {
2202 card = &cardmap[chn];
2203 if(&card->dsp_task==task) break;
2204 chn++;
2206 if(chn>=EXI_CHANNEL_2) return;
2208 workarea = (u32)card->workarea;
2209 workarea = ((workarea+47)&~0x1f);
2210 key = ((u32*)workarea)[8];
2212 val = (key^card->cipher)&~0xffff;
2213 len = __card_dummylen();
2214 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
2215 EXI_Unlock(chn);
2216 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2217 return;
2220 val = exnor(card->cipher,((len+card->latency+4)<<3)+1);
2222 u32 a,b,c,r1,r2,r3;
2223 a = (val<<23);
2224 b = (val<<15);
2225 c = (val<<7);
2226 r1 = (val^c);
2227 r2 = (b^r1);
2228 r3 = ~(a^r2); //eqv(a,r2)
2229 r1 = (val|(r3>>31));
2230 card->cipher = r1;
2233 val = ((key<<16)^card->cipher)&~0xffff;
2234 len = __card_dummylen();
2235 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
2236 EXI_Unlock(chn);
2237 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2238 return;
2241 ret = __card_readstatus(chn,&status);
2242 if(EXI_Probe(chn)==0) {
2243 EXI_Unlock(chn);
2244 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2245 return;
2247 if(!ret && !(status&CARD_STATUS_UNLOCKED)) {
2248 EXI_Unlock(chn);
2249 ret = CARD_ERROR_IOERROR;
2251 __card_mountcallback(chn,ret);
2254 static s32 __dounlock(s32 chn,u32 *key)
2256 s32 ret;
2257 u32 array_addr,len,val;
2258 u32 a,b,c,d,e;
2259 card_block *card = &cardmap[chn];
2260 u32 *workarea = card->workarea;
2261 u32 *cipher1 = (u32*)(((u32)card->workarea+47)&~31);
2262 u32 *cipher2 = &cipher1[8];
2263 #ifdef _CARD_DEBUG
2264 printf("__dounlock(%d,%p)\n",chn,key);
2265 #endif
2266 array_addr = __card_initval();
2267 len = __card_dummylen();
2269 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len,0)<0) return CARD_ERROR_NOCARD;
2271 ret = 0;
2272 val = exnor_1st(array_addr,(len<<3)+1);
2274 u32 a,b,c,r1,r2,r3;
2275 a = (val>>23);
2276 b = (val>>15);
2277 c = (val>>7);
2278 r1 = (val^c);
2279 r2 = (b^r1);
2280 r3 = ~(a^r2); //eqv(a,r2)
2281 r1 = (val|(r3<<31));
2282 card->cipher = r1;
2284 card->cipher = bitrev(card->cipher);
2286 array_addr = 0;
2287 len = __card_dummylen();
2288 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len+20,1)<0) return CARD_ERROR_NOCARD;
2290 a = ((u32*)tmp_buffer)[0];
2291 b = ((u32*)tmp_buffer)[1];
2292 c = ((u32*)tmp_buffer)[2];
2293 d = ((u32*)tmp_buffer)[3];
2294 e = ((u32*)tmp_buffer)[4];
2296 a = a^card->cipher;
2297 val = exnor(card->cipher,32);
2299 u32 a,b,c,r1,r2,r3;
2300 a = (val<<23);
2301 b = (val<<15);
2302 c = (val<<7);
2303 r1 = (val^c);
2304 r2 = (b^r1);
2305 r3 = ~(a^r2); //eqv(a,r2)
2306 r1 = (val|(r3>>31));
2307 card->cipher = r1;
2310 b = b^card->cipher;
2311 val = exnor(card->cipher,32);
2313 u32 a,b,c,r1,r2,r3;
2314 a = (val<<23);
2315 b = (val<<15);
2316 c = (val<<7);
2317 r1 = (val^c);
2318 r2 = (b^r1);
2319 r3 = ~(a^r2); //eqv(a,r2)
2320 r1 = (val|(r3>>31));
2321 card->cipher = r1;
2324 c = c^card->cipher;
2325 val = exnor(card->cipher,32);
2327 u32 a,b,c,r1,r2,r3;
2328 a = (val<<23);
2329 b = (val<<15);
2330 c = (val<<7);
2331 r1 = (val^c);
2332 r2 = (b^r1);
2333 r3 = ~(a^r2); //eqv(a,r2)
2334 r1 = (val|(r3>>31));
2335 card->cipher = r1;
2338 d = d^card->cipher;
2339 val = exnor(card->cipher,32);
2341 u32 a,b,c,r1,r2,r3;
2342 a = (val<<23);
2343 b = (val<<15);
2344 c = (val<<7);
2345 r1 = (val^c);
2346 r2 = (b^r1);
2347 r3 = ~(a^r2); //eqv(a,r2)
2348 r1 = (val|(r3>>31));
2349 card->cipher = r1;
2352 e = e^card->cipher;
2353 val = exnor(card->cipher,(len<<3));
2355 u32 a,b,c,r1,r2,r3;
2356 a = (val<<23);
2357 b = (val<<15);
2358 c = (val<<7);
2359 r1 = (val^c);
2360 r2 = (b^r1);
2361 r3 = ~(a^r2); //eqv(a,r2)
2362 r1 = (val|(r3>>31));
2363 card->cipher = r1;
2366 val = exnor(card->cipher,33);
2368 u32 a,b,c,r1,r2,r3;
2369 a = (val<<23);
2370 b = (val<<15);
2371 c = (val<<7);
2372 r1 = (val^c);
2373 r2 = (b^r1);
2374 r3 = ~(a^r2); //eqv(a,r2)
2375 r1 = (val|(r3>>31));
2376 card->cipher = r1;
2379 cipher1[0] = d;
2380 cipher1[1] = e;
2381 workarea[0] = (u32)cipher1;
2382 workarea[1] = 8;
2383 workarea[2] = 0;
2384 workarea[3] = (u32)cipher2;
2385 DCFlushRange(cipher1,8);
2386 DCInvalidateRange(cipher2,4);
2387 DCFlushRange(workarea,16);
2389 card->dsp_task.prio = 255;
2390 card->dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(_cardunlockdata);
2391 card->dsp_task.iram_len = 352;
2392 card->dsp_task.iram_addr = 0x0000;
2393 card->dsp_task.init_vec = 16;
2394 card->dsp_task.res_cb = NULL;
2395 card->dsp_task.req_cb = NULL;
2396 card->dsp_task.init_cb = __dsp_initcallback;
2397 card->dsp_task.done_cb = __dsp_donecallback;
2398 DSP_AddTask(&card->dsp_task);
2400 key[0] = a;
2401 key[1] = b;
2402 key[2] = c;
2404 return CARD_ERROR_READY;
2407 s32 CARD_Init(const char *gamecode,const char *company)
2409 u32 i,level;
2411 if(card_inited) return CARD_ERROR_READY;
2412 #ifdef _CARD_DEBUG
2413 printf("CARD_Init(%s,%s,%d)\n",gamecode,company);
2414 #endif
2415 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4);
2416 if(company && strlen(company)<=2) memcpy(card_company,company,2);
2418 _CPU_ISR_Disable(level);
2419 DSP_Init();
2421 memset(cardmap,0,sizeof(card_block)*2);
2422 for(i=0;i<2;i++) {
2423 cardmap[i].result = CARD_ERROR_NOCARD;
2424 LWP_InitQueue(&cardmap[i].wait_sync_queue);
2425 SYS_CreateAlarm(&cardmap[i].timeout_svc);
2427 SYS_RegisterResetFunc(&card_resetinfo);
2428 card_inited = 1;
2429 _CPU_ISR_Restore(level);
2430 return CARD_ERROR_READY;
2433 s32 CARD_Probe(s32 chn)
2435 return EXI_Probe(chn);
2438 s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size)
2440 s32 ret;
2441 u32 level,card_id;
2442 card_block *card = NULL;
2443 #ifdef _CARD_DEBUG
2444 printf("CARD_ProbeEx(%d,%p,%p)\n",chn,mem_size,sect_size);
2445 #endif
2446 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2447 card = &cardmap[chn];
2449 _CPU_ISR_Disable(level);
2450 ret = EXI_ProbeEx(chn);
2451 if(ret<=0) {
2452 if(!ret) ret = CARD_ERROR_BUSY;
2453 else ret = CARD_ERROR_NOCARD;
2454 _CPU_ISR_Restore(level);
2455 return ret;
2458 if(card->attached) {
2459 if(card->mount_step<1) {
2460 _CPU_ISR_Restore(level);
2461 return CARD_ERROR_BUSY;
2463 if(mem_size) *mem_size = card->card_size;
2464 if(sect_size) *sect_size = card->sector_size;
2466 _CPU_ISR_Restore(level);
2467 return CARD_ERROR_READY;
2470 if(EXI_GetState(chn)&EXI_FLAG_ATTACH) ret = CARD_ERROR_WRONGDEVICE;
2471 else {
2472 ret = CARD_ERROR_BUSY;
2473 if(EXI_GetID(chn,EXI_DEVICE_0,&card_id)) {
2474 if(!__card_iscard(card_id)) ret = CARD_ERROR_WRONGDEVICE;
2475 else {
2476 if(mem_size) *mem_size = card_id&0xFC;
2477 if(sect_size) {
2478 u32 idx = _ROTL(card_id,23)&0x1c;
2479 *sect_size = card_sector_size[idx>>2];
2481 ret = CARD_ERROR_READY;
2486 _CPU_ISR_Restore(level);
2487 return ret;
2490 s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb)
2492 s32 ret = CARD_ERROR_READY;
2493 u32 level;
2494 cardcallback attachcb = NULL;
2495 card_block *card = NULL;
2496 #ifdef _CARD_DEBUG
2497 printf("CARD_MountAsync(%d,%p,%p,%p)\n",chn,workarea,detach_cb,attach_cb);
2498 #endif
2499 if(!workarea) return CARD_ERROR_NOCARD;
2500 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2501 card = &cardmap[chn];
2503 _CPU_ISR_Disable(level);
2504 #ifdef _CARD_DEBUG
2505 printf("card->attached = %d,%08x\n",card->attached,EXI_GetState(chn));
2506 #endif
2507 if(card->result==CARD_ERROR_BUSY) {
2508 _CPU_ISR_Restore(level);
2509 return CARD_ERROR_BUSY;
2511 if(card->attached || !(EXI_GetState(chn)&EXI_FLAG_ATTACH)) {
2512 card->result = CARD_ERROR_BUSY;
2513 card->workarea = workarea;
2514 card->card_ext_cb = detach_cb;
2516 attachcb = attach_cb;
2517 if(!attachcb) attachcb = __card_defaultapicallback;
2518 card->card_api_cb = attachcb;
2519 card->card_exi_cb = NULL;
2521 if(!card->attached) {
2522 if(EXI_Attach(chn,__card_exthandler)==0) {
2523 card->result = CARD_ERROR_NOCARD;
2524 #ifdef _CARD_DEBUG
2525 printf("card->attached = %d,%08x,attach failed\n",card->attached,EXI_GetState(chn));
2526 #endif
2527 _CPU_ISR_Restore(level);
2528 return CARD_ERROR_NOCARD;
2531 card->mount_step = 0;
2532 card->attached = 1;
2533 #ifdef _CARD_DEBUG
2534 printf("card->attached = %d,%08x\n",card->attached,EXI_GetState(chn));
2535 #endif
2536 EXI_RegisterEXICallback(chn,NULL);
2537 SYS_CancelAlarm(card->timeout_svc);
2538 card->curr_dir = NULL;
2539 card->curr_fat = NULL;
2540 _CPU_ISR_Restore(level);
2542 card->card_unlock_cb = __card_mountcallback;
2543 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) return 0;
2545 card->card_unlock_cb = NULL;
2546 __card_domount(chn);
2547 return 1;
2550 ret = CARD_ERROR_WRONGDEVICE;
2551 _CPU_ISR_Restore(level);
2552 return ret;
2555 s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb)
2557 s32 ret;
2558 #ifdef _CARD_DEBUG
2559 printf("CARD_Mount(%d,%p,%p)\n",chn,workarea,detach_cb);
2560 #endif
2561 if((ret=CARD_MountAsync(chn,workarea,detach_cb,__card_synccallback))>=0) {
2562 ret = __card_sync(chn);
2564 return ret;
2567 s32 CARD_Unmount(s32 chn)
2569 s32 ret;
2570 card_block *card = NULL;
2572 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2574 if((ret=__card_getcntrlblock(chn,&card))<0) ret = CARD_ERROR_NOCARD;
2576 __card_dounmount(chn,ret);
2577 return CARD_ERROR_READY;
2580 s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2582 s32 ret;
2583 cardcallback cb = NULL;
2584 struct card_dat *dirblock = NULL;
2585 card_block *card = NULL;
2587 if(len<=0 || (len&0x1ff) || (offset>0 && (offset&0x1ff))) return CARD_ERROR_FATAL_ERROR;
2588 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2590 dirblock = __card_getdirblock(card);
2591 DCInvalidateRange(buffer,len);
2593 cb = callback;
2594 if(!cb) cb = __card_defaultapicallback;
2595 card->card_api_cb = cb;
2597 if(len>=(card->sector_size-(file->offset&(card->sector_size-1)))) len = (card->sector_size-(file->offset&(card->sector_size-1)));
2599 if((ret=__card_read(file->chn,(file->iblock*card->sector_size),len,buffer,__read_callback))<0) {
2600 __card_putcntrlblock(card,ret);
2601 return ret;
2603 return 0;
2606 s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset)
2608 s32 ret;
2610 if((ret=CARD_ReadAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2611 ret = __card_sync(file->chn);
2613 return ret;
2616 s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2618 s32 ret;
2619 cardcallback cb = NULL;
2620 card_block *card = NULL;
2622 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2623 if(len<0 || (len&(card->sector_size-1)) || (offset>0 && offset&(card->sector_size-1))) {
2624 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
2625 return CARD_ERROR_FATAL_ERROR;
2628 DCStoreRange(buffer,len);
2629 cb = callback;
2630 if(!cb) cb = __card_defaultapicallback;
2631 card->card_api_cb = cb;
2633 card->cmd_usr_buf = buffer;
2634 if((ret=__card_sectorerase(file->chn,(file->iblock*card->sector_size),__erase_callback))>=0) return ret;
2635 __card_putcntrlblock(card,ret);
2636 return ret;
2639 s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset)
2641 s32 ret;
2643 if((ret=CARD_WriteAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2644 ret = __card_sync(file->chn);
2646 return ret;
2649 s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback)
2651 u32 i,len;
2652 s32 ret,filenum;
2653 cardcallback cb = NULL;
2654 card_block *card = NULL;
2655 struct card_bat *fatblock = NULL;
2656 struct card_dat *dirblock = NULL;
2657 struct card_direntry *entry = NULL;
2658 #ifdef _CARD_DEBUG
2659 printf("CARD_CreateAsync(%d,%s,%d,%p,%p)\n",chn,filename,size,file,callback);
2660 #endif
2661 len = strlen(filename);
2662 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2664 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2665 if(size<=0 || size%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2667 dirblock = __card_getdirblock(card);
2669 filenum = -1;
2670 entry = dirblock->entries;
2671 for(i=0;i<CARD_MAXFILES;i++) {
2672 if(entry[i].gamecode[0]==0xff) {
2673 if(filenum==-1) filenum = i;
2674 } else if(memcmp(entry[i].filename,filename,len)==0) {
2675 if((card_gamecode[0]==0xff || card_company[0]==0xff)
2676 || ((card_gamecode[0]!=0xff && memcmp(entry[i].gamecode,card_gamecode,4)==0)
2677 && (card_company[0]!=0xff && memcmp(entry[i].company,card_company,2)==0))) {
2678 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2679 return CARD_ERROR_EXIST;
2683 if(filenum==-1) {
2684 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2685 return CARD_ERROR_NOENT;
2688 fatblock = __card_getbatblock(card);
2689 if((fatblock->freeblocks*card->sector_size)<size) {
2690 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2691 return CARD_ERROR_INSSPACE;
2694 cb = callback;
2695 if(!cb) cb = __card_defaultapicallback;
2696 card->card_api_cb = cb;
2698 entry[filenum].length = size/card->sector_size;
2699 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2700 memcpy(entry[filenum].filename,filename,len+1);
2702 card->curr_file = file;
2703 file->chn = chn;
2704 file->filenum = filenum;
2705 if((ret=__card_allocblock(chn,(size/card->sector_size),__card_createfatcallback))<0) {
2706 __card_putcntrlblock(card,ret);
2707 return ret;
2710 return 0;
2713 s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file)
2715 s32 ret;
2717 if((ret=CARD_CreateAsync(chn,filename,size,file,__card_synccallback))>=0) {
2718 ret = __card_sync(chn);
2720 return ret;
2723 s32 CARD_CreateEntryAsync(s32 chn,card_dir *direntry,card_file *file,cardcallback callback)
2725 u32 i,len;
2726 s32 ret,filenum;
2727 cardcallback cb = NULL;
2728 card_block *card = NULL;
2729 struct card_bat *fatblock = NULL;
2730 struct card_dat *dirblock = NULL;
2731 struct card_direntry *entry = NULL;
2732 #ifdef _CARD_DEBUG
2733 printf("CARD_CreateEntryAsync(%d,%p,%p,%p)\n",chn,direntry,file,callback);
2734 #endif
2735 len = strlen((const char*)direntry->filename);
2736 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2738 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2739 if(direntry->filelen<=0 || direntry->filelen%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2741 dirblock = __card_getdirblock(card);
2743 filenum = -1;
2744 entry = dirblock->entries;
2745 for(i=0;i<CARD_MAXFILES;i++) {
2746 if(entry[i].gamecode[0]==0xff) {
2747 if(filenum==-1) filenum = i;
2748 } else if(memcmp(entry[i].filename,direntry->filename,len)==0) {
2749 if((entry->gamecode[0]==0xff || entry->company[0]==0xff)
2750 || ((entry->gamecode[0]!=0xff && memcmp(entry[i].gamecode,entry->gamecode,4)==0)
2751 && (entry->company[0]!=0xff && memcmp(entry[i].company,entry->company,2)==0))) {
2752 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2753 return CARD_ERROR_EXIST;
2757 if(filenum==-1) {
2758 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2759 return CARD_ERROR_NOENT;
2762 fatblock = __card_getbatblock(card);
2763 if((fatblock->freeblocks*card->sector_size)<direntry->filelen) {
2764 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2765 return CARD_ERROR_INSSPACE;
2768 cb = callback;
2769 if(!cb) cb = __card_defaultapicallback;
2770 card->card_api_cb = cb;
2772 entry[filenum].length = direntry->filelen/card->sector_size;
2773 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2774 memcpy(entry[filenum].filename,direntry->filename,len+1);
2776 card->curr_file = file;
2777 file->chn = chn;
2778 file->filenum = filenum;
2779 if((ret=__card_allocblock(chn,(direntry->filelen/card->sector_size),__card_createfatcallback))<0) {
2780 __card_putcntrlblock(card,ret);
2781 return ret;
2784 return 0;
2787 s32 CARD_CreateEntry(s32 chn,card_dir *direntry,card_file *file)
2789 s32 ret;
2791 if((ret=CARD_CreateEntryAsync(chn,direntry,file,__card_synccallback))>=0) {
2792 ret = __card_sync(chn);
2794 return ret;
2797 s32 CARD_Open(s32 chn,const char *filename,card_file *file)
2799 s32 ret,fileno;
2800 struct card_dat *dirblock = NULL;
2801 card_block *card = NULL;
2803 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2805 file->filenum = -1;
2806 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2807 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2808 __card_putcntrlblock(card,ret);
2809 return ret;
2811 dirblock = __card_getdirblock(card);
2812 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2813 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2814 return CARD_ERROR_BROKEN;
2816 file->chn = chn;
2817 file->filenum = fileno;
2818 file->offset = 0;
2819 file->len = dirblock->entries[fileno].length*card->sector_size;
2820 file->iblock = dirblock->entries[fileno].block;
2822 __card_putcntrlblock(card,CARD_ERROR_READY);
2823 return CARD_ERROR_READY;
2826 s32 CARD_OpenEntry(s32 chn,card_dir *entry,card_file *file)
2828 s32 ret,fileno;
2829 struct card_dat *dirblock = NULL;
2830 card_block *card = NULL;
2832 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2834 file->filenum = -1;
2835 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2836 if((ret=__card_getfilenum(card,(const char*)entry->filename,(const char*)entry->gamecode,(const char*)entry->company,&fileno))<0) {
2837 __card_putcntrlblock(card,ret);
2838 return ret;
2841 dirblock = __card_getdirblock(card);
2842 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2843 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2844 return CARD_ERROR_BROKEN;
2847 file->chn = chn;
2848 file->filenum = entry->fileno;
2849 file->offset = 0;
2850 file->len = dirblock->entries[fileno].length*card->sector_size;
2851 file->iblock = dirblock->entries[fileno].block;
2853 __card_putcntrlblock(card,CARD_ERROR_READY);
2854 return CARD_ERROR_READY;
2857 s32 CARD_Close(card_file *file)
2859 s32 ret;
2860 card_block *card = NULL;
2862 if(file->chn<EXI_CHANNEL_0 || file->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2863 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
2864 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
2866 file->chn = -1;
2867 __card_putcntrlblock(card,CARD_ERROR_READY);
2868 return CARD_ERROR_READY;
2871 s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback)
2873 s32 ret,fileno;
2874 cardcallback cb = NULL;
2875 card_block *card = NULL;
2876 struct card_dat *dirblock = NULL;
2877 struct card_direntry *entry = NULL;
2878 #ifdef _CARD_DEBUG
2879 printf("CARD_DeleteAsync(%d,%s,%p)\n",chn,filename,callback);
2880 #endif
2881 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2882 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2883 __card_putcntrlblock(card,ret);
2884 return ret;
2887 dirblock = __card_getdirblock(card);
2888 entry = &dirblock->entries[fileno];
2890 card->curr_fileblock = entry->block;
2891 memset(entry,-1,sizeof(struct card_direntry));
2893 cb = callback;
2894 if(!cb) cb = __card_defaultapicallback;
2895 card->card_api_cb = cb;
2897 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2899 __card_putcntrlblock(card,ret);
2900 return ret;
2903 s32 CARD_Delete(s32 chn,const char *filename)
2905 s32 ret;
2906 #ifdef _CARD_DEBUG
2907 printf("CARD_Delete(%d,%s)\n",chn,filename);
2908 #endif
2909 if((ret=CARD_DeleteAsync(chn,filename,__card_synccallback))>=0) {
2910 ret = __card_sync(chn);
2912 return ret;
2915 s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback)
2917 s32 ret;
2918 cardcallback cb = NULL;
2919 card_block *card = NULL;
2920 struct card_dat *dirblock = NULL;
2921 struct card_direntry *entry = NULL;
2922 #ifdef _CARD_DEBUG
2923 printf("CARD_DeleteEntryAsync(%p,%p)\n",dir_entry,callback);
2924 #endif
2925 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2926 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2928 dirblock = __card_getdirblock(card);
2929 entry = &dirblock->entries[dir_entry->fileno];
2931 card->curr_fileblock = entry->block;
2932 memset(entry,-1,sizeof(struct card_direntry));
2934 cb = callback;
2935 if(!cb) cb = __card_defaultapicallback;
2936 card->card_api_cb = cb;
2938 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2940 __card_putcntrlblock(card,ret);
2941 return ret;
2944 s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry)
2946 s32 ret;
2947 #ifdef _CARD_DEBUG
2948 printf("CARD_DeleteEntry(%p)\n",dir_entry);
2949 #endif
2950 if((ret=CARD_DeleteEntryAsync(chn,dir_entry,__card_synccallback))>=0) {
2951 ret = __card_sync(chn);
2953 return ret;
2956 s32 CARD_FormatAsync(s32 chn,cardcallback callback)
2958 u32 enc;
2960 enc = SYS_GetFontEncoding();
2961 return __card_formatregion(chn,enc,callback);
2964 s32 CARD_Format(s32 chn)
2966 s32 ret;
2967 u32 enc;
2969 enc = SYS_GetFontEncoding();
2970 if((ret=__card_formatregion(chn,enc,__card_synccallback))>=0) {
2971 ret = __card_sync(chn);
2973 return ret;
2976 s32 CARD_GetErrorCode(s32 chn)
2978 card_block *card = NULL;
2980 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2981 card = &cardmap[chn];
2982 return card->result;
2985 s32 __card_findnext(card_dir *dir)
2987 s32 ret;
2988 struct card_dat *dirblock = NULL;
2989 struct card_direntry *entries = NULL;
2990 card_block *card = NULL;
2992 if(dir->chn<EXI_CHANNEL_0 || dir->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2993 if(dir->fileno>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
2994 if((ret=__card_getcntrlblock(dir->chn,&card))<0) return ret;
2996 if(!card->attached) return CARD_ERROR_NOCARD;
2997 dirblock = __card_getdirblock(card);
2999 entries = dirblock->entries;
3000 do {
3001 //printf("%s\n", entries[dir->fileno].filename);
3002 if(entries[dir->fileno].gamecode[0]!=0xff) {
3003 if ((dir->showall || memcmp(entries[dir->fileno].gamecode,card_gamecode,4)==0)
3004 && (dir->showall || memcmp(entries[dir->fileno].company,card_company,2)==0)) {
3005 dir->filelen = entries[dir->fileno].length*card->sector_size;
3006 memcpy(dir->filename, entries[dir->fileno].filename, CARD_FILENAMELEN);
3007 memcpy(dir->gamecode, entries[dir->fileno].gamecode, 4);
3008 memcpy(dir->company, entries[dir->fileno].company, 2);
3010 __card_putcntrlblock(card,CARD_ERROR_READY);
3011 return CARD_ERROR_READY;
3014 dir->fileno++;
3015 } while (dir->fileno < CARD_MAXFILES);
3016 __card_putcntrlblock(card,CARD_ERROR_NOFILE);
3017 return CARD_ERROR_NOFILE;
3020 s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall)
3022 // initialise structure
3023 dir->chn = chn;
3024 dir->fileno = 0;
3025 dir->filelen = 0;
3026 dir->filename[0] = 0;
3027 dir->gamecode[0] = 0;
3028 dir->company[0] = 0;
3029 dir->showall = showall;
3030 return __card_findnext(dir);
3033 s32 CARD_FindNext(card_dir *dir)
3035 dir->fileno++;
3037 return __card_findnext(dir);
3040 s32 CARD_GetDirectory(s32 chn,card_dir *dir_entries,s32 *count,bool showall)
3042 s32 i,cnt;
3043 s32 ret = CARD_ERROR_READY;
3044 struct card_dat *dirblock = NULL;
3045 struct card_direntry *entries = NULL;
3046 card_block *card = NULL;
3048 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3049 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3051 if(!card->attached) return CARD_ERROR_NOCARD;
3052 dirblock = __card_getdirblock(card);
3054 entries = dirblock->entries;
3055 for(i=0,cnt=0;i<CARD_MAXFILES;i++) {
3056 if(entries[i].gamecode[0]!=0xff) {
3057 if(showall || ((card_gamecode[0]!=0xff && memcmp(entries[i].gamecode,card_gamecode,4)==0)
3058 && (card_company[0]!=0xff && memcmp(entries[i].company,card_company,2)==0))) {
3059 dir_entries[cnt].fileno = i;
3060 dir_entries[cnt].permissions = entries[i].permission;
3061 dir_entries[cnt].filelen = entries[i].length*card->sector_size;
3062 memcpy(dir_entries[cnt].gamecode,entries[i].gamecode,4);
3063 memcpy(dir_entries[cnt].company,entries[i].company,2);
3064 memcpy(dir_entries[cnt].filename,entries[i].filename,CARD_FILENAMELEN);
3065 cnt++;
3069 if(count) *count = cnt;
3070 if(cnt==0) ret = CARD_ERROR_NOFILE;
3071 __card_putcntrlblock(card,ret);
3072 return ret;
3075 s32 CARD_GetSectorSize(s32 chn,u32 *sector_size)
3077 s32 ret;
3078 card_block *card = NULL;
3080 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3081 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3083 *sector_size = card->sector_size;
3084 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
3086 return ret;
3089 s32 CARD_GetBlockCount(s32 chn,u32 *block_count)
3091 s32 ret;
3092 card_block *card = NULL;
3094 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3095 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3097 *block_count = card->blocks;
3098 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
3100 return ret;
3103 s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats)
3105 s32 ret;
3106 card_block *card = NULL;
3107 struct card_dat *dirblock = NULL;
3108 struct card_direntry *entry = NULL;
3110 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3111 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
3113 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3115 dirblock = __card_getdirblock(card);
3116 if(dirblock) {
3117 entry = &dirblock->entries[fileno];
3118 memcpy(stats->gamecode,entry->gamecode,4);
3119 memcpy(stats->company,entry->company,2);
3120 memcpy(stats->filename,entry->filename,CARD_FILENAMELEN);
3121 stats->len = entry->length*card->sector_size;
3122 stats->time = entry->lastmodified;
3123 stats->banner_fmt = entry->bannerfmt;
3124 stats->icon_addr = entry->iconaddr;
3125 stats->icon_fmt = entry->iconfmt;
3126 stats->icon_speed = entry->iconspeed;
3127 stats->comment_addr = entry->commentaddr;
3128 __card_updateiconoffsets(entry,stats);
3131 return __card_putcntrlblock(card,CARD_ERROR_READY);
3134 s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback)
3136 s32 ret;
3137 card_block *card = NULL;
3138 struct card_dat *dirblock = NULL;
3139 struct card_direntry *entry = NULL;
3141 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3142 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
3143 if(stats->icon_addr!=-1 && stats->icon_addr>CARD_READSIZE) return CARD_ERROR_FATAL_ERROR;
3144 if(stats->comment_addr!=-1 && stats->comment_addr>8128) return CARD_ERROR_FATAL_ERROR;
3145 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3147 ret = CARD_ERROR_BROKEN;
3148 dirblock = __card_getdirblock(card);
3149 if(dirblock) {
3150 entry = &dirblock->entries[fileno];
3151 entry->bannerfmt = stats->banner_fmt;
3152 entry->iconaddr = stats->icon_addr;
3153 entry->iconfmt = stats->icon_fmt;
3154 entry->iconspeed = stats->icon_speed;
3155 entry->commentaddr = stats->comment_addr;
3156 __card_updateiconoffsets(entry,stats);
3158 if(entry->iconaddr==-1) entry->iconfmt = ((entry->iconfmt&~CARD_ICON_MASK)|CARD_ICON_CI);
3160 entry->lastmodified = time(NULL);
3161 if((ret=__card_updatedir(chn,callback))>=0) return ret;
3164 return __card_putcntrlblock(card,ret);
3167 s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats)
3169 s32 ret;
3171 if((ret=CARD_SetStatusAsync(chn,fileno,stats,__card_synccallback))>=0) {
3172 ret = __card_sync(chn);
3174 return ret;
3177 s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr)
3179 s32 ret;
3180 struct card_direntry entry;
3182 if((ret=__card_getstatusex(chn,fileno,&entry))==CARD_ERROR_READY) {
3183 *attr = entry.permission;
3185 return ret;
3188 s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback)
3190 s32 ret;
3191 struct card_direntry entry;
3193 if((ret=__card_getstatusex(chn,fileno,&entry))>=0) {
3194 entry.permission = attr;
3195 ret = __card_setstatusexasync(chn,fileno,&entry,callback);
3197 return ret;
3200 s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr)
3202 s32 ret;
3204 if((ret=CARD_SetAttributesAsync(chn,fileno,attr,__card_synccallback))>=0) {
3205 ret = __card_sync(chn);
3207 return ret;
3210 s32 CARD_SetCompany(const char *company)
3212 u32 level,i;
3214 _CPU_ISR_Disable(level);
3215 for(i=0;i<2;i++) card_company[i] = 0xff;
3216 if(company && strlen(company)<=2) memcpy(card_company,company,2) ;
3217 _CPU_ISR_Restore(level);
3219 return CARD_ERROR_READY;
3222 s32 CARD_SetGamecode(const char *gamecode)
3224 u32 level,i;
3226 _CPU_ISR_Disable(level);
3227 for(i=0;i<4;i++) card_gamecode[i] = 0xff;
3228 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4) ;
3229 _CPU_ISR_Restore(level);
3231 return CARD_ERROR_READY;