remove const from TPL_OpenTPLFromMemory since the memory is altered
[libogc.git] / libogc / card.c
blobdefe95a0c3cd30b44e83ddf834d814aa4af5063e
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 #if defined(HW_RVL)
152 static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) =
154 0x00000000,0x00000000,0x00000000,0x00000000,
155 0x00000000,0x00000000,0x00000021,0x02ff0021,
156 0x13061203,0x12041305,0x009200ff,0x0088ffff,
157 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf,
158 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf,
159 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e,
160 0x1fdf24ff,0x02403fff,0x00980400,0x009a0010,
161 0x00990000,0x8e0002bf,0x009402bf,0x864402bf,
162 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00,
163 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380,
164 0x00010295,0x005a0380,0x00020295,0x8000029f,
165 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e,
166 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff,
167 0x03403fff,0x1c9f02bf,0x008e00c7,0xffff02bf,
168 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf,
169 0x008e20ff,0x03403fff,0x1f5f02bf,0x008e21ff,
170 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021,
171 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0,
172 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd,
173 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d,
174 0x009c02df,0x00000000,0x00000000,0x00000000,
175 0x00000000,0x00000000,0x00000000,0x00000000
178 #elif defined(HW_DOL)
180 static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) =
182 0x00000000,0x00000000,0x00000000,0x00000000,
183 0x00000000,0x00000000,0x00000021,0x02ff0021,
184 0x13061203,0x12041305,0x009200ff,0x0088ffff,
185 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf,
186 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf,
187 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e,
188 0x1fdf24ff,0x02400fff,0x00980400,0x009a0010,
189 0x00990000,0x8e0002bf,0x009402bf,0x864402bf,
190 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00,
191 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380,
192 0x00010295,0x005a0380,0x00020295,0x8000029f,
193 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e,
194 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff,
195 0x03400fff,0x1c9f02bf,0x008e00c7,0xffff02bf,
196 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf,
197 0x008e20ff,0x03400fff,0x1f5f02bf,0x008e21ff,
198 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021,
199 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0,
200 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd,
201 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d,
202 0x009c02df,0x00000000,0x00000000,0x00000000,
203 0x00000000,0x00000000,0x00000000,0x00000000
205 #endif
207 static u32 card_sector_size[] =
209 0x0002000,
210 0x0004000,
211 0x0008000,
212 0x0010000,
213 0x0020000,
214 0x0040000,
215 0x0000000,
216 0x0000000
219 static u32 card_latency[] =
221 0x00000004,
222 0x00000008,
223 0x00000010,
224 0x00000020,
225 0x00000030,
226 0x00000080,
227 0x00000100,
228 0x00000200
231 static u32 card_inited = 0;
232 static u32 crand_next = 1;
234 static u8 card_gamecode[4] = {0xff,0xff,0xff,0xff};
235 static u8 card_company[2] = {0xff,0xff};
236 static card_block cardmap[2];
238 static void __card_mountcallback(s32 chn,s32 result);
239 static void __erase_callback(s32 chn,s32 result);
240 static s32 __dounlock(s32 chn,u32 *key);
241 static s32 __card_readsegment(s32 chn,cardcallback callback);
242 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
243 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback);
244 static s32 __card_updatedir(s32 chn,cardcallback callback);
245 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
246 static s32 __card_writepage(s32 chn,cardcallback callback);
247 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback);
248 static s32 __card_onreset(s32 final);
250 static sys_resetinfo card_resetinfo = {
252 __card_onreset,
256 extern unsigned long gettick();
257 extern long long gettime();
258 extern syssram* __SYS_LockSram();
259 extern syssramex* __SYS_LockSramEx();
260 extern u32 __SYS_UnlockSram(u32 write);
261 extern u32 __SYS_UnlockSramEx(u32 write);
263 static vu16* const _viReg = (u16*)0xCC002000;
265 /* new api */
266 static s32 __card_onreset(s32 final)
268 if(final==FALSE) {
269 if(CARD_Unmount(CARD_SLOTA)==-1) return 0;
270 if(CARD_Unmount(CARD_SLOTB)==-1) return 0;
272 return 1;
275 static void __card_checksum(u16 *buff,u32 len,u16 *cs1,u16 *cs2)
277 u32 i;
278 #ifdef _CARD_DEBUG
279 printf("__card_checksum(%p,%d,%p,%p)\n",buff,len,cs1,cs2);
280 #endif
281 *cs1 = 0;
282 *cs2 = 0;
283 len /= 2;
284 for (i = 0; i < len; ++i) {
285 *cs1 += buff[i];
286 *cs2 += (buff[i] ^ 0xffff);
288 if (*cs1 == 0xffff) *cs1 = 0;
289 if (*cs2 == 0xffff) *cs2 = 0;
292 static s32 __card_putcntrlblock(card_block *card,s32 result)
294 u32 level;
296 _CPU_ISR_Disable(level);
297 if(card->attached) card->result = result;
298 else if(card->result==CARD_ERROR_BUSY) card->result = result;
299 _CPU_ISR_Restore(level);
300 return result;
303 static s32 __card_getcntrlblock(s32 chn,card_block **card)
305 s32 ret;
306 u32 level;
307 card_block *rcard = NULL;
309 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
311 _CPU_ISR_Disable(level);
312 rcard = &cardmap[chn];
313 if(!rcard->attached) {
314 _CPU_ISR_Restore(level);
315 return CARD_ERROR_NOCARD;
318 ret = CARD_ERROR_BUSY;
319 if(rcard->result!=CARD_ERROR_BUSY) {
320 rcard->result = CARD_ERROR_BUSY;
321 rcard->card_api_cb = NULL;
322 *card = rcard;
323 ret = CARD_ERROR_READY;
325 _CPU_ISR_Restore(level);
326 return ret;
329 static __inline__ struct card_dat* __card_getdirblock(card_block *card)
331 return card->curr_dir;
334 static __inline__ struct card_bat* __card_getbatblock(card_block *card)
336 return card->curr_fat;
339 static s32 __card_sync(s32 chn)
341 s32 ret;
342 u32 level;
343 card_block *card = &cardmap[chn];
345 _CPU_ISR_Disable(level);
346 while((ret=CARD_GetErrorCode(chn))==CARD_ERROR_BUSY) {
347 LWP_ThreadSleep(card->wait_sync_queue);
349 _CPU_ISR_Restore(level);
350 return ret;
353 static void __card_synccallback(s32 chn,s32 result)
355 u32 level;
356 card_block *card = &cardmap[chn];
357 #ifdef _CARD_DEBUG
358 printf("__card_synccallback(%d,%d,%d)\n",chn,result,card->result);
359 #endif
360 _CPU_ISR_Disable(level);
361 LWP_ThreadBroadcast(card->wait_sync_queue);
362 _CPU_ISR_Restore(level);
365 static void __card_updateiconoffsets(struct card_direntry *entry,card_stat *stats)
367 s32 i;
368 u8 bnrfmt,nicons;
369 u32 iconaddr,iconbase;
371 iconaddr = entry->iconaddr;
372 if(iconaddr==-1) {
373 stats->banner_fmt = 0;
374 stats->icon_fmt = 0;
375 stats->icon_speed = 0;
376 iconaddr = 0;
379 if(entry->bannerfmt&CARD_BANNER_MASK) {
380 if(!(entry->bannerfmt&0x10)) {
381 bnrfmt = (entry->bannerfmt&CARD_BANNER_MASK);
382 if(bnrfmt==CARD_BANNER_CI) {
383 stats->banner_fmt = bnrfmt;
384 stats->offset_banner = iconaddr;
385 stats->offset_banner_tlut = iconaddr+3072;
386 iconaddr += (3072+512);
387 } else if(bnrfmt==CARD_BANNER_RGB) {
388 stats->banner_fmt = bnrfmt;
389 stats->offset_banner = iconaddr;
390 stats->offset_banner_tlut = -1;
391 iconaddr += 6144;
393 } else {
394 stats->offset_banner = -1;
395 stats->offset_banner_tlut = -1;
399 nicons = 0;
400 for(i=0;i<CARD_MAXICONS;i++) {
401 stats->iconfmt[i] = ((entry->iconfmt>>(i<<1))&CARD_ICON_MASK);
402 stats->iconspeed[i] = ((entry->iconspeed>>(i<<1))&CARD_SPEED_MASK);
403 if(stats->iconspeed[i]==0) stats->iconfmt[i] = 0;
404 if(stats->iconfmt[i]) nicons++;
407 iconbase = iconaddr;
408 for(i=0;i<CARD_MAXICONS;i++) {
409 switch(stats->iconfmt[i]) {
410 case 1: //CARD_ICON_CI with shared palette
411 stats->offset_icon[i] = iconaddr;
412 stats->offset_icon_tlut[i] = iconbase + (nicons*1024);
413 iconaddr += 1024;
414 break;
415 case 2: //CARD_ICON_RGB
416 stats->offset_icon[i] = iconaddr;
417 stats->offset_icon_tlut[i] = -1;
418 iconaddr += 3072;
419 break;
420 case 3: //CARD_ICON_CI with own palette
421 stats->offset_icon[i] = iconaddr;
422 stats->offset_icon_tlut[i] = iconaddr + 1024;
423 iconaddr += 1536;
424 break;
425 default: //CARD_ICON_NONE
426 stats->offset_icon[i] = -1;
427 stats->offset_icon_tlut[i] = -1;
428 break;
433 // stats->offset_data = iconaddr;
436 static s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry)
438 s32 ret;
439 card_block *card = NULL;
440 struct card_dat *dirblock = NULL;
442 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
443 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
444 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
446 ret = CARD_ERROR_BROKEN;
447 dirblock = __card_getdirblock(card);
448 if(dirblock) {
449 ret = CARD_ERROR_READY;
450 memcpy(entry,&dirblock->entries[fileno],sizeof(struct card_direntry));
452 return __card_putcntrlblock(card,ret);
455 static s32 __card_setstatusexasync(s32 chn,s32 fileno,struct card_direntry *entry,cardcallback callback)
457 s32 ret,i,bend;
458 card_block *card = NULL;
459 struct card_dat *dirblock = NULL;
460 struct card_direntry *entries = NULL;
462 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
463 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
464 if(entry->filename[0]==0xff || entry->filename[0]==0) return CARD_ERROR_FATAL_ERROR;
465 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
467 ret = CARD_ERROR_BROKEN;
468 dirblock = __card_getdirblock(card);
469 if(dirblock) {
470 i = 0; bend = 0;
471 ret = CARD_ERROR_READY;
472 entries = dirblock->entries;
473 while(i<CARD_FILENAMELEN) {
474 if(bend || entry->filename[i]==0) {
475 entry->filename[i] = 0;
476 bend = 1;
478 i++;
481 if(memcmp(entries[fileno].filename,entry->filename,CARD_FILENAMELEN)
482 || memcmp(entries[fileno].gamecode,entry->gamecode,4)
483 || memcmp(entries[fileno].company,entry->company,2)) {
484 i = 0;
485 while(i<CARD_MAXFILES) {
486 if(i!=fileno && entries[i].gamecode[0]!=0xff
487 && memcmp(entries[i].gamecode,entry->gamecode,4)==0
488 && memcmp(entries[i].company,entry->company,2)==0
489 && memcmp(entries[i].filename,entry->filename,CARD_FILENAMELEN)==0) {
490 return __card_putcntrlblock(card,CARD_ERROR_EXIST);
492 i++;
494 memcpy(entries[fileno].filename,entry->filename,CARD_FILENAMELEN);
495 memcpy(entries[fileno].gamecode,entry->gamecode,4);
496 memcpy(entries[fileno].company,entry->company,2);
499 entries[fileno].lastmodified = entry->lastmodified;
500 entries[fileno].bannerfmt = entry->bannerfmt;
501 entries[fileno].iconaddr = entry->iconaddr;
502 entries[fileno].iconfmt = entry->iconfmt;
503 entries[fileno].iconspeed = entry->iconspeed;
504 entries[fileno].commentaddr = entry->commentaddr;
505 entries[fileno].permission = entry->permission;
506 entries[fileno].copytimes = entry->copytimes;
508 if((ret=__card_updatedir(chn,callback))>=0) return ret;
510 return __card_putcntrlblock(card,ret);
513 static s32 __card_setstatusex(s32 chn,s32 fileno,struct card_direntry *entry)
515 s32 ret;
517 if((ret=__card_setstatusexasync(chn,fileno,entry,__card_synccallback))>=0) {
518 ret = __card_sync(chn);
520 return ret;
523 static s32 __card_getfilenum(card_block *card,const char *filename,const char *gamecode,const char *company,s32 *fileno)
525 u32 i = 0;
526 struct card_direntry *entries = NULL;
527 struct card_dat *dirblock = NULL;
528 #ifdef _CARD_DEBUG
529 printf("__card_getfilenum(%p,%s,%s,%s)\n",card,filename,gamecode,company);
530 #endif
531 if(!card->attached) return CARD_ERROR_NOCARD;
532 dirblock = __card_getdirblock(card);
534 entries = dirblock->entries;
535 for(i=0;i<CARD_MAXFILES;i++) {
536 if(entries[i].gamecode[0]!=0xff) {
537 if(strnicmp((const char*)entries[i].filename,filename,strlen(filename))==0) {
538 if((gamecode && gamecode[0]!=0xff && memcmp(entries[i].gamecode,gamecode,4)!=0)
539 || (company && company[0]!=0xff && memcmp(entries[i].company,company,2)!=0)) continue;
541 *fileno = i;
542 break;
546 if(i>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
547 return CARD_ERROR_READY;
550 static s32 __card_seek(card_file *file,s32 len,s32 offset,card_block **rcard)
552 s32 ret;
553 s32 i,entry_len;
554 card_block *card = NULL;
555 struct card_direntry *entry = NULL;
556 struct card_dat *dirblock = NULL;
557 struct card_bat *fatblock = NULL;
558 #ifdef _CARD_DEBUG
559 printf("__card_seek(%d,%p,%d,%d)\n",file->filenum,file,len,offset);
560 #endif
561 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
562 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
563 #ifdef _CARD_DEBUG
564 printf("__card_seek(%d)\n",file->iblock);
565 #endif
566 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
567 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
568 return CARD_ERROR_FATAL_ERROR;
571 dirblock = __card_getdirblock(card);
572 entry = &dirblock->entries[file->filenum];
573 #ifdef _CARD_DEBUG
574 printf("__card_seek(%p,%d)\n",entry,file->filenum);
575 #endif
576 if(entry->gamecode[0]!=0xff) {
577 entry_len = entry->length*card->sector_size;
578 if(entry_len<offset || entry_len<(offset+len)) {
579 __card_putcntrlblock(card,CARD_ERROR_LIMIT);
580 return CARD_ERROR_LIMIT;
582 card->curr_file = file;
583 file->len = len;
585 if(offset<file->offset) {
586 file->offset = 0;
587 file->iblock = entry->block;
588 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
589 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
590 return CARD_ERROR_BROKEN;
594 fatblock = __card_getbatblock(card);
595 for(i=file->iblock;i<card->blocks && file->offset<(offset&~(card->sector_size-1));i=file->iblock) {
596 file->offset += card->sector_size;
597 file->iblock = fatblock->fat[i-CARD_SYSAREA];
598 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
599 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
600 return CARD_ERROR_BROKEN;
603 file->offset = offset;
604 *rcard = card;
606 return CARD_ERROR_READY;
609 static u32 __card_checkdir(card_block *card,u32 *currdir)
611 u32 dir,bad,bad_dir;
612 u16 chksum0,chksum1;
613 struct card_dircntrl *dircntrl[2];
614 struct card_dat *dirblock[2];
615 #ifdef _CARD_DEBUG
616 printf("__card_checkdir(%p,%p)\n",card,currdir);
617 #endif
618 dir = 0;
619 bad = 0;
620 bad_dir = 0;
621 while(dir<2) {
622 dirblock[dir] = card->workarea+((dir+1)<<13);
623 dircntrl[dir] = (card->workarea+((dir+1)<<13))+8128;
624 __card_checksum((u16*)dirblock[dir],0x1ffc,&chksum0,&chksum1);
625 if(chksum0!=dircntrl[dir]->chksum1 || chksum1!=dircntrl[dir]->chksum2) {
626 #ifdef _CARD_DEBUG
627 printf("__card_checkdir(bad checksums: (%04x : %04x),(%04x : %04x)\n",chksum0,dircntrl[dir]->chksum1,chksum1,dircntrl[dir]->chksum2);
628 #endif
629 card->curr_dir = NULL;
630 bad_dir = dir;
631 bad++;
633 dir++;
636 dir = bad_dir;
637 if(!bad) {
638 if(dircntrl[0]->updated<dircntrl[1]->updated) dir = 0;
639 else dir = 1;
641 if(card->curr_dir==NULL) {
642 card->curr_dir = dirblock[dir];
643 memcpy(dirblock[dir],dirblock[dir^1],8192);
645 else if(card->curr_dir==dirblock[0]) dir = 0;
646 else dir = 1;
648 if(currdir) *currdir = dir;
649 return bad;
652 static u32 __card_checkfat(card_block *card,u32 *currfat)
654 u32 fat,bad,bad_fat;
655 u16 chksum0,chksum1;
656 struct card_bat *fatblock[2];
657 #ifdef _CARD_DEBUG
658 printf("__card_checkfat(%p,%p)\n",card,currfat);
659 #endif
660 fat = 0;
661 bad = 0;
662 bad_fat = 0;
663 while(fat<2) {
664 fatblock[fat] = card->workarea+((fat+3)<<13);
665 __card_checksum((u16*)(((u32)fatblock[fat])+4),0x1ffc,&chksum0,&chksum1);
666 if(chksum0!=fatblock[fat]->chksum1 || chksum1!=fatblock[fat]->chksum2) {
667 #ifdef _CARD_DEBUG
668 printf("__card_checkfat(bad checksums: (%04x : %04x),(%04x : %04x)\n",chksum0,fatblock[fat]->chksum1,chksum1,fatblock[fat]->chksum2);
669 #endif
670 card->curr_fat = NULL;
671 bad_fat = fat;
672 bad++;
673 } else {
674 u16 curblock = CARD_SYSAREA;
675 u16 freeblocks = 0;
676 while(curblock<card->blocks) {
677 if(!fatblock[fat]->fat[curblock-CARD_SYSAREA]) freeblocks++;
678 curblock++;
680 if(freeblocks!=fatblock[fat]->freeblocks) {
681 #ifdef _CARD_DEBUG
682 printf("__card_checkfat(freeblocks!=fatblock[fat]->freeblocks (%d : %d))\n",freeblocks,fatblock[fat]->freeblocks);
683 #endif
684 card->curr_fat = NULL;
685 bad_fat = fat;
686 bad++;
689 fat++;
692 fat = bad_fat;
693 if(!bad) {
694 if(fatblock[0]->updated<fatblock[1]->updated) fat = 0;
695 else fat = 1;
697 if(card->curr_fat==NULL) {
698 card->curr_fat = fatblock[fat];
699 memcpy(fatblock[fat],fatblock[fat^1],8192);
701 else if(card->curr_fat==fatblock[0]) fat = 0;
702 else fat = 1;
704 if(currfat) *currfat = fat;
705 return bad;
708 static s32 __card_verify(card_block *card)
710 u32 ret = 0;
712 ret += __card_checkdir(card,NULL);
713 ret += __card_checkfat(card,NULL);
714 #ifdef _CARD_DEBUG
715 printf("__card_verify(%d)\n",ret);
716 #endif
717 if(ret<=2) {
718 if(card->curr_dir && card->curr_fat) return CARD_ERROR_READY;
720 return CARD_ERROR_BROKEN;
723 static u32 __card_iscard(u32 id)
725 u32 ret;
726 u32 idx,tmp,secsize;
728 if(id&~0xffff) return 0;
729 if(id&0x03) return 0;
731 ret = 0;
732 tmp = id&0xfc;
733 if(tmp==EXI_MEMCARD59 || tmp==EXI_MEMCARD123
734 || tmp==EXI_MEMCARD251 || tmp==EXI_MEMCARD507
735 || tmp==EXI_MEMCARD1019 || tmp==EXI_MEMCARD2043) {
736 idx = _ROTL(id,23)&0x1c;
737 if((secsize=card_sector_size[idx>>2])==0) return 0;
738 tmp = ((tmp<<20)&0x1FFE0000)/secsize;
739 if(tmp>8) ret = 1;
741 return ret;
744 static s32 __card_allocblock(s32 chn,u32 blocksneed,cardcallback callback)
746 s32 ret;
747 u16 block,currblock = 0,prevblock = 0;
748 u32 i,count;
749 card_block *card = NULL;
750 struct card_bat *fatblock = NULL;
751 #ifdef _CARD_DEBUG
752 printf("__card_allocblock(%d,%d,%p)\n",chn,blocksneed,callback);
753 #endif
754 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
755 card = &cardmap[chn];
757 if(!card->attached) return CARD_ERROR_NOCARD;
758 fatblock = __card_getbatblock(card);
759 #ifdef _CARD_DEBUG
760 printf("__card_allocblock(%p,%d)\n",fatblock,fatblock->freeblocks);
761 #endif
763 if(fatblock->freeblocks<blocksneed) return CARD_ERROR_INSSPACE;
765 // Add which blocks this file will take up into the FAT
766 count = 0;
767 block = 0xffff;
768 currblock = fatblock->lastalloc;
769 i = blocksneed;
770 while(1) {
771 if(i==0) {
772 // Done allocating blocks
773 #ifdef _CARD_DEBUG
774 printf("__card_allocblock(%d : %d)\n",block,currblock);
775 #endif
776 fatblock->freeblocks -= blocksneed;
777 fatblock->lastalloc = currblock;
778 card->curr_fileblock = block;
779 ret = __card_updatefat(chn,fatblock,callback);
780 break;
784 Since testing free space has already been done, if all the blocks
785 the file takes up cannot be entered into the FAT, something is
786 wrong.
788 count++;
789 if(count>=(card->blocks-CARD_SYSAREA)) return CARD_ERROR_BROKEN;
791 currblock++;
792 if(currblock<CARD_SYSAREA || currblock>=card->blocks) currblock = CARD_SYSAREA;
793 if(fatblock->fat[currblock-CARD_SYSAREA]==0) {
794 if(block!=0xffff)
795 fatblock->fat[prevblock-CARD_SYSAREA] = currblock;
796 else
797 block = currblock;
799 fatblock->fat[currblock-CARD_SYSAREA] = 0xffff;
800 prevblock = currblock;
801 i--;
804 return ret;
807 static s32 __card_freeblock(s32 chn,u16 block,cardcallback callback)
809 u16 next = 0xffff,prev = 0xffff;
810 card_block *card = NULL;
811 struct card_bat *fatblock = NULL;
812 #ifdef _CARD_DEBUG
813 printf("__card_freeblock(%d,%d,%p)\n",chn,block,callback);
814 #endif
815 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
816 card = &cardmap[chn];
818 if(!card->attached) return CARD_ERROR_NOCARD;
820 fatblock = __card_getbatblock(card);
821 next = fatblock->fat[block-CARD_SYSAREA];
822 while(1) {
823 if(next==0xffff) break;
824 if(next<CARD_SYSAREA || next>=card->blocks) return CARD_ERROR_BROKEN;
826 // Get the file's next block and clear the previous one from the fat
827 prev = next;
828 next = fatblock->fat[prev-CARD_SYSAREA];
829 fatblock->fat[prev-CARD_SYSAREA] = 0;
830 fatblock->freeblocks++;
832 return __card_updatefat(chn,fatblock,callback);
835 static s32 __card_unlockedhandler(s32 chn,s32 dev)
837 s32 ret;
838 cardcallback cb = NULL;
839 card_block *card = NULL;
841 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
842 card = &cardmap[chn];
844 ret = CARD_ERROR_READY;
845 cb = card->card_unlock_cb;
846 if(cb) {
847 card->card_unlock_cb = NULL;
848 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
849 cb(chn,ret);
851 return CARD_ERROR_UNLOCKED;
854 static s32 __card_readstatus(s32 chn,u8 *pstatus)
856 u8 val[2];
857 u32 err;
858 s32 ret;
860 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
861 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
863 err = 0;
864 val[0] = 0x83; val[1] = 0x00;
865 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
866 if(EXI_Sync(chn)==0) err |= 0x02;
867 if(EXI_Imm(chn,pstatus,1,EXI_READ,NULL)==0) err |= 0x04;
868 if(EXI_Sync(chn)==0) err |= 0x08;
869 if(EXI_Deselect(chn)==0) err |= 0x10;
871 if(err) ret = CARD_ERROR_NOCARD;
872 else ret = CARD_ERROR_READY;
873 #ifdef _CARD_DEBUG
874 printf("__card_readstatus(%d,%08x)\n",chn,*pstatus);
875 #endif
876 return ret;
879 static s32 __card_clearstatus(s32 chn)
881 u8 val;
882 u32 err;
883 s32 ret;
884 #ifdef _CARD_DEBUG
885 printf("__card_clearstatus(%d)\n",chn);
886 #endif
887 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
888 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
890 err = 0;
891 val = 0x89;
892 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
893 if(EXI_Sync(chn)==0) err |= 0x02;
894 if(EXI_Deselect(chn)==0) err |= 0x04;
896 if(err) ret = CARD_ERROR_NOCARD;
897 else ret = CARD_ERROR_READY;
899 return ret;
902 static s32 __card_sleep(s32 chn)
904 u8 val;
905 u32 err;
906 s32 ret;
907 #ifdef _CARD_DEBUG
908 printf("__card_sleep(%d)\n",chn);
909 #endif
910 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
911 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
913 err = 0;
914 val = 0x88;
915 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
916 if(EXI_Sync(chn)==0) err |= 0x02;
917 if(EXI_Deselect(chn)==0) err |= 0x04;
919 if(err) ret = CARD_ERROR_NOCARD;
920 else ret = CARD_ERROR_READY;
922 return ret;
925 static s32 __card_wake(s32 chn)
927 u8 val;
928 u32 err;
929 s32 ret;
930 #ifdef _CARD_DEBUG
931 printf("__card_wake(%d)\n",chn);
932 #endif
934 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
935 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
937 err = 0;
938 val = 0x87;
939 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
940 if(EXI_Sync(chn)==0) err |= 0x02;
941 if(EXI_Deselect(chn)==0) err |= 0x04;
943 if(err) ret = CARD_ERROR_NOCARD;
944 else ret = CARD_ERROR_READY;
946 return ret;
949 static s32 __card_enableinterrupt(s32 chn,u32 enable)
951 u8 val[2];
952 u32 err;
953 s32 ret;
954 #ifdef _CARD_DEBUG
955 printf("__card_enableinterrupt(%d,%d)\n",chn,enable);
956 #endif
958 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
959 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
961 err = 0;
962 val[0] = 0x81;
963 if(enable) val[1] = 0x01;
964 else val[1] = 0x00;
965 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
966 if(EXI_Sync(chn)==0) err |= 0x02;
967 if(EXI_Deselect(chn)==0) err |= 0x04;
969 if(err) ret = CARD_ERROR_BUSY;
970 else ret = CARD_ERROR_READY;
972 return ret;
975 static s32 __card_txhandler(s32 chn,s32 dev)
977 u32 err;
978 s32 ret = CARD_ERROR_READY;
979 cardcallback cb = NULL;
980 card_block *card = NULL;
981 #ifdef _CARD_DEBUG
982 printf("__card_txhandler(%d,%d)\n",chn,dev);
983 #endif
984 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
985 card = &cardmap[chn];
987 err = 0;
988 if(EXI_Deselect(chn)==0) ret |= err;
989 if(EXI_Unlock(chn)==0) ret |= err;
991 cb = card->card_tx_cb;
992 if(cb) {
993 card->card_tx_cb = NULL;
994 if(!err) {
995 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
996 } else ret = CARD_ERROR_NOCARD;
997 cb(chn,ret);
999 return 1;
1002 static void __timeouthandler(syswd_t alarm,void *cbarg)
1004 u32 chn;
1005 s32 ret = CARD_ERROR_READY;
1006 cardcallback cb;
1007 card_block *card = NULL;
1008 #ifdef _CARD_DEBUG
1009 printf("__timeouthandler(%p)\n",alarm);
1010 #endif
1011 chn = 0;
1012 while(chn<EXI_CHANNEL_2) {
1013 card = &cardmap[chn];
1014 if(card->timeout_svc==alarm) break;
1015 chn++;
1017 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1020 if(card->attached) {
1021 EXI_RegisterEXICallback(chn,NULL);
1022 cb = card->card_exi_cb;
1023 if(cb) {
1024 card->card_exi_cb = NULL;
1025 ret = CARD_ERROR_IOERROR;
1026 cb(chn,ret);
1031 static void __setuptimeout(card_block *card)
1033 struct timespec tb;
1034 #ifdef _CARD_DEBUG
1035 printf("__setuptimeout(%p)\n",&card->timeout_svc);
1036 #endif
1037 SYS_CancelAlarm(card->timeout_svc);
1039 if(card->cmd[0]==0xf1 || card->cmd[0]==0xf4) {
1040 #ifdef _CARD_DEBUG
1041 printf("__setuptimeout(%02x, %dsec)\n",card->cmd[0],1*(card->sector_size/8192));
1042 #endif
1043 tb.tv_sec = 1*(card->sector_size/8192);
1044 tb.tv_nsec = 0;
1045 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL);
1046 } else if(card->cmd[0]==0xf2) {
1047 #ifdef _CARD_DEBUG
1048 printf("__setuptimeout(0xf2, 100ms)\n");
1049 #endif
1050 tb.tv_sec = 0;
1051 tb.tv_nsec = 100*TB_NSPERMS;
1052 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL);
1056 static s32 __retry(s32 chn)
1058 u32 len;
1059 card_block *card = NULL;
1061 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1062 card = &cardmap[chn];
1063 #ifdef _CARD_DEBUG
1064 printf("__retry(%d)\n",chn);
1065 #endif
1066 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
1067 EXI_Unlock(chn);
1068 return CARD_ERROR_NOCARD;
1071 __setuptimeout(card);
1073 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
1074 EXI_Deselect(chn);
1075 EXI_Unlock(chn);
1076 return CARD_ERROR_NOCARD;
1079 if(card->cmd[0]==0x52) {
1080 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) {
1081 EXI_Deselect(chn);
1082 EXI_Unlock(chn);
1083 return CARD_ERROR_NOCARD;
1087 if(card->cmd_mode==-1) {
1088 EXI_Deselect(chn);
1089 EXI_Unlock(chn);
1090 return CARD_ERROR_READY;
1093 len = 128;
1094 if(card->cmd[0]==0x52) len = CARD_READSIZE;
1095 if(EXI_Dma(chn,card->cmd_usr_buf,len,card->cmd_mode,__card_txhandler)==0) {
1096 EXI_Deselect(chn);
1097 EXI_Unlock(chn);
1098 return CARD_ERROR_NOCARD;
1100 return CARD_ERROR_READY;
1103 static void __card_defaultapicallback(s32 chn,s32 result)
1105 #ifdef _CARD_DEBUG
1106 printf("__card_defaultapicallback(%d,%d)\n",chn,result);
1107 #endif
1108 return;
1111 static s32 __card_exihandler(s32 chn,s32 dev)
1113 u8 status;
1114 s32 ret = CARD_ERROR_READY;
1115 card_block *card = NULL;
1116 cardcallback cb;
1117 #ifdef _CARD_DEBUG
1118 printf("__card_exihandler(%d,%d)\n",chn,dev);
1119 #endif
1120 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 1;
1121 card = &cardmap[chn];
1123 SYS_CancelAlarm(card->timeout_svc);
1124 if(card->attached) {
1125 if(EXI_Lock(chn,EXI_DEVICE_0,NULL)==1) {
1126 if((ret=__card_readstatus(chn,&status))>=0
1127 && (ret=__card_clearstatus(chn))>=0) {
1128 if(status&0x18) ret = CARD_ERROR_IOERROR;
1129 else ret = CARD_ERROR_READY;
1131 if(ret==CARD_ERROR_IOERROR) {
1132 if((--card->cmd_retries)>0) {
1133 ret = __retry(chn);
1134 if(ret<0) goto exit;
1135 return 1;
1139 EXI_Unlock(chn);
1140 } else ret = CARD_ERROR_FATAL_ERROR;
1141 exit:
1142 cb = card->card_exi_cb;
1143 if(cb) {
1144 card->card_exi_cb = NULL;
1145 cb(chn,ret);
1148 return 1;
1151 static s32 __card_exthandler(s32 chn,s32 dev)
1153 cardcallback cb;
1154 card_block *card = NULL;
1155 #ifdef _CARD_DEBUG
1156 printf("__card_exthandler(%d,%d)\n",chn,dev);
1157 #endif
1158 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
1159 card = &cardmap[chn];
1161 if(card->attached) {
1162 if(card->card_tx_cb) {
1163 printf("error: card->card_tx_cb!=NULL\n");
1165 card->attached = 0;
1166 EXI_RegisterEXICallback(chn,NULL);
1167 SYS_CancelAlarm(card->timeout_svc);
1169 cb = card->card_exi_cb;
1170 if(cb) {
1171 card->card_exi_cb = NULL;
1172 cb(chn,CARD_ERROR_NOCARD);
1175 cb = card->card_ext_cb;
1176 if(cb) {
1177 card->card_ext_cb = NULL;
1178 cb(chn,CARD_ERROR_NOCARD);
1182 return 1;
1185 static void __write_callback(s32 chn,s32 result)
1187 s32 ret;
1188 cardcallback cb = NULL;
1189 card_file *file = NULL;
1190 struct card_bat *fatblock = NULL;
1191 struct card_dat *dirblock = NULL;
1192 struct card_direntry *entry = NULL;
1193 card_block *card = &cardmap[chn];
1194 #ifdef _CARD_DEBUG
1195 printf("__write_callback(%d,%d)\n",chn,result);
1196 #endif
1197 ret = result;
1198 if(ret>=0) {
1199 file = card->curr_file;
1200 if(file->len>=0) {
1201 file->len = (card->sector_size-file->len);
1202 if(file->len<=0) {
1203 dirblock = __card_getdirblock(card);
1204 entry = &dirblock->entries[file->filenum];
1205 entry->lastmodified = time(NULL);
1206 cb = card->card_api_cb;
1207 card->card_api_cb = NULL;
1208 if((ret=__card_updatedir(chn,cb))>=0) return;
1209 } else {
1210 fatblock = __card_getbatblock(card);
1211 file->offset += card->sector_size;
1212 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1213 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1214 ret = CARD_ERROR_BROKEN;
1215 goto exit;
1217 if((ret=__card_sectorerase(chn,(file->iblock*card->sector_size),__erase_callback))>=0) return;
1219 } else
1220 ret = CARD_ERROR_CANCELED;
1223 exit:
1224 cb = card->card_api_cb;
1225 card->card_api_cb = NULL;
1226 __card_putcntrlblock(card,ret);
1227 if(cb) cb(chn,ret);
1230 static void __erase_callback(s32 chn,s32 result)
1232 s32 ret;
1233 cardcallback cb = NULL;
1234 card_file *file = NULL;
1235 card_block *card = &cardmap[chn];
1236 #ifdef _CARD_DEBUG
1237 printf("__erase_callback(%d,%d)\n",chn,result);
1238 #endif
1239 ret = result;
1240 if(ret>=0) {
1241 file = card->curr_file;
1242 if((ret=__card_write(chn,(file->iblock*card->sector_size),card->sector_size,card->cmd_usr_buf,__write_callback))>=0) return;
1245 cb = card->card_api_cb;
1246 card->card_api_cb = NULL;
1247 __card_putcntrlblock(card,ret);
1248 if(cb) cb(chn,ret);
1251 static void __read_callback(s32 chn,s32 result)
1253 s32 ret;
1254 s32 len;
1255 cardcallback cb = NULL;
1256 card_file *file = NULL;
1257 card_block *card = 0;
1258 struct card_bat *fatblock = NULL;
1259 #ifdef _CARD_DEBUG
1260 printf("__read_callback(%d,%d)\n",chn,result);
1261 #endif
1262 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1263 card = &cardmap[chn];
1265 ret = result;
1266 file = card->curr_file;
1267 #ifdef _CARD_DEBUG
1268 printf("__read_callback(file->len = %d,file->iblock = %d)\n",file->len,file->iblock);
1269 #endif
1270 if(ret>=0) {
1271 if(file->len>=0) {
1272 file->len = file->len-(((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1273 #ifdef _CARD_DEBUG
1274 printf("__read_callback(file->len = %d)\n",file->len);
1275 #endif
1276 if(file->len>0) {
1277 fatblock = __card_getbatblock(card);
1278 file->offset += (((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1279 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1280 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1281 ret = CARD_ERROR_BROKEN;
1282 goto exit;
1284 len = file->len<card->sector_size?card->sector_size:file->len;
1285 if(__card_read(chn,(file->iblock*card->sector_size),len,card->cmd_usr_buf,__read_callback)>=0) return;
1288 } else
1289 ret = CARD_ERROR_CANCELED;
1292 exit:
1293 cb = card->card_api_cb;
1294 card->card_api_cb = NULL;
1295 __card_putcntrlblock(card,ret);
1296 if(cb) cb(chn,ret);
1299 static void __delete_callback(s32 chn,s32 result)
1301 s32 ret;
1302 cardcallback cb = NULL;
1303 card_block *card = &cardmap[chn];
1304 #ifdef _CARD_DEBUG
1305 printf("__delete_callback(%d,%d)\n",chn,result);
1306 #endif
1307 cb = card->card_api_cb;
1308 card->card_api_cb = NULL;
1310 ret = result;
1311 if(ret>=0 && (ret=__card_freeblock(chn,card->curr_fileblock,cb))>=0) return;
1313 __card_putcntrlblock(card,ret);
1314 if(cb) cb(chn,ret);
1317 static void __format_callback(s32 chn,s32 result)
1319 s32 ret;
1320 cardcallback cb = NULL;
1321 card_block *card = &cardmap[chn];
1323 ret = result;
1324 if(ret>=0) {
1325 if((++card->format_step)<CARD_SYSAREA) {
1326 if((ret=__card_sectorerase(chn,(card->format_step*card->sector_size),__format_callback))>=0) return;
1327 goto exit;
1329 if(card->format_step<10) {
1330 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;
1331 goto exit;
1334 card->curr_dir = card->workarea+CARD_SYSDIR;
1335 memcpy(card->curr_dir,card->workarea+CARD_SYSDIR_BACK,8192);
1337 card->curr_fat = card->workarea+CARD_SYSBAT;
1338 memcpy(card->curr_fat,card->workarea+CARD_SYSBAT_BACK,8192);
1340 exit:
1341 cb = card->card_api_cb;
1342 card->card_api_cb = NULL;
1343 __card_putcntrlblock(card,ret);
1344 if(cb) cb(chn,ret);
1347 static void __blockwritecallback(s32 chn,s32 result)
1349 s32 ret = CARD_ERROR_READY;
1350 cardcallback cb = NULL;
1351 card_block *card = &cardmap[chn];
1352 #ifdef _CARD_DEBUG
1353 printf("__blockwritecallback(%d,%d)\n",chn,result);
1354 #endif
1355 ret = result;
1356 if(ret>=0) {
1357 card->transfer_cnt += 128;
1358 card->cmd_sector_addr += 128;
1359 card->cmd_usr_buf += 128;
1360 if((--card->cmd_blck_cnt)>0) {
1361 if((ret=__card_writepage(chn,__blockwritecallback))>=CARD_ERROR_READY) return;
1365 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1367 cb = card->card_xfer_cb;
1368 if(cb) {
1369 card->card_xfer_cb = NULL;
1370 cb(chn,ret);
1374 static void __blockreadcallback(s32 chn,s32 result)
1376 s32 ret = CARD_ERROR_READY;
1377 cardcallback cb = NULL;
1378 card_block *card = &cardmap[chn];
1379 #ifdef _CARD_DEBUG
1380 printf("__blockreadcallback(%d,%d)\n",chn,result);
1381 #endif
1382 ret = result;
1383 if(ret>=0) {
1384 card->transfer_cnt += CARD_READSIZE;
1385 card->cmd_sector_addr += CARD_READSIZE;
1386 card->cmd_usr_buf += CARD_READSIZE;
1387 if((--card->cmd_blck_cnt)>0) {
1388 if((ret=__card_readsegment(chn,__blockreadcallback))>=CARD_ERROR_READY) return;
1392 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1393 cb = card->card_xfer_cb;
1394 if(cb) {
1395 card->card_xfer_cb = NULL;
1396 cb(chn,ret);
1400 static void __unlocked_callback(s32 chn,s32 result)
1402 s32 ret;
1403 card_block *card;
1404 cardcallback cb;
1405 #ifdef _CARD_DEBUG
1406 printf("__unlocked_callback(%d,%d)\n",chn,result);
1407 #endif
1408 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1409 card = &cardmap[chn];
1411 ret = result;
1412 if(ret>=0) {
1413 card->card_unlock_cb = __unlocked_callback;
1414 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==1) {
1415 card->card_unlock_cb = NULL;
1416 ret = __retry(chn);
1417 } else
1418 ret = 0;
1420 if(ret<0) {
1421 if(card->cmd[0]==0xf3 || card->cmd[0]>=0xf5) return;
1422 else if(card->cmd[0]==0x52) {
1423 cb = card->card_tx_cb;
1424 if(cb) {
1425 card->card_tx_cb = NULL;
1426 cb(chn,ret);
1428 } else if(card->cmd[0]>=0xf1) {
1429 cb = card->card_exi_cb;
1430 if(cb) {
1431 card->card_exi_cb = NULL;
1432 cb(chn,ret);
1438 static s32 __card_start(s32 chn,cardcallback tx_cb,cardcallback exi_cb)
1440 u32 level;
1441 card_block *card = NULL;
1442 #ifdef _CARD_DEBUG
1443 printf("__card_start(%d,%p,%p)\n",chn,tx_cb,exi_cb);
1444 #endif
1445 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1446 card = &cardmap[chn];
1448 _CPU_ISR_Disable(level);
1449 if(tx_cb) card->card_tx_cb = tx_cb;
1450 if(exi_cb) card->card_exi_cb = exi_cb;
1452 card->card_unlock_cb = __unlocked_callback;
1453 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) {
1454 _CPU_ISR_Restore(level);
1455 #ifdef _CARD_DEBUG
1456 printf("__card_start(done CARD_ERROR_BUSY)\n");
1457 #endif
1458 return CARD_ERROR_BUSY;
1460 card->card_unlock_cb = NULL;
1462 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
1463 EXI_Unlock(chn);
1464 _CPU_ISR_Restore(level);
1465 #ifdef _CARD_DEBUG
1466 printf("__card_start(done CARD_ERROR_NOCARD)\n");
1467 #endif
1468 return CARD_ERROR_NOCARD;
1471 __setuptimeout(card);
1472 _CPU_ISR_Restore(level);
1474 #ifdef _CARD_DEBUG
1475 printf("__card_start(done CARD_ERROR_READY)\n");
1476 #endif
1477 return CARD_ERROR_READY;
1480 static s32 __card_writepage(s32 chn,cardcallback callback)
1482 s32 ret;
1483 card_block *card = NULL;
1484 #ifdef _CARD_DEBUG
1485 printf("__card_writepage(%d,%p)\n",chn,callback);
1486 #endif
1487 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1488 card = &cardmap[chn];
1490 card->cmd[0] = 0xf2;
1491 card->cmd[1] = (card->cmd_sector_addr>>17)&0x3f;
1492 card->cmd[2] = (card->cmd_sector_addr>>9)&0xff;
1493 card->cmd[3] = (card->cmd_sector_addr>>7)&3;
1494 card->cmd[4] = card->cmd_sector_addr&0x7f;
1495 card->cmd_len = 5;
1496 card->cmd_mode = EXI_WRITE;
1497 card->cmd_retries = 3;
1499 ret = __card_start(chn,NULL,callback);
1500 if(ret<0) return ret;
1502 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==1
1503 && EXI_Dma(chn,card->cmd_usr_buf,128,card->cmd_mode,__card_txhandler)==1) return CARD_ERROR_READY;
1505 card->card_exi_cb = NULL;
1506 EXI_Deselect(chn);
1507 EXI_Unlock(chn);
1508 return CARD_ERROR_NOCARD;
1511 static s32 __card_readsegment(s32 chn,cardcallback callback)
1513 u32 err;
1514 s32 ret;
1515 card_block *card = NULL;
1516 #ifdef _CARD_DEBUG
1517 printf("__card_readsegment(%d,%p)\n",chn,callback);
1518 #endif
1519 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1520 card = &cardmap[chn];
1522 card->cmd[0] = 0x52;
1523 card->cmd[1] = (card->cmd_sector_addr&0xFE0000)>>17;
1524 card->cmd[2] = (card->cmd_sector_addr&0x01FE00)>>9;
1525 card->cmd[3] = (card->cmd_sector_addr&0x000180)>>7;
1526 card->cmd[4] = (card->cmd_sector_addr&0x00007F);
1527 card->cmd_len = 5;
1528 card->cmd_mode = EXI_READ;
1529 card->cmd_retries = 0;
1531 ret = __card_start(chn,callback,NULL);
1532 if(ret<0) return ret;
1534 err = 0;
1535 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) err |= 0x01;
1536 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
1537 if(EXI_Dma(chn,card->cmd_usr_buf,CARD_READSIZE,card->cmd_mode,__card_txhandler)==0) err |= 0x04;
1539 if(err) {
1540 card->card_tx_cb = NULL;
1541 EXI_Deselect(chn);
1542 EXI_Unlock(chn);
1543 return CARD_ERROR_NOCARD;
1545 return CARD_ERROR_READY;
1548 static void __card_fatwritecallback(s32 chn,s32 result)
1550 s32 ret;
1551 cardcallback cb = NULL;
1552 struct card_bat *fat1,*fat2;
1553 card_block *card = &cardmap[chn];
1554 #ifdef _CARD_DEBUG
1555 printf("__card_fatwritecallback(%d,%d)\n",chn,result);
1556 #endif
1557 ret = result;
1558 if(ret>=0) {
1559 fat1 = (card->workarea+0x6000);
1560 fat2 = (card->workarea+0x8000);
1561 if(card->curr_fat==fat1) {
1562 card->curr_fat = fat2;
1563 memcpy(fat2,fat1,8192);
1564 } else {
1565 card->curr_fat = fat1;
1566 memcpy(fat1,fat2,8192);
1569 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1570 #ifdef _CARD_DEBUG
1571 printf("__card_fatwritecallback(%p,%p)\n",card->card_api_cb,card->card_erase_cb);
1572 #endif
1573 cb = card->card_erase_cb;
1574 if(cb) {
1575 card->card_erase_cb = NULL;
1576 cb(chn,ret);
1580 static void __card_dirwritecallback(s32 chn,s32 result)
1582 s32 ret;
1583 cardcallback cb = NULL;
1584 struct card_dat *dir1,*dir2;
1585 card_block *card = &cardmap[chn];
1586 #ifdef _CARD_DEBUG
1587 printf("__card_dirwritecallback(%d,%d)\n",chn,result);
1588 #endif
1589 ret = result;
1590 if(ret>=0) {
1591 dir1 = (card->workarea+0x2000);
1592 dir2 = (card->workarea+0x4000);
1593 if(card->curr_dir==dir1) {
1594 card->curr_dir = dir2;
1595 memcpy(dir2,dir1,8192);
1596 } else {
1597 card->curr_dir = dir1;
1598 memcpy(dir1,dir2,8192);
1601 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1602 #ifdef _CARD_DEBUG
1603 printf("__card_dirwritecallback(%p,%p)\n",card->card_api_cb,card->card_erase_cb);
1604 #endif
1605 cb = card->card_erase_cb;
1606 if(cb) {
1607 card->card_erase_cb = NULL;
1608 cb(chn,ret);
1612 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1614 s32 ret;
1615 card_block *card = NULL;
1616 #ifdef _CARD_DEBUG
1617 printf("__card_write(%d,%08x,%d,%p,%p)\n",chn,address,block_len,buffer,callback);
1618 #endif
1619 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1620 card = &cardmap[chn];
1622 if(!card->attached) return CARD_ERROR_NOCARD;
1624 card->cmd_blck_cnt = block_len>>7;
1625 card->cmd_sector_addr = address;
1626 card->cmd_usr_buf = buffer;
1627 card->card_xfer_cb = callback;
1628 ret = __card_writepage(chn,__blockwritecallback);
1630 return ret;
1633 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1635 s32 ret;
1636 card_block *card = NULL;
1637 #ifdef _CARD_DEBUG
1638 printf("__card_read(%d,%08x,%d,%p,%p)\n",chn,address,block_len,buffer,callback);
1639 #endif
1640 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1641 card = &cardmap[chn];
1643 card->cmd_sector_addr = address;
1644 card->cmd_blck_cnt = block_len>>9;
1645 card->cmd_usr_buf = buffer;
1646 card->card_xfer_cb = callback;
1647 ret = __card_readsegment(chn,__blockreadcallback);
1649 return ret;
1652 static s32 __card_formatregion(s32 chn,u32 encode,cardcallback callback)
1654 s32 ret;
1655 u16 tmp;
1656 u32 cnt;
1657 u64 time;
1658 u64 rnd_val;
1659 void *workarea,*memblock;
1660 cardcallback cb = NULL;
1661 card_block *card = NULL;
1662 struct card_header *header;
1663 struct card_bat *fatblock = NULL;
1664 struct card_dircntrl *dircntrl = NULL;
1665 syssram *sram;
1666 syssramex *sramex;
1667 #ifdef _CARD_DEBUG
1668 printf("__card_formatregion(%d,%d,%p)\n",chn,encode,callback);
1669 #endif
1670 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1672 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
1674 header = workarea = card->workarea;
1675 memset(header,0xff,8192);
1677 tmp = _viReg[55];
1678 header->encoding = encode;
1680 sram = __SYS_LockSram();
1681 header->serial[5] = sram->counter_bias;
1682 header->serial[6] = sram->lang;
1683 __SYS_UnlockSram(0);
1685 cnt = 0;
1686 rnd_val = time = gettime();
1687 sramex = __SYS_LockSramEx();
1688 while(cnt<12) {
1689 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1690 ((u8*)header->serial)[cnt] = (sramex->flash_id[chn][cnt]+(u32)rnd_val);
1692 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1693 rnd_val &= (u64)0x0000000000007fff;
1695 cnt++;
1697 __SYS_UnlockSramEx(0);
1699 *(u64*)&(header->serial[3]) = time;
1700 header->serial[7] = tmp;
1701 header->device_id = 0;
1702 header->size = card->card_size;
1703 __card_checksum((u16*)header,508,&header->chksum1,&header->chksum2);
1705 cnt = 0;
1706 while(cnt<2) {
1707 memblock = workarea+((cnt+1)<<13);
1708 dircntrl = memblock+8128;
1709 memset(memblock,0xff,8192);
1710 __card_checksum(memblock,8188,&dircntrl->chksum1,&dircntrl->chksum2);
1711 cnt++;
1714 cnt = 0;
1715 while(cnt<2) {
1716 memblock = workarea+((cnt+3)<<13);
1717 fatblock = memblock;
1718 memset(memblock,0,8192);
1719 fatblock->updated = cnt;
1720 fatblock->freeblocks = card->blocks-CARD_SYSAREA;
1721 fatblock->lastalloc = 4;
1722 __card_checksum(memblock+4,8188,&fatblock->chksum1,&fatblock->chksum2);
1723 cnt++;
1726 cb = callback;
1727 if(!cb) cb = __card_defaultapicallback;
1728 card->card_api_cb = cb;
1730 DCStoreRange(card->workarea,0xA000);
1732 card->format_step = 0;
1733 if((ret=__card_sectorerase(chn,(card->sector_size*card->format_step),__format_callback))>=0) return ret;
1735 __card_putcntrlblock(card,ret);
1736 return ret;
1739 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback)
1741 s32 ret;
1742 card_block *card = NULL;
1743 #ifdef _CARD_DEBUG
1744 printf("__card_sectorerase(%d,%08x,%p)\n",chn,sector,callback);
1745 #endif
1746 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1747 card = &cardmap[chn];
1749 if(sector%card->sector_size) return CARD_ERROR_FATAL_ERROR;
1751 card->cmd[0] = 0xf1;
1752 card->cmd[1] = (sector>>17)&0x7f;
1753 card->cmd[2] = (sector>>9)&0xff;
1754 card->cmd_len = 3;
1755 card->cmd_mode = -1;
1756 card->cmd_retries = 3;
1758 ret = __card_start(chn,NULL,callback);
1759 if(ret<0) return ret;
1761 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
1762 card->card_exi_cb = NULL;
1763 return CARD_ERROR_NOCARD;
1766 EXI_Deselect(chn);
1767 EXI_Unlock(chn);
1768 return ret;
1771 static void __card_faterasecallback(s32 chn,s32 result)
1773 s32 ret;
1774 cardcallback cb = NULL;
1775 struct card_bat *fatblock = NULL;
1776 card_block *card = &cardmap[chn];
1777 #ifdef _CARD_DEBUG
1778 printf("__card_faterasecallback(%d,%d)\n",chn,result);
1779 #endif
1780 ret = result;
1781 if(ret>=0) {
1782 fatblock = __card_getbatblock(card);
1783 if((ret=__card_write(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,8192,fatblock,__card_fatwritecallback))>=0) return;
1785 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1787 cb = card->card_erase_cb;
1788 if(cb) {
1789 card->card_erase_cb = NULL;
1790 cb(chn,ret);
1794 static void __card_direrasecallback(s32 chn,s32 result)
1796 s32 ret;
1797 cardcallback cb = NULL;
1798 struct card_dat *dirblock = NULL;
1799 card_block *card = &cardmap[chn];
1800 #ifdef _CARD_DEBUG
1801 printf("__card_direrasecallback(%d,%d)\n",chn,result);
1802 #endif
1803 ret = result;
1804 if(ret>=0) {
1805 dirblock = __card_getdirblock(card);
1806 if((ret=__card_write(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,8192,dirblock,__card_dirwritecallback))>=0) return;
1808 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1810 cb = card->card_erase_cb;
1811 if(cb) {
1812 card->card_erase_cb = NULL;
1813 cb(chn,ret);
1817 static void __card_createfatcallback(s32 chn,s32 result)
1819 s32 ret;
1820 cardcallback cb = NULL;
1821 card_file *file = NULL;
1822 struct card_direntry *entry = NULL;
1823 struct card_dat *dirblock = NULL;
1824 card_block *card = &cardmap[chn];
1825 #ifdef _CARD_DEBUG
1826 printf("__card_createfatcallback(%d,%d)\n",chn,result);
1827 #endif
1828 cb = card->card_api_cb;
1829 card->card_api_cb = NULL;
1831 dirblock = __card_getdirblock(card);
1833 file = card->curr_file;
1834 entry = &dirblock->entries[file->filenum];
1836 memset(entry->gamecode,0,4);
1837 memset(entry->company,0,2);
1838 if(card_gamecode[0]!=0xff) memcpy(entry->gamecode,card_gamecode,4);
1839 if(card_gamecode[0]!=0xff) memcpy(entry->company,card_company,2);
1840 entry->block = card->curr_fileblock;
1841 entry->permission = CARD_ATTRIB_PUBLIC;
1842 entry->pad_00 = 0xff;
1843 entry->copytimes = 0;
1844 entry->iconaddr = -1;
1845 entry->iconfmt = 0;
1846 entry->iconspeed = 0;
1847 entry->pad_01 = 0xffff;
1848 entry->iconspeed = (entry->iconspeed&~CARD_SPEED_MASK)|CARD_SPEED_FAST;
1849 entry->lastmodified = time(NULL);
1851 file->offset = 0;
1852 file->iblock = card->curr_fileblock;
1854 if((ret=__card_updatedir(chn,cb))<0) {
1855 __card_putcntrlblock(card,ret);
1856 if(cb) cb(chn,ret);
1860 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback)
1862 card_block *card = NULL;
1863 #ifdef _CARD_DEBUG
1864 printf("__card_updatefat(%d,%p,%p)\n",chn,fatblock,callback);
1865 #endif
1866 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1867 card = &cardmap[chn];
1869 if(!card->attached) return CARD_ERROR_NOCARD;
1871 ++fatblock->updated;
1872 __card_checksum((u16*)(((u32)fatblock)+4),0x1ffc,&fatblock->chksum1,&fatblock->chksum2);
1873 DCStoreRange(fatblock,8192);
1874 card->card_erase_cb = callback;
1876 return __card_sectorerase(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,__card_faterasecallback);
1879 static s32 __card_updatedir(s32 chn,cardcallback callback)
1881 card_block *card = NULL;
1882 void *dirblock = NULL;
1883 struct card_dircntrl *dircntrl = NULL;
1884 #ifdef _CARD_DEBUG
1885 printf("__card_updatedir(%d,%p)\n",chn,callback);
1886 #endif
1887 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1888 card = &cardmap[chn];
1890 if(!card->attached) return CARD_ERROR_NOCARD;
1892 dirblock = __card_getdirblock(card);
1893 dircntrl = dirblock+8128;
1894 ++dircntrl->updated;
1895 __card_checksum((u16*)dirblock,0x1ffc,&dircntrl->chksum1,&dircntrl->chksum2);
1896 DCStoreRange(dirblock,0x2000);
1897 card->card_erase_cb = callback;
1899 return __card_sectorerase(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,__card_direrasecallback);
1902 static void __card_dounmount(s32 chn,s32 result)
1904 u32 level;
1905 card_block *card;
1907 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1908 card = &cardmap[chn];
1910 _CPU_ISR_Disable(level);
1911 if(card->attached) {
1912 card->attached = 0;
1913 card->mount_step = 0;
1914 card->result = result;
1915 EXI_RegisterEXICallback(chn,NULL);
1916 EXI_Detach(chn);
1917 SYS_CancelAlarm(card->timeout_svc);
1919 _CPU_ISR_Restore(level);
1922 static s32 __card_domount(s32 chn)
1924 u8 status,kval;
1925 s32 ret = CARD_ERROR_READY;
1926 u32 sum;
1927 u32 id,idx,cnt;
1928 card_block *card;
1929 syssramex *sramex;
1931 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1932 card = &cardmap[chn];
1933 #ifdef _CARD_DEBUG
1934 printf("__card_domount(%d,%d)\n",chn,card->mount_step);
1935 #endif
1936 if(card->mount_step==0) {
1937 ret = 0;
1938 id = 0;
1939 if(EXI_GetID(chn,EXI_DEVICE_0,&id)==0) ret = CARD_ERROR_NOCARD;
1940 else if(!__card_iscard(id)) ret = CARD_ERROR_WRONGDEVICE;
1942 if(ret<0) goto exit;
1943 card->cid = id;
1944 card->card_size = (id&0xfc);
1945 #ifdef _CARD_DEBUG
1946 printf("__card_domount(card_type = %08x,%08x,%08x)\n",card->card_size,card->cid,id);
1947 #endif
1948 if(card->card_size) {
1949 idx = _ROTL(id,23)&0x1c;
1950 card->sector_size = card_sector_size[idx>>2];
1951 card->blocks = ((card->card_size<<20)>>3)/card->sector_size;
1953 if(card->blocks>0x0008) {
1954 idx = _ROTL(id,26)&0x1c;
1955 card->latency = card_latency[idx>>2];
1957 if((ret=__card_clearstatus(chn))<0) goto exit;
1958 if((ret=__card_readstatus(chn,&status))<0) goto exit;
1960 if(EXI_Probe(chn)==0) {
1961 ret = CARD_ERROR_NOCARD;
1962 goto exit;
1964 if(!(status&CARD_STATUS_UNLOCKED)) {
1965 #ifdef _CARD_DEBUG
1966 printf("__card_domount(card locked)\n");
1967 #endif
1968 if((ret=__dounlock(chn,card->key))<0) goto exit;
1970 cnt = 0;
1971 sum = 0;
1972 sramex = __SYS_LockSramEx();
1973 while(cnt<12) {
1974 kval = ((u8*)card->key)[cnt];
1975 sramex->flash_id[chn][cnt] = kval;
1976 sum += kval;
1977 cnt++;
1979 sum = (sum^-1)&0xff;
1980 sramex->flashID_chksum[chn] = (sum<<8)|sum;
1981 __SYS_UnlockSramEx(1);
1982 return ret;
1984 card->mount_step = 1;
1986 cnt = 0;
1987 sum = 0;
1988 sramex = __SYS_LockSramEx();
1989 while(cnt<12) {
1990 sum += sramex->flash_id[chn][cnt];
1991 cnt++;
1993 cnt = sramex->flashID_chksum[chn];
1994 __SYS_UnlockSramEx(0);
1996 sum = (sum^-1)&0xff;
1997 sum |= (sum<<8);
1998 if(cnt!=sum) {
1999 ret = CARD_ERROR_IOERROR;
2000 goto exit;
2005 if(card->mount_step==1) {
2006 card->mount_step = 2;
2007 if((ret=__card_enableinterrupt(chn,1))<0) goto exit;
2008 EXI_RegisterEXICallback(chn,__card_exihandler);
2009 EXI_Unlock(chn);
2011 DCInvalidateRange(card->workarea,0xA000);
2014 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;
2015 return ret;
2017 exit:
2018 EXI_Unlock(chn);
2019 __card_dounmount(chn,ret);
2021 return ret;
2024 static void __card_mountcallback(s32 chn,s32 result)
2026 s32 ret;
2027 cardcallback cb;
2028 card_block *card = &cardmap[chn];
2030 ret = result;
2031 if(ret==CARD_ERROR_NOCARD || ret==CARD_ERROR_IOERROR) {
2032 __card_dounmount(chn,ret);
2033 __card_putcntrlblock(card,ret);
2034 }else if(ret==CARD_ERROR_UNLOCKED) {
2035 if((ret=__card_domount(chn))>=0) return;
2036 } else {
2037 if((++card->mount_step)<7) {
2038 if((ret=__card_domount(chn))>=0) return;
2039 } else {
2040 ret = __card_verify(card);
2041 __card_putcntrlblock(card,ret);
2045 cb = card->card_api_cb;
2046 card->card_api_cb = NULL;
2047 if(cb) cb(chn,ret);
2050 static __inline__ void __card_srand(u32 val)
2052 crand_next = val;
2055 static __inline__ u32 __card_rand()
2057 crand_next = (crand_next*0x41C64E6D)+12345;
2058 return _SHIFTR(crand_next,16,15);
2061 static u32 __card_initval()
2063 u32 ticks = gettick();
2065 __card_srand(ticks);
2066 return ((0x7FEC8000|__card_rand())&~0x00000fff);
2069 static u32 __card_dummylen()
2071 u32 ticks = gettick();
2072 u32 val = 0,cnt = 0,shift = 1;
2074 __card_srand(ticks);
2075 val = (__card_rand()&0x1f)+1;
2077 do {
2078 ticks = gettick();
2079 val = ticks<<shift;
2080 shift++;
2081 if(shift>16) shift = 1;
2082 __card_srand(val);
2083 val = (__card_rand()&0x1f)+1;
2084 cnt++;
2085 }while(val<4 && cnt<10);
2086 if(val<4) val = 4;
2088 return val;
2092 static u32 exnor_1st(u32 a,u32 b)
2094 u32 c,d,e,f,r1,r2,r3,r4;
2096 c = 0;
2097 while(c<b) {
2098 d = (a>>23);
2099 e = (a>>15);
2100 f = (a>>7);
2101 r1 = (a^f);
2102 r2 = (e^r1);
2103 r3 = ~(d^r2); //eqv(d,r2)
2104 e = (a>>1);
2105 r4 = ((r3<<30)&0x40000000);
2106 a = (e|r4);
2107 c++;
2109 return a;
2112 static u32 exnor(u32 a,u32 b)
2114 u32 c,d,e,f,r1,r2,r3,r4;
2116 c = 0;
2117 while(c<b) {
2118 d = (a<<23);
2119 e = (a<<15);
2120 f = (a<<7);
2121 r1 = (a^f);
2122 r2 = (e^r1);
2123 r3 = ~(d^r2); //eqv(d,r2)
2124 e = (a<<1);
2125 r4 = ((r3>>30)&0x02);
2126 a = (e|r4);
2127 c++;
2129 return a;
2132 static u32 bitrev(u32 val)
2134 u32 cnt,val1,ret,shift,shift1;
2136 cnt = 0;
2137 ret = 0;
2138 shift = 1;
2139 shift1 = 0;
2140 while(cnt<32) {
2141 if(cnt<=15) {
2142 val1 = val&(1<<cnt);
2143 val1 <<= ((31-cnt)-shift1);
2144 ret |= val1;
2145 shift1++;
2146 } else if(cnt==31) {
2147 val1 = val>>31;
2148 ret |= val1;
2149 } else {
2150 val1 = 1;
2151 val1 = val&(1<<cnt);
2152 val1 >>= shift;
2153 ret |= val1;
2154 shift += 2;
2156 cnt++;
2158 return ret;
2161 static s32 __card_readarrayunlock(s32 chn,u32 address,void *buffer,u32 len,u32 flag)
2163 s32 ret;
2164 u32 err;
2165 u8 regbuf[5];
2166 card_block *card = &cardmap[chn];
2167 #ifdef _CARD_DEBUG
2168 printf("__card_readarrayunlock(%d,%d,%p,%d,%d)\n",chn,address,buffer,len,flag);
2169 #endif
2170 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
2172 address &= 0xFFFFF000;
2173 memset(regbuf,0,5);
2175 regbuf[0] = 0x52;
2176 if(!flag) {
2177 regbuf[1] = ((address&0x60000000)>>29)&0xff;
2178 regbuf[2] = ((address&0x1FE00000)>>21)&0xff;
2179 regbuf[3] = ((address&0x00180000)>>19)&0xff;
2180 regbuf[4] = ((address&0x0007F000)>>12)&0xff;
2181 } else {
2182 regbuf[1] = (address>>24)&0xff;
2183 regbuf[2] = ((address&0x00FF0000)>>16)&0xff;
2186 err = 0;
2187 if(EXI_ImmEx(chn,regbuf,5,EXI_WRITE)==0) err |= 0x01;
2188 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
2189 if(EXI_ImmEx(chn,buffer,len,EXI_READ)==0) err |= 0x04;
2190 if(EXI_Deselect(chn)==0) err |= 0x08;
2192 if(err) ret = CARD_ERROR_NOCARD;
2193 else ret = CARD_ERROR_READY;
2195 return ret;
2198 static void __dsp_initcallback(dsptask_t *task)
2200 u32 chn;
2201 card_block *card = NULL;
2202 #ifdef _CARD_DEBUG
2203 printf("__dsp_initcallback(%p)\n",task);
2204 #endif
2205 chn = 0;
2206 while(chn<EXI_CHANNEL_2) {
2207 card = &cardmap[chn];
2208 if(&card->dsp_task==task) break;
2209 chn++;
2211 if(chn>=EXI_CHANNEL_2) return;
2213 DSP_SendMailTo(0xFF000000);
2214 while(DSP_CheckMailTo());
2215 DSP_SendMailTo((u32)card->workarea);
2216 while(DSP_CheckMailTo());
2219 static u8 tmp_buffer[64] ATTRIBUTE_ALIGN(32);
2220 static void __dsp_donecallback(dsptask_t *task)
2223 u8 status;
2224 s32 ret;
2225 u32 chn,len,key;
2226 u32 workarea,val;
2227 card_block *card = NULL;
2228 #ifdef _CARD_DEBUG
2229 printf("__dsp_donecallback(%p)\n",task);
2230 #endif
2231 chn = 0;
2232 while(chn<EXI_CHANNEL_2) {
2233 card = &cardmap[chn];
2234 if(&card->dsp_task==task) break;
2235 chn++;
2237 if(chn>=EXI_CHANNEL_2) return;
2239 workarea = (u32)card->workarea;
2240 workarea = ((workarea+47)&~0x1f);
2241 key = ((u32*)workarea)[8];
2243 val = (key^card->cipher)&~0xffff;
2244 len = __card_dummylen();
2245 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
2246 EXI_Unlock(chn);
2247 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2248 return;
2251 val = exnor(card->cipher,((len+card->latency+4)<<3)+1);
2253 u32 a,b,c,r1,r2,r3;
2254 a = (val<<23);
2255 b = (val<<15);
2256 c = (val<<7);
2257 r1 = (val^c);
2258 r2 = (b^r1);
2259 r3 = ~(a^r2); //eqv(a,r2)
2260 r1 = (val|(r3>>31));
2261 card->cipher = r1;
2264 val = ((key<<16)^card->cipher)&~0xffff;
2265 len = __card_dummylen();
2266 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
2267 EXI_Unlock(chn);
2268 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2269 return;
2272 ret = __card_readstatus(chn,&status);
2273 if(EXI_Probe(chn)==0) {
2274 EXI_Unlock(chn);
2275 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2276 return;
2278 if(!ret && !(status&CARD_STATUS_UNLOCKED)) {
2279 EXI_Unlock(chn);
2280 ret = CARD_ERROR_IOERROR;
2282 __card_mountcallback(chn,ret);
2285 static s32 __dounlock(s32 chn,u32 *key)
2287 s32 ret;
2288 u32 array_addr,len,val;
2289 u32 a,b,c,d,e;
2290 card_block *card = &cardmap[chn];
2291 u32 *workarea = card->workarea;
2292 u32 *cipher1 = (u32*)(((u32)card->workarea+47)&~31);
2293 u32 *cipher2 = &cipher1[8];
2294 #ifdef _CARD_DEBUG
2295 printf("__dounlock(%d,%p)\n",chn,key);
2296 #endif
2297 array_addr = __card_initval();
2298 len = __card_dummylen();
2300 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len,0)<0) return CARD_ERROR_NOCARD;
2302 ret = 0;
2303 val = exnor_1st(array_addr,(len<<3)+1);
2305 u32 a,b,c,r1,r2,r3;
2306 a = (val>>23);
2307 b = (val>>15);
2308 c = (val>>7);
2309 r1 = (val^c);
2310 r2 = (b^r1);
2311 r3 = ~(a^r2); //eqv(a,r2)
2312 r1 = (val|(r3<<31));
2313 card->cipher = r1;
2315 card->cipher = bitrev(card->cipher);
2317 array_addr = 0;
2318 len = __card_dummylen();
2319 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len+20,1)<0) return CARD_ERROR_NOCARD;
2321 a = ((u32*)tmp_buffer)[0];
2322 b = ((u32*)tmp_buffer)[1];
2323 c = ((u32*)tmp_buffer)[2];
2324 d = ((u32*)tmp_buffer)[3];
2325 e = ((u32*)tmp_buffer)[4];
2327 a = a^card->cipher;
2328 val = exnor(card->cipher,32);
2330 u32 a,b,c,r1,r2,r3;
2331 a = (val<<23);
2332 b = (val<<15);
2333 c = (val<<7);
2334 r1 = (val^c);
2335 r2 = (b^r1);
2336 r3 = ~(a^r2); //eqv(a,r2)
2337 r1 = (val|(r3>>31));
2338 card->cipher = r1;
2341 b = b^card->cipher;
2342 val = exnor(card->cipher,32);
2344 u32 a,b,c,r1,r2,r3;
2345 a = (val<<23);
2346 b = (val<<15);
2347 c = (val<<7);
2348 r1 = (val^c);
2349 r2 = (b^r1);
2350 r3 = ~(a^r2); //eqv(a,r2)
2351 r1 = (val|(r3>>31));
2352 card->cipher = r1;
2355 c = c^card->cipher;
2356 val = exnor(card->cipher,32);
2358 u32 a,b,c,r1,r2,r3;
2359 a = (val<<23);
2360 b = (val<<15);
2361 c = (val<<7);
2362 r1 = (val^c);
2363 r2 = (b^r1);
2364 r3 = ~(a^r2); //eqv(a,r2)
2365 r1 = (val|(r3>>31));
2366 card->cipher = r1;
2369 d = d^card->cipher;
2370 val = exnor(card->cipher,32);
2372 u32 a,b,c,r1,r2,r3;
2373 a = (val<<23);
2374 b = (val<<15);
2375 c = (val<<7);
2376 r1 = (val^c);
2377 r2 = (b^r1);
2378 r3 = ~(a^r2); //eqv(a,r2)
2379 r1 = (val|(r3>>31));
2380 card->cipher = r1;
2383 e = e^card->cipher;
2384 val = exnor(card->cipher,(len<<3));
2386 u32 a,b,c,r1,r2,r3;
2387 a = (val<<23);
2388 b = (val<<15);
2389 c = (val<<7);
2390 r1 = (val^c);
2391 r2 = (b^r1);
2392 r3 = ~(a^r2); //eqv(a,r2)
2393 r1 = (val|(r3>>31));
2394 card->cipher = r1;
2397 val = exnor(card->cipher,33);
2399 u32 a,b,c,r1,r2,r3;
2400 a = (val<<23);
2401 b = (val<<15);
2402 c = (val<<7);
2403 r1 = (val^c);
2404 r2 = (b^r1);
2405 r3 = ~(a^r2); //eqv(a,r2)
2406 r1 = (val|(r3>>31));
2407 card->cipher = r1;
2410 cipher1[0] = d;
2411 cipher1[1] = e;
2412 workarea[0] = (u32)cipher1;
2413 workarea[1] = 8;
2414 workarea[2] = 0;
2415 workarea[3] = (u32)cipher2;
2416 DCFlushRange(cipher1,8);
2417 DCInvalidateRange(cipher2,4);
2418 DCFlushRange(workarea,16);
2420 card->dsp_task.prio = 255;
2421 card->dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(_cardunlockdata);
2422 card->dsp_task.iram_len = 352;
2423 card->dsp_task.iram_addr = 0x0000;
2424 card->dsp_task.init_vec = 16;
2425 card->dsp_task.res_cb = NULL;
2426 card->dsp_task.req_cb = NULL;
2427 card->dsp_task.init_cb = __dsp_initcallback;
2428 card->dsp_task.done_cb = __dsp_donecallback;
2429 DSP_AddTask(&card->dsp_task);
2431 key[0] = a;
2432 key[1] = b;
2433 key[2] = c;
2435 return CARD_ERROR_READY;
2438 s32 CARD_Init(const char *gamecode,const char *company)
2440 u32 i,level;
2442 if(card_inited) return CARD_ERROR_READY;
2443 #ifdef _CARD_DEBUG
2444 printf("CARD_Init(%s,%s,%d)\n",gamecode,company);
2445 #endif
2446 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4);
2447 if(company && strlen(company)<=2) memcpy(card_company,company,2);
2449 _CPU_ISR_Disable(level);
2450 DSP_Init();
2452 memset(cardmap,0,sizeof(card_block)*2);
2453 for(i=0;i<2;i++) {
2454 cardmap[i].result = CARD_ERROR_NOCARD;
2455 LWP_InitQueue(&cardmap[i].wait_sync_queue);
2456 SYS_CreateAlarm(&cardmap[i].timeout_svc);
2458 SYS_RegisterResetFunc(&card_resetinfo);
2459 card_inited = 1;
2460 _CPU_ISR_Restore(level);
2461 return CARD_ERROR_READY;
2464 s32 CARD_Probe(s32 chn)
2466 return EXI_Probe(chn);
2469 s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size)
2471 s32 ret;
2472 u32 level,card_id;
2473 card_block *card = NULL;
2474 #ifdef _CARD_DEBUG
2475 printf("CARD_ProbeEx(%d,%p,%p)\n",chn,mem_size,sect_size);
2476 #endif
2477 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2478 card = &cardmap[chn];
2480 _CPU_ISR_Disable(level);
2481 ret = EXI_ProbeEx(chn);
2482 if(ret<=0) {
2483 if(!ret) ret = CARD_ERROR_BUSY;
2484 else ret = CARD_ERROR_NOCARD;
2485 _CPU_ISR_Restore(level);
2486 return ret;
2489 if(card->attached) {
2490 if(card->mount_step<1) {
2491 _CPU_ISR_Restore(level);
2492 return CARD_ERROR_BUSY;
2494 if(mem_size) *mem_size = card->card_size;
2495 if(sect_size) *sect_size = card->sector_size;
2497 _CPU_ISR_Restore(level);
2498 return CARD_ERROR_READY;
2501 if(EXI_GetState(chn)&EXI_FLAG_ATTACH) ret = CARD_ERROR_WRONGDEVICE;
2502 else {
2503 ret = CARD_ERROR_BUSY;
2504 if(EXI_GetID(chn,EXI_DEVICE_0,&card_id)) {
2505 if(!__card_iscard(card_id)) ret = CARD_ERROR_WRONGDEVICE;
2506 else {
2507 if(mem_size) *mem_size = card_id&0xFC;
2508 if(sect_size) {
2509 u32 idx = _ROTL(card_id,23)&0x1c;
2510 *sect_size = card_sector_size[idx>>2];
2512 ret = CARD_ERROR_READY;
2517 _CPU_ISR_Restore(level);
2518 return ret;
2521 s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb)
2523 s32 ret = CARD_ERROR_READY;
2524 u32 level;
2525 cardcallback attachcb = NULL;
2526 card_block *card = NULL;
2527 #ifdef _CARD_DEBUG
2528 printf("CARD_MountAsync(%d,%p,%p,%p)\n",chn,workarea,detach_cb,attach_cb);
2529 #endif
2530 if(!workarea) return CARD_ERROR_NOCARD;
2531 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2532 card = &cardmap[chn];
2534 _CPU_ISR_Disable(level);
2535 #ifdef _CARD_DEBUG
2536 printf("card->attached = %d,%08x\n",card->attached,EXI_GetState(chn));
2537 #endif
2538 if(card->result==CARD_ERROR_BUSY) {
2539 _CPU_ISR_Restore(level);
2540 return CARD_ERROR_BUSY;
2542 if(card->attached || !(EXI_GetState(chn)&EXI_FLAG_ATTACH)) {
2543 card->result = CARD_ERROR_BUSY;
2544 card->workarea = workarea;
2545 card->card_ext_cb = detach_cb;
2547 attachcb = attach_cb;
2548 if(!attachcb) attachcb = __card_defaultapicallback;
2549 card->card_api_cb = attachcb;
2550 card->card_exi_cb = NULL;
2552 if(!card->attached) {
2553 if(EXI_Attach(chn,__card_exthandler)==0) {
2554 card->result = CARD_ERROR_NOCARD;
2555 #ifdef _CARD_DEBUG
2556 printf("card->attached = %d,%08x,attach failed\n",card->attached,EXI_GetState(chn));
2557 #endif
2558 _CPU_ISR_Restore(level);
2559 return CARD_ERROR_NOCARD;
2562 card->mount_step = 0;
2563 card->attached = 1;
2564 #ifdef _CARD_DEBUG
2565 printf("card->attached = %d,%08x\n",card->attached,EXI_GetState(chn));
2566 #endif
2567 EXI_RegisterEXICallback(chn,NULL);
2568 SYS_CancelAlarm(card->timeout_svc);
2569 card->curr_dir = NULL;
2570 card->curr_fat = NULL;
2571 _CPU_ISR_Restore(level);
2573 card->card_unlock_cb = __card_mountcallback;
2574 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) return 0;
2576 card->card_unlock_cb = NULL;
2577 __card_domount(chn);
2578 return 1;
2581 ret = CARD_ERROR_WRONGDEVICE;
2582 _CPU_ISR_Restore(level);
2583 return ret;
2586 s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb)
2588 s32 ret;
2589 #ifdef _CARD_DEBUG
2590 printf("CARD_Mount(%d,%p,%p)\n",chn,workarea,detach_cb);
2591 #endif
2592 if((ret=CARD_MountAsync(chn,workarea,detach_cb,__card_synccallback))>=0) {
2593 ret = __card_sync(chn);
2595 return ret;
2598 s32 CARD_Unmount(s32 chn)
2600 s32 ret;
2601 card_block *card = NULL;
2603 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2605 if((ret=__card_getcntrlblock(chn,&card))<0) ret = CARD_ERROR_NOCARD;
2607 __card_dounmount(chn,ret);
2608 return CARD_ERROR_READY;
2611 s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2613 s32 ret;
2614 cardcallback cb = NULL;
2615 struct card_dat *dirblock = NULL;
2616 card_block *card = NULL;
2618 if(len<=0 || (len&0x1ff) || (offset>0 && (offset&0x1ff))) return CARD_ERROR_FATAL_ERROR;
2619 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2621 dirblock = __card_getdirblock(card);
2622 DCInvalidateRange(buffer,len);
2624 cb = callback;
2625 if(!cb) cb = __card_defaultapicallback;
2626 card->card_api_cb = cb;
2628 if(len>=(card->sector_size-(file->offset&(card->sector_size-1)))) len = (card->sector_size-(file->offset&(card->sector_size-1)));
2630 if((ret=__card_read(file->chn,(file->iblock*card->sector_size),len,buffer,__read_callback))<0) {
2631 __card_putcntrlblock(card,ret);
2632 return ret;
2634 return 0;
2637 s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset)
2639 s32 ret;
2641 if((ret=CARD_ReadAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2642 ret = __card_sync(file->chn);
2644 return ret;
2647 s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2649 s32 ret;
2650 cardcallback cb = NULL;
2651 card_block *card = NULL;
2653 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2654 if(len<0 || (len&(card->sector_size-1)) || (offset>0 && offset&(card->sector_size-1))) {
2655 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
2656 return CARD_ERROR_FATAL_ERROR;
2659 DCStoreRange(buffer,len);
2660 cb = callback;
2661 if(!cb) cb = __card_defaultapicallback;
2662 card->card_api_cb = cb;
2664 card->cmd_usr_buf = buffer;
2665 if((ret=__card_sectorerase(file->chn,(file->iblock*card->sector_size),__erase_callback))>=0) return ret;
2666 __card_putcntrlblock(card,ret);
2667 return ret;
2670 s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset)
2672 s32 ret;
2674 if((ret=CARD_WriteAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2675 ret = __card_sync(file->chn);
2677 return ret;
2680 s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback)
2682 u32 i,len;
2683 s32 ret,filenum;
2684 cardcallback cb = NULL;
2685 card_block *card = NULL;
2686 struct card_bat *fatblock = NULL;
2687 struct card_dat *dirblock = NULL;
2688 struct card_direntry *entry = NULL;
2689 #ifdef _CARD_DEBUG
2690 printf("CARD_CreateAsync(%d,%s,%d,%p,%p)\n",chn,filename,size,file,callback);
2691 #endif
2692 len = strlen(filename);
2693 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2695 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2696 if(size<=0 || size%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2698 dirblock = __card_getdirblock(card);
2700 filenum = -1;
2701 entry = dirblock->entries;
2702 for(i=0;i<CARD_MAXFILES;i++) {
2703 if(entry[i].gamecode[0]==0xff) {
2704 if(filenum==-1) filenum = i;
2705 } else if(memcmp(entry[i].filename,filename,len)==0) {
2706 if((card_gamecode[0]==0xff || card_company[0]==0xff)
2707 || ((card_gamecode[0]!=0xff && memcmp(entry[i].gamecode,card_gamecode,4)==0)
2708 && (card_company[0]!=0xff && memcmp(entry[i].company,card_company,2)==0))) {
2709 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2710 return CARD_ERROR_EXIST;
2714 if(filenum==-1) {
2715 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2716 return CARD_ERROR_NOENT;
2719 fatblock = __card_getbatblock(card);
2720 if((fatblock->freeblocks*card->sector_size)<size) {
2721 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2722 return CARD_ERROR_INSSPACE;
2725 cb = callback;
2726 if(!cb) cb = __card_defaultapicallback;
2727 card->card_api_cb = cb;
2729 entry[filenum].length = size/card->sector_size;
2730 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2731 memcpy(entry[filenum].filename,filename,len+1);
2733 card->curr_file = file;
2734 file->chn = chn;
2735 file->filenum = filenum;
2736 if((ret=__card_allocblock(chn,(size/card->sector_size),__card_createfatcallback))<0) {
2737 __card_putcntrlblock(card,ret);
2738 return ret;
2741 return 0;
2744 s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file)
2746 s32 ret;
2748 if((ret=CARD_CreateAsync(chn,filename,size,file,__card_synccallback))>=0) {
2749 ret = __card_sync(chn);
2751 return ret;
2754 s32 CARD_CreateEntryAsync(s32 chn,card_dir *direntry,card_file *file,cardcallback callback)
2756 u32 i,len;
2757 s32 ret,filenum;
2758 cardcallback cb = NULL;
2759 card_block *card = NULL;
2760 struct card_bat *fatblock = NULL;
2761 struct card_dat *dirblock = NULL;
2762 struct card_direntry *entry = NULL;
2763 #ifdef _CARD_DEBUG
2764 printf("CARD_CreateEntryAsync(%d,%p,%p,%p)\n",chn,direntry,file,callback);
2765 #endif
2766 len = strlen((const char*)direntry->filename);
2767 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2769 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2770 if(direntry->filelen<=0 || direntry->filelen%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2772 dirblock = __card_getdirblock(card);
2774 filenum = -1;
2775 entry = dirblock->entries;
2776 for(i=0;i<CARD_MAXFILES;i++) {
2777 if(entry[i].gamecode[0]==0xff) {
2778 if(filenum==-1) filenum = i;
2779 } else if(memcmp(entry[i].filename,direntry->filename,len)==0) {
2780 if((entry->gamecode[0]==0xff || entry->company[0]==0xff)
2781 || ((entry->gamecode[0]!=0xff && memcmp(entry[i].gamecode,entry->gamecode,4)==0)
2782 && (entry->company[0]!=0xff && memcmp(entry[i].company,entry->company,2)==0))) {
2783 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2784 return CARD_ERROR_EXIST;
2788 if(filenum==-1) {
2789 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2790 return CARD_ERROR_NOENT;
2793 fatblock = __card_getbatblock(card);
2794 if((fatblock->freeblocks*card->sector_size)<direntry->filelen) {
2795 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2796 return CARD_ERROR_INSSPACE;
2799 cb = callback;
2800 if(!cb) cb = __card_defaultapicallback;
2801 card->card_api_cb = cb;
2803 entry[filenum].length = direntry->filelen/card->sector_size;
2804 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2805 memcpy(entry[filenum].filename,direntry->filename,len+1);
2807 card->curr_file = file;
2808 file->chn = chn;
2809 file->filenum = filenum;
2810 if((ret=__card_allocblock(chn,(direntry->filelen/card->sector_size),__card_createfatcallback))<0) {
2811 __card_putcntrlblock(card,ret);
2812 return ret;
2815 return 0;
2818 s32 CARD_CreateEntry(s32 chn,card_dir *direntry,card_file *file)
2820 s32 ret;
2822 if((ret=CARD_CreateEntryAsync(chn,direntry,file,__card_synccallback))>=0) {
2823 ret = __card_sync(chn);
2825 return ret;
2828 s32 CARD_Open(s32 chn,const char *filename,card_file *file)
2830 s32 ret,fileno;
2831 struct card_dat *dirblock = NULL;
2832 card_block *card = NULL;
2834 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2836 file->filenum = -1;
2837 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2838 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2839 __card_putcntrlblock(card,ret);
2840 return ret;
2842 dirblock = __card_getdirblock(card);
2843 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2844 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2845 return CARD_ERROR_BROKEN;
2847 file->chn = chn;
2848 file->filenum = 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_OpenEntry(s32 chn,card_dir *entry,card_file *file)
2859 s32 ret,fileno;
2860 struct card_dat *dirblock = NULL;
2861 card_block *card = NULL;
2863 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2865 file->filenum = -1;
2866 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2867 if((ret=__card_getfilenum(card,(const char*)entry->filename,(const char*)entry->gamecode,(const char*)entry->company,&fileno))<0) {
2868 __card_putcntrlblock(card,ret);
2869 return ret;
2872 dirblock = __card_getdirblock(card);
2873 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2874 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2875 return CARD_ERROR_BROKEN;
2878 file->chn = chn;
2879 file->filenum = entry->fileno;
2880 file->offset = 0;
2881 file->len = dirblock->entries[fileno].length*card->sector_size;
2882 file->iblock = dirblock->entries[fileno].block;
2884 __card_putcntrlblock(card,CARD_ERROR_READY);
2885 return CARD_ERROR_READY;
2888 s32 CARD_Close(card_file *file)
2890 s32 ret;
2891 card_block *card = NULL;
2893 if(file->chn<EXI_CHANNEL_0 || file->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2894 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
2895 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
2897 file->chn = -1;
2898 __card_putcntrlblock(card,CARD_ERROR_READY);
2899 return CARD_ERROR_READY;
2902 s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback)
2904 s32 ret,fileno;
2905 cardcallback cb = NULL;
2906 card_block *card = NULL;
2907 struct card_dat *dirblock = NULL;
2908 struct card_direntry *entry = NULL;
2909 #ifdef _CARD_DEBUG
2910 printf("CARD_DeleteAsync(%d,%s,%p)\n",chn,filename,callback);
2911 #endif
2912 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2913 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2914 __card_putcntrlblock(card,ret);
2915 return ret;
2918 dirblock = __card_getdirblock(card);
2919 entry = &dirblock->entries[fileno];
2921 card->curr_fileblock = entry->block;
2922 memset(entry,-1,sizeof(struct card_direntry));
2924 cb = callback;
2925 if(!cb) cb = __card_defaultapicallback;
2926 card->card_api_cb = cb;
2928 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2930 __card_putcntrlblock(card,ret);
2931 return ret;
2934 s32 CARD_Delete(s32 chn,const char *filename)
2936 s32 ret;
2937 #ifdef _CARD_DEBUG
2938 printf("CARD_Delete(%d,%s)\n",chn,filename);
2939 #endif
2940 if((ret=CARD_DeleteAsync(chn,filename,__card_synccallback))>=0) {
2941 ret = __card_sync(chn);
2943 return ret;
2946 s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback)
2948 s32 ret;
2949 cardcallback cb = NULL;
2950 card_block *card = NULL;
2951 struct card_dat *dirblock = NULL;
2952 struct card_direntry *entry = NULL;
2953 #ifdef _CARD_DEBUG
2954 printf("CARD_DeleteEntryAsync(%p,%p)\n",dir_entry,callback);
2955 #endif
2956 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2957 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2959 dirblock = __card_getdirblock(card);
2960 entry = &dirblock->entries[dir_entry->fileno];
2962 card->curr_fileblock = entry->block;
2963 memset(entry,-1,sizeof(struct card_direntry));
2965 cb = callback;
2966 if(!cb) cb = __card_defaultapicallback;
2967 card->card_api_cb = cb;
2969 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2971 __card_putcntrlblock(card,ret);
2972 return ret;
2975 s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry)
2977 s32 ret;
2978 #ifdef _CARD_DEBUG
2979 printf("CARD_DeleteEntry(%p)\n",dir_entry);
2980 #endif
2981 if((ret=CARD_DeleteEntryAsync(chn,dir_entry,__card_synccallback))>=0) {
2982 ret = __card_sync(chn);
2984 return ret;
2987 s32 CARD_FormatAsync(s32 chn,cardcallback callback)
2989 u32 enc;
2991 enc = SYS_GetFontEncoding();
2992 return __card_formatregion(chn,enc,callback);
2995 s32 CARD_Format(s32 chn)
2997 s32 ret;
2998 u32 enc;
3000 enc = SYS_GetFontEncoding();
3001 if((ret=__card_formatregion(chn,enc,__card_synccallback))>=0) {
3002 ret = __card_sync(chn);
3004 return ret;
3007 s32 CARD_GetErrorCode(s32 chn)
3009 card_block *card = NULL;
3011 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3012 card = &cardmap[chn];
3013 return card->result;
3016 s32 __card_findnext(card_dir *dir)
3018 s32 ret;
3019 struct card_dat *dirblock = NULL;
3020 struct card_direntry *entries = NULL;
3021 card_block *card = NULL;
3023 if(dir->chn<EXI_CHANNEL_0 || dir->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3024 if(dir->fileno>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
3025 if((ret=__card_getcntrlblock(dir->chn,&card))<0) return ret;
3027 if(!card->attached) return CARD_ERROR_NOCARD;
3028 dirblock = __card_getdirblock(card);
3030 entries = dirblock->entries;
3031 do {
3032 //printf("%s\n", entries[dir->fileno].filename);
3033 if(entries[dir->fileno].gamecode[0]!=0xff) {
3034 if ((dir->showall || memcmp(entries[dir->fileno].gamecode,card_gamecode,4)==0)
3035 && (dir->showall || memcmp(entries[dir->fileno].company,card_company,2)==0)) {
3036 dir->filelen = entries[dir->fileno].length*card->sector_size;
3037 memcpy(dir->filename, entries[dir->fileno].filename, CARD_FILENAMELEN);
3038 memcpy(dir->gamecode, entries[dir->fileno].gamecode, 4);
3039 memcpy(dir->company, entries[dir->fileno].company, 2);
3041 __card_putcntrlblock(card,CARD_ERROR_READY);
3042 return CARD_ERROR_READY;
3045 dir->fileno++;
3046 } while (dir->fileno < CARD_MAXFILES);
3047 __card_putcntrlblock(card,CARD_ERROR_NOFILE);
3048 return CARD_ERROR_NOFILE;
3051 s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall)
3053 // initialise structure
3054 dir->chn = chn;
3055 dir->fileno = 0;
3056 dir->filelen = 0;
3057 dir->filename[0] = 0;
3058 dir->gamecode[0] = 0;
3059 dir->company[0] = 0;
3060 dir->showall = showall;
3061 return __card_findnext(dir);
3064 s32 CARD_FindNext(card_dir *dir)
3066 dir->fileno++;
3068 return __card_findnext(dir);
3071 s32 CARD_GetDirectory(s32 chn,card_dir *dir_entries,s32 *count,bool showall)
3073 s32 i,cnt;
3074 s32 ret = CARD_ERROR_READY;
3075 struct card_dat *dirblock = NULL;
3076 struct card_direntry *entries = NULL;
3077 card_block *card = NULL;
3079 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3080 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3082 if(!card->attached) return CARD_ERROR_NOCARD;
3083 dirblock = __card_getdirblock(card);
3085 entries = dirblock->entries;
3086 for(i=0,cnt=0;i<CARD_MAXFILES;i++) {
3087 if(entries[i].gamecode[0]!=0xff) {
3088 if(showall || ((card_gamecode[0]!=0xff && memcmp(entries[i].gamecode,card_gamecode,4)==0)
3089 && (card_company[0]!=0xff && memcmp(entries[i].company,card_company,2)==0))) {
3090 dir_entries[cnt].fileno = i;
3091 dir_entries[cnt].permissions = entries[i].permission;
3092 dir_entries[cnt].filelen = entries[i].length*card->sector_size;
3093 memcpy(dir_entries[cnt].gamecode,entries[i].gamecode,4);
3094 memcpy(dir_entries[cnt].company,entries[i].company,2);
3095 memcpy(dir_entries[cnt].filename,entries[i].filename,CARD_FILENAMELEN);
3096 cnt++;
3100 if(count) *count = cnt;
3101 if(cnt==0) ret = CARD_ERROR_NOFILE;
3102 __card_putcntrlblock(card,ret);
3103 return ret;
3106 s32 CARD_GetSectorSize(s32 chn,u32 *sector_size)
3108 s32 ret;
3109 card_block *card = NULL;
3111 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3112 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3114 *sector_size = card->sector_size;
3115 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
3117 return ret;
3120 s32 CARD_GetBlockCount(s32 chn,u32 *block_count)
3122 s32 ret;
3123 card_block *card = NULL;
3125 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3126 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3128 *block_count = card->blocks;
3129 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
3131 return ret;
3134 s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats)
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;
3144 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3146 dirblock = __card_getdirblock(card);
3147 if(dirblock) {
3148 entry = &dirblock->entries[fileno];
3149 memcpy(stats->gamecode,entry->gamecode,4);
3150 memcpy(stats->company,entry->company,2);
3151 memcpy(stats->filename,entry->filename,CARD_FILENAMELEN);
3152 stats->len = entry->length*card->sector_size;
3153 stats->time = entry->lastmodified;
3154 stats->banner_fmt = entry->bannerfmt;
3155 stats->icon_addr = entry->iconaddr;
3156 stats->icon_fmt = entry->iconfmt;
3157 stats->icon_speed = entry->iconspeed;
3158 stats->comment_addr = entry->commentaddr;
3159 __card_updateiconoffsets(entry,stats);
3162 return __card_putcntrlblock(card,CARD_ERROR_READY);
3165 s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback)
3167 s32 ret;
3168 card_block *card = NULL;
3169 struct card_dat *dirblock = NULL;
3170 struct card_direntry *entry = NULL;
3172 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
3173 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
3174 if(stats->icon_addr!=-1 && stats->icon_addr>CARD_READSIZE) return CARD_ERROR_FATAL_ERROR;
3175 if(stats->comment_addr!=-1 && stats->comment_addr>8128) return CARD_ERROR_FATAL_ERROR;
3176 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
3178 ret = CARD_ERROR_BROKEN;
3179 dirblock = __card_getdirblock(card);
3180 if(dirblock) {
3181 entry = &dirblock->entries[fileno];
3182 entry->bannerfmt = stats->banner_fmt;
3183 entry->iconaddr = stats->icon_addr;
3184 entry->iconfmt = stats->icon_fmt;
3185 entry->iconspeed = stats->icon_speed;
3186 entry->commentaddr = stats->comment_addr;
3187 __card_updateiconoffsets(entry,stats);
3189 if(entry->iconaddr==-1) entry->iconfmt = ((entry->iconfmt&~CARD_ICON_MASK)|CARD_ICON_CI);
3191 entry->lastmodified = time(NULL);
3192 if((ret=__card_updatedir(chn,callback))>=0) return ret;
3195 return __card_putcntrlblock(card,ret);
3198 s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats)
3200 s32 ret;
3202 if((ret=CARD_SetStatusAsync(chn,fileno,stats,__card_synccallback))>=0) {
3203 ret = __card_sync(chn);
3205 return ret;
3208 s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr)
3210 s32 ret;
3211 struct card_direntry entry;
3213 if((ret=__card_getstatusex(chn,fileno,&entry))==CARD_ERROR_READY) {
3214 *attr = entry.permission;
3216 return ret;
3219 s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback)
3221 s32 ret;
3222 struct card_direntry entry;
3224 if((ret=__card_getstatusex(chn,fileno,&entry))>=0) {
3225 entry.permission = attr;
3226 ret = __card_setstatusexasync(chn,fileno,&entry,callback);
3228 return ret;
3231 s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr)
3233 s32 ret;
3235 if((ret=CARD_SetAttributesAsync(chn,fileno,attr,__card_synccallback))>=0) {
3236 ret = __card_sync(chn);
3238 return ret;
3241 s32 CARD_SetCompany(const char *company)
3243 u32 level,i;
3245 _CPU_ISR_Disable(level);
3246 for(i=0;i<2;i++) card_company[i] = 0xff;
3247 if(company && strlen(company)<=2) memcpy(card_company,company,2) ;
3248 _CPU_ISR_Restore(level);
3250 return CARD_ERROR_READY;
3253 s32 CARD_SetGamecode(const char *gamecode)
3255 u32 level,i;
3257 _CPU_ISR_Disable(level);
3258 for(i=0;i<4;i++) card_gamecode[i] = 0xff;
3259 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4) ;
3260 _CPU_ISR_Restore(level);
3262 return CARD_ERROR_READY;