1 /*-------------------------------------------------------------
2
3 card.c -- Memory card subsystem
4
5 Copyright (C) 2004
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
8
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.
12
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:
16
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.
21
22 2. Altered source versions must be plainly marked as such, and
23 must not be misrepresented as being the original software.
24
25 3. This notice may not be removed or altered from any source
26 distribution.
27
28 -------------------------------------------------------------*/
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <malloc.h>
34 #include <time.h>
35 #include <gcutil.h>
36 #include "asm.h"
37 #include "processor.h"
38 #include "system.h"
39 #include "ogcsys.h"
40 #include "cache.h"
41 #include "dsp.h"
42 #include "lwp.h"
43 #include "exi.h"
44 #include "card.h"
45
46 #define CARD_SYSAREA 5
47 #define CARD_SYSDIR 0x2000
48 #define CARD_SYSDIR_BACK 0x4000
49 #define CARD_SYSBAT 0x6000
50 #define CARD_SYSBAT_BACK 0x8000
51
52 #define _SHIFTL(v, s, w) \
53 ((u32) (((u32)(v) & ((0x01 << (w)) - 1)) << (s)))
54 #define _SHIFTR(v, s, w) \
55 ((u32)(((u32)(v) >> (s)) & ((0x01 << (w)) - 1)))
56 #define _ROTL(v,s) \
57 (((u32)v<<s)|((u32)v>>(0x20-s)))
58
59 #define CARD_STATUS_UNLOCKED 0x40
60
61 struct card_header {
62 u32 serial[0x08];
63 u16 device_id;
64 u16 size;
65 u16 encoding;
66 u8 padding[0x1d6];
67 u16 chksum1;
68 u16 chksum2;
69 } ATTRIBUTE_PACKED;
70
71 struct card_direntry {
72 u8 gamecode[4];
73 u8 company[2];
74 u8 pad_00;
75 u8 bannerfmt;
76 u8 filename[CARD_FILENAMELEN];
77 u32 lastmodified;
78 u32 iconaddr;
79 u16 iconfmt;
80 u16 iconspeed;
81 u8 permission;
82 u8 copytimes;
83 u16 block;
84 u16 length;
85 u16 pad_01;
86 u32 commentaddr;
87 } ATTRIBUTE_PACKED;
88
89 struct card_dat { // dir allocation table
90 struct card_direntry entries[CARD_MAXFILES];
91 };
92
93 struct card_dircntrl {
94 u8 pad[58];
95 u16 updated;
96 u16 chksum1;
97 u16 chksum2;
98 } ATTRIBUTE_PACKED;
99
100 struct card_bat {
101 u16 chksum1;
102 u16 chksum2;
103 u16 updated;
104 u16 freeblocks;
105 u16 lastalloc;
106 u16 fat[0xffc];
107 } ATTRIBUTE_PACKED;
108
109 typedef struct _card_block {
110 u8 cmd[9];
111 u32 cmd_len;
112 u32 cmd_mode;
113 u32 cmd_blck_cnt;
114 u32 cmd_sector_addr;
115 u32 cmd_retries;
116 u32 attached;
117 s32 result;
118 u32 cid;
119 u16 card_size;
120 u32 mount_step;
121 u32 format_step;
122 u32 sector_size;
123 u16 blocks;
124 u32 latency;
125 u32 cipher;
126 u32 key[3];
127 u32 transfer_cnt;
128 u16 curr_fileblock;
129 card_file *curr_file;
130 struct card_dat *curr_dir;
131 struct card_bat *curr_fat;
132 void *workarea;
133 void *cmd_usr_buf;
134 lwpq_t wait_sync_queue;
135 syswd_t timeout_svc;
136 dsptask_t dsp_task;
137
138 cardcallback card_ext_cb;
139 cardcallback card_tx_cb;
140 cardcallback card_exi_cb;
141 cardcallback card_api_cb;
142 cardcallback card_xfer_cb;
143 cardcallback card_erase_cb;
144 cardcallback card_unlock_cb;
145 } card_block;
146
147 #if defined(HW_RVL)
148
149 static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) =
150 {
151 0x00000000,0x00000000,0x00000000,0x00000000,
152 0x00000000,0x00000000,0x00000021,0x02ff0021,
153 0x13061203,0x12041305,0x009200ff,0x0088ffff,
154 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf,
155 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf,
156 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e,
157 0x1fdf24ff,0x02403fff,0x00980400,0x009a0010,
158 0x00990000,0x8e0002bf,0x009402bf,0x864402bf,
159 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00,
160 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380,
161 0x00010295,0x005a0380,0x00020295,0x8000029f,
162 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e,
163 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff,
164 0x03403fff,0x1c9f02bf,0x008e00c7,0xffff02bf,
165 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf,
166 0x008e20ff,0x03403fff,0x1f5f02bf,0x008e21ff,
167 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021,
168 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0,
169 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd,
170 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d,
171 0x009c02df,0x00000000,0x00000000,0x00000000,
172 0x00000000,0x00000000,0x00000000,0x00000000
173 };
174
175 #elif defined(HW_DOL)
176
177 static u32 _cardunlockdata[0x160] ATTRIBUTE_ALIGN(32) =
178 {
179 0x00000000,0x00000000,0x00000000,0x00000000,
180 0x00000000,0x00000000,0x00000021,0x02ff0021,
181 0x13061203,0x12041305,0x009200ff,0x0088ffff,
182 0x0089ffff,0x008affff,0x008bffff,0x8f0002bf,
183 0x008816fc,0xdcd116fd,0x000016fb,0x000102bf,
184 0x008e25ff,0x0380ff00,0x02940027,0x02bf008e,
185 0x1fdf24ff,0x02400fff,0x00980400,0x009a0010,
186 0x00990000,0x8e0002bf,0x009402bf,0x864402bf,
187 0x008816fc,0xdcd116fd,0x000316fb,0x00018f00,
188 0x02bf008e,0x0380cdd1,0x02940048,0x27ff0380,
189 0x00010295,0x005a0380,0x00020295,0x8000029f,
190 0x00480021,0x8e0002bf,0x008e25ff,0x02bf008e,
191 0x25ff02bf,0x008e25ff,0x02bf008e,0x00c5ffff,
192 0x03400fff,0x1c9f02bf,0x008e00c7,0xffff02bf,
193 0x008e00c6,0xffff02bf,0x008e00c0,0xffff02bf,
194 0x008e20ff,0x03400fff,0x1f5f02bf,0x008e21ff,
195 0x02bf008e,0x23ff1205,0x1206029f,0x80b50021,
196 0x27fc03c0,0x8000029d,0x008802df,0x27fe03c0,
197 0x8000029c,0x008e02df,0x2ece2ccf,0x00f8ffcd,
198 0x00f9ffc9,0x00faffcb,0x26c902c0,0x0004029d,
199 0x009c02df,0x00000000,0x00000000,0x00000000,
200 0x00000000,0x00000000,0x00000000,0x00000000
201 };
202 #endif
203
204 static u32 card_sector_size[] =
205 {
206 0x0002000,
207 0x0004000,
208 0x0008000,
209 0x0010000,
210 0x0020000,
211 0x0040000,
212 0x0000000,
213 0x0000000
214 };
215
216 static u32 card_latency[] =
217 {
218 0x00000004,
219 0x00000008,
220 0x00000010,
221 0x00000020,
222 0x00000030,
223 0x00000080,
224 0x00000100,
225 0x00000200
226 };
227
228 static u32 card_inited = 0;
229 static u32 crand_next = 1;
230
231 static u8 card_gamecode[4] = {0xff,0xff,0xff,0xff};
232 static u8 card_company[2] = {0xff,0xff};
233 static card_block cardmap[2];
234
235 static void __card_mountcallback(s32 chn,s32 result);
236 static void __erase_callback(s32 chn,s32 result);
237 static s32 __dounlock(s32 chn,u32 *key);
238 static s32 __card_readsegment(s32 chn,cardcallback callback);
239 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
240 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback);
241 static s32 __card_updatedir(s32 chn,cardcallback callback);
242 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
243 static s32 __card_writepage(s32 chn,cardcallback callback);
244 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback);
245 static s32 __card_onreset(s32 final);
246
247 static sys_resetinfo card_resetinfo = {
248 {},
249 __card_onreset,
250 127
251 };
252
253 extern unsigned long gettick();
254 extern long long gettime();
255 extern syssram* __SYS_LockSram();
256 extern syssramex* __SYS_LockSramEx();
257 extern u32 __SYS_UnlockSram(u32 write);
258 extern u32 __SYS_UnlockSramEx(u32 write);
259
260 static vu16* const _viReg = (u16*)0xCC002000;
261
262 /* new api */
__card_onreset(s32 final)263 static s32 __card_onreset(s32 final)
264 {
265 if(final==FALSE) {
266 if(CARD_Unmount(CARD_SLOTA)==-1) return 0;
267 if(CARD_Unmount(CARD_SLOTB)==-1) return 0;
268 }
269 return 1;
270 }
271
__card_checksum(u16 * buff,u32 len,u16 * cs1,u16 * cs2)272 static void __card_checksum(u16 *buff,u32 len,u16 *cs1,u16 *cs2)
273 {
274 u32 i;
275 *cs1 = 0;
276 *cs2 = 0;
277 len /= 2;
278 for (i = 0; i < len; ++i) {
279 *cs1 += buff[i];
280 *cs2 += (buff[i] ^ 0xffff);
281 }
282 if (*cs1 == 0xffff) *cs1 = 0;
283 if (*cs2 == 0xffff) *cs2 = 0;
284 }
285
__card_putcntrlblock(card_block * card,s32 result)286 static s32 __card_putcntrlblock(card_block *card,s32 result)
287 {
288 u32 level;
289
290 _CPU_ISR_Disable(level);
291 if(card->attached) card->result = result;
292 else if(card->result==CARD_ERROR_BUSY) card->result = result;
293 _CPU_ISR_Restore(level);
294 return result;
295 }
296
__card_getcntrlblock(s32 chn,card_block ** card)297 static s32 __card_getcntrlblock(s32 chn,card_block **card)
298 {
299 s32 ret;
300 u32 level;
301 card_block *rcard = NULL;
302
303 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
304
305 _CPU_ISR_Disable(level);
306 rcard = &cardmap[chn];
307 if(!rcard->attached) {
308 _CPU_ISR_Restore(level);
309 return CARD_ERROR_NOCARD;
310 }
311
312 ret = CARD_ERROR_BUSY;
313 if(rcard->result!=CARD_ERROR_BUSY) {
314 rcard->result = CARD_ERROR_BUSY;
315 rcard->card_api_cb = NULL;
316 *card = rcard;
317 ret = CARD_ERROR_READY;
318 }
319 _CPU_ISR_Restore(level);
320 return ret;
321 }
322
__card_getdirblock(card_block * card)323 static __inline__ struct card_dat* __card_getdirblock(card_block *card)
324 {
325 return card->curr_dir;
326 }
327
__card_getbatblock(card_block * card)328 static __inline__ struct card_bat* __card_getbatblock(card_block *card)
329 {
330 return card->curr_fat;
331 }
332
__card_sync(s32 chn)333 static s32 __card_sync(s32 chn)
334 {
335 s32 ret;
336 u32 level;
337 card_block *card = &cardmap[chn];
338
339 _CPU_ISR_Disable(level);
340 while((ret=CARD_GetErrorCode(chn))==CARD_ERROR_BUSY) {
341 LWP_ThreadSleep(card->wait_sync_queue);
342 }
343 _CPU_ISR_Restore(level);
344 return ret;
345 }
346
__card_synccallback(s32 chn,s32 result)347 static void __card_synccallback(s32 chn,s32 result)
348 {
349 u32 level;
350 card_block *card = &cardmap[chn];
351 _CPU_ISR_Disable(level);
352 LWP_ThreadBroadcast(card->wait_sync_queue);
353 _CPU_ISR_Restore(level);
354 }
355
__card_updateiconoffsets(struct card_direntry * entry,card_stat * stats)356 static void __card_updateiconoffsets(struct card_direntry *entry,card_stat *stats)
357 {
358 s32 i;
359 u8 bnrfmt,nicons;
360 u32 iconaddr,iconbase;
361
362 iconaddr = entry->iconaddr;
363 if(iconaddr==-1) {
364 stats->banner_fmt = 0;
365 stats->icon_fmt = 0;
366 stats->icon_speed = 0;
367 iconaddr = 0;
368 }
369
370 if(entry->bannerfmt&CARD_BANNER_MASK) {
371 if(!(entry->bannerfmt&0x10)) {
372 bnrfmt = (entry->bannerfmt&CARD_BANNER_MASK);
373 if(bnrfmt==CARD_BANNER_CI) {
374 stats->banner_fmt = bnrfmt;
375 stats->offset_banner = iconaddr;
376 stats->offset_banner_tlut = iconaddr+3072;
377 iconaddr += (3072+512);
378 } else if(bnrfmt==CARD_BANNER_RGB) {
379 stats->banner_fmt = bnrfmt;
380 stats->offset_banner = iconaddr;
381 stats->offset_banner_tlut = -1;
382 iconaddr += 6144;
383 }
384 } else {
385 stats->offset_banner = -1;
386 stats->offset_banner_tlut = -1;
387 }
388 }
389
390 nicons = 0;
391 for(i=0;i<CARD_MAXICONS;i++) {
392 stats->iconfmt[i] = ((entry->iconfmt>>(i<<1))&CARD_ICON_MASK);
393 stats->iconspeed[i] = ((entry->iconspeed>>(i<<1))&CARD_SPEED_MASK);
394 if(stats->iconspeed[i]==0) stats->iconfmt[i] = 0;
395 if(stats->iconfmt[i]) nicons++;
396 }
397
398 iconbase = iconaddr;
399 for(i=0;i<CARD_MAXICONS;i++) {
400 switch(stats->iconfmt[i]) {
401 case 1: //CARD_ICON_CI with shared palette
402 stats->offset_icon[i] = iconaddr;
403 stats->offset_icon_tlut[i] = iconbase + (nicons*1024);
404 iconaddr += 1024;
405 break;
406 case 2: //CARD_ICON_RGB
407 stats->offset_icon[i] = iconaddr;
408 stats->offset_icon_tlut[i] = -1;
409 iconaddr += 3072;
410 break;
411 case 3: //CARD_ICON_CI with own palette
412 stats->offset_icon[i] = iconaddr;
413 stats->offset_icon_tlut[i] = iconaddr + 1024;
414 iconaddr += 1536;
415 break;
416 default: //CARD_ICON_NONE
417 stats->offset_icon[i] = -1;
418 stats->offset_icon_tlut[i] = -1;
419 break;
420
421 }
422 }
423 // stats->offset_data = iconaddr;
424 }
425
__card_getstatusex(s32 chn,s32 fileno,struct card_direntry * entry)426 static s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry)
427 {
428 s32 ret;
429 card_block *card = NULL;
430 struct card_dat *dirblock = NULL;
431
432 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
433 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
434 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
435
436 ret = CARD_ERROR_BROKEN;
437 dirblock = __card_getdirblock(card);
438 if(dirblock) {
439 ret = CARD_ERROR_READY;
440 memcpy(entry,&dirblock->entries[fileno],sizeof(struct card_direntry));
441 }
442 return __card_putcntrlblock(card,ret);
443 }
444
__card_setstatusexasync(s32 chn,s32 fileno,struct card_direntry * entry,cardcallback callback)445 static s32 __card_setstatusexasync(s32 chn,s32 fileno,struct card_direntry *entry,cardcallback callback)
446 {
447 s32 ret,i,bend;
448 card_block *card = NULL;
449 struct card_dat *dirblock = NULL;
450 struct card_direntry *entries = NULL;
451
452 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
453 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
454 if(entry->filename[0]==0xff || entry->filename[0]==0) return CARD_ERROR_FATAL_ERROR;
455 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
456
457 ret = CARD_ERROR_BROKEN;
458 dirblock = __card_getdirblock(card);
459 if(dirblock) {
460 i = 0; bend = 0;
461 ret = CARD_ERROR_READY;
462 entries = dirblock->entries;
463 while(i<CARD_FILENAMELEN) {
464 if(bend || entry->filename[i]==0) {
465 entry->filename[i] = 0;
466 bend = 1;
467 }
468 i++;
469 }
470
471 if(memcmp(entries[fileno].filename,entry->filename,CARD_FILENAMELEN)
472 || memcmp(entries[fileno].gamecode,entry->gamecode,4)
473 || memcmp(entries[fileno].company,entry->company,2)) {
474 i = 0;
475 while(i<CARD_MAXFILES) {
476 if(i!=fileno && entries[i].gamecode[0]!=0xff
477 && memcmp(entries[i].gamecode,entry->gamecode,4)==0
478 && memcmp(entries[i].company,entry->company,2)==0
479 && memcmp(entries[i].filename,entry->filename,CARD_FILENAMELEN)==0) {
480 return __card_putcntrlblock(card,CARD_ERROR_EXIST);
481 }
482 i++;
483 }
484 memcpy(entries[fileno].filename,entry->filename,CARD_FILENAMELEN);
485 memcpy(entries[fileno].gamecode,entry->gamecode,4);
486 memcpy(entries[fileno].company,entry->company,2);
487 }
488
489 entries[fileno].lastmodified = entry->lastmodified;
490 entries[fileno].bannerfmt = entry->bannerfmt;
491 entries[fileno].iconaddr = entry->iconaddr;
492 entries[fileno].iconfmt = entry->iconfmt;
493 entries[fileno].iconspeed = entry->iconspeed;
494 entries[fileno].commentaddr = entry->commentaddr;
495 entries[fileno].permission = entry->permission;
496 entries[fileno].copytimes = entry->copytimes;
497
498 if((ret=__card_updatedir(chn,callback))>=0) return ret;
499 }
500 return __card_putcntrlblock(card,ret);
501 }
502
__card_getfilenum(card_block * card,const char * filename,const char * gamecode,const char * company,s32 * fileno)503 static s32 __card_getfilenum(card_block *card,const char *filename,const char *gamecode,const char *company,s32 *fileno)
504 {
505 u32 i = 0;
506 struct card_direntry *entries = NULL;
507 struct card_dat *dirblock = NULL;
508 if(!card->attached) return CARD_ERROR_NOCARD;
509 dirblock = __card_getdirblock(card);
510
511 entries = dirblock->entries;
512 for(i=0;i<CARD_MAXFILES;i++) {
513 if(entries[i].gamecode[0]!=0xff) {
514 if(strcmp(filename,(const char*)entries[i].filename)==0) {
515 if((gamecode && gamecode[0]!=0xff && memcmp(entries[i].gamecode,gamecode,4)!=0)
516 || (company && company[0]!=0xff && memcmp(entries[i].company,company,2)!=0)) continue;
517
518 *fileno = i;
519 break;
520 }
521 }
522 }
523 if(i>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
524 return CARD_ERROR_READY;
525 }
526
__card_seek(card_file * file,s32 len,s32 offset,card_block ** rcard)527 static s32 __card_seek(card_file *file,s32 len,s32 offset,card_block **rcard)
528 {
529 s32 ret;
530 s32 i,entry_len;
531 card_block *card = NULL;
532 struct card_direntry *entry = NULL;
533 struct card_dat *dirblock = NULL;
534 struct card_bat *fatblock = NULL;
535 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
536 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
537 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
538 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
539 return CARD_ERROR_FATAL_ERROR;
540 }
541
542 dirblock = __card_getdirblock(card);
543 entry = &dirblock->entries[file->filenum];
544 if(entry->gamecode[0]!=0xff) {
545 entry_len = entry->length*card->sector_size;
546 if(entry_len<offset || entry_len<(offset+len)) {
547 __card_putcntrlblock(card,CARD_ERROR_LIMIT);
548 return CARD_ERROR_LIMIT;
549 }
550 card->curr_file = file;
551 file->len = len;
552
553 if(offset<file->offset) {
554 file->offset = 0;
555 file->iblock = entry->block;
556 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
557 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
558 return CARD_ERROR_BROKEN;
559 }
560 }
561
562 fatblock = __card_getbatblock(card);
563 for(i=file->iblock;i<card->blocks && file->offset<(offset&~(card->sector_size-1));i=file->iblock) {
564 file->offset += card->sector_size;
565 file->iblock = fatblock->fat[i-CARD_SYSAREA];
566 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
567 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
568 return CARD_ERROR_BROKEN;
569 }
570 }
571 file->offset = offset;
572 *rcard = card;
573 }
574 return CARD_ERROR_READY;
575 }
576
__card_checkdir(card_block * card,u32 * currdir)577 static u32 __card_checkdir(card_block *card,u32 *currdir)
578 {
579 u32 dir,bad,bad_dir;
580 u16 chksum0,chksum1;
581 struct card_dircntrl *dircntrl[2];
582 struct card_dat *dirblock[2];
583 dir = 0;
584 bad = 0;
585 bad_dir = 0;
586 while(dir<2) {
587 dirblock[dir] = card->workarea+((dir+1)<<13);
588 dircntrl[dir] = (card->workarea+((dir+1)<<13))+8128;
589 __card_checksum((u16*)dirblock[dir],0x1ffc,&chksum0,&chksum1);
590 if(chksum0!=dircntrl[dir]->chksum1 || chksum1!=dircntrl[dir]->chksum2) {
591 card->curr_dir = NULL;
592 bad_dir = dir;
593 bad++;
594 }
595 dir++;
596 }
597
598 dir = bad_dir;
599 if(!bad) {
600 if(dircntrl[0]->updated<dircntrl[1]->updated) dir = 0;
601 else dir = 1;
602 }
603 if(card->curr_dir==NULL) {
604 card->curr_dir = dirblock[dir];
605 memcpy(dirblock[dir],dirblock[dir^1],8192);
606 }
607 else if(card->curr_dir==dirblock[0]) dir = 0;
608 else dir = 1;
609
610 if(currdir) *currdir = dir;
611 return bad;
612 }
613
__card_checkfat(card_block * card,u32 * currfat)614 static u32 __card_checkfat(card_block *card,u32 *currfat)
615 {
616 u32 fat,bad,bad_fat;
617 u16 chksum0,chksum1;
618 struct card_bat *fatblock[2];
619 fat = 0;
620 bad = 0;
621 bad_fat = 0;
622 while(fat<2) {
623 fatblock[fat] = card->workarea+((fat+3)<<13);
624 __card_checksum((u16*)(((u32)fatblock[fat])+4),0x1ffc,&chksum0,&chksum1);
625 if(chksum0!=fatblock[fat]->chksum1 || chksum1!=fatblock[fat]->chksum2) {
626 card->curr_fat = NULL;
627 bad_fat = fat;
628 bad++;
629 } else {
630 u16 curblock = CARD_SYSAREA;
631 u16 freeblocks = 0;
632 while(curblock<card->blocks) {
633 if(!fatblock[fat]->fat[curblock-CARD_SYSAREA]) freeblocks++;
634 curblock++;
635 }
636 if(freeblocks!=fatblock[fat]->freeblocks) {
637 card->curr_fat = NULL;
638 bad_fat = fat;
639 bad++;
640 }
641 }
642 fat++;
643 }
644
645 fat = bad_fat;
646 if(!bad) {
647 if(fatblock[0]->updated<fatblock[1]->updated) fat = 0;
648 else fat = 1;
649 }
650 if(card->curr_fat==NULL) {
651 card->curr_fat = fatblock[fat];
652 memcpy(fatblock[fat],fatblock[fat^1],8192);
653 }
654 else if(card->curr_fat==fatblock[0]) fat = 0;
655 else fat = 1;
656
657 if(currfat) *currfat = fat;
658 return bad;
659 }
660
__card_verify(card_block * card)661 static s32 __card_verify(card_block *card)
662 {
663 u32 ret = 0;
664
665 ret += __card_checkdir(card,NULL);
666 ret += __card_checkfat(card,NULL);
667 if(ret<=2) {
668 if(card->curr_dir && card->curr_fat) return CARD_ERROR_READY;
669 }
670 return CARD_ERROR_BROKEN;
671 }
672
__card_iscard(u32 id)673 static u32 __card_iscard(u32 id)
674 {
675 u32 ret;
676 u32 idx,tmp,secsize;
677
678 if(id&~0xffff) return 0;
679 if(id&0x03) return 0;
680
681 ret = 0;
682 tmp = id&0xfc;
683 if(tmp==EXI_MEMCARD59 || tmp==EXI_MEMCARD123
684 || tmp==EXI_MEMCARD251 || tmp==EXI_MEMCARD507
685 || tmp==EXI_MEMCARD1019 || tmp==EXI_MEMCARD2043) {
686 idx = _ROTL(id,23)&0x1c;
687 if((secsize=card_sector_size[idx>>2])==0) return 0;
688 tmp = ((tmp<<20)&0x1FFE0000)/secsize;
689 if(tmp>8) ret = 1;
690 }
691 return ret;
692 }
693
__card_allocblock(s32 chn,u32 blocksneed,cardcallback callback)694 static s32 __card_allocblock(s32 chn,u32 blocksneed,cardcallback callback)
695 {
696 s32 ret;
697 u16 block,currblock = 0,prevblock = 0;
698 u32 i,count;
699 card_block *card = NULL;
700 struct card_bat *fatblock = NULL;
701 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
702 card = &cardmap[chn];
703
704 if(!card->attached) return CARD_ERROR_NOCARD;
705 fatblock = __card_getbatblock(card);
706
707 if(fatblock->freeblocks<blocksneed) return CARD_ERROR_INSSPACE;
708
709 // Add which blocks this file will take up into the FAT
710 count = 0;
711 block = 0xffff;
712 currblock = fatblock->lastalloc;
713 i = blocksneed;
714 while(1) {
715 if(i==0) {
716 // Done allocating blocks
717 fatblock->freeblocks -= blocksneed;
718 fatblock->lastalloc = currblock;
719 card->curr_fileblock = block;
720 ret = __card_updatefat(chn,fatblock,callback);
721 break;
722 }
723
724 /*
725 Since testing free space has already been done, if all the blocks
726 the file takes up cannot be entered into the FAT, something is
727 wrong.
728 */
729 count++;
730 if(count>=(card->blocks-CARD_SYSAREA)) return CARD_ERROR_BROKEN;
731
732 currblock++;
733 if(currblock<CARD_SYSAREA || currblock>=card->blocks) currblock = CARD_SYSAREA;
734 if(fatblock->fat[currblock-CARD_SYSAREA]==0) {
735 if(block!=0xffff)
736 fatblock->fat[prevblock-CARD_SYSAREA] = currblock;
737 else
738 block = currblock;
739
740 fatblock->fat[currblock-CARD_SYSAREA] = 0xffff;
741 prevblock = currblock;
742 i--;
743 }
744 }
745 return ret;
746 }
747
__card_freeblock(s32 chn,u16 block,cardcallback callback)748 static s32 __card_freeblock(s32 chn,u16 block,cardcallback callback)
749 {
750 u16 next = 0xffff,prev = 0xffff;
751 card_block *card = NULL;
752 struct card_bat *fatblock = NULL;
753 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
754 card = &cardmap[chn];
755
756 if(!card->attached) return CARD_ERROR_NOCARD;
757
758 fatblock = __card_getbatblock(card);
759 next = fatblock->fat[block-CARD_SYSAREA];
760 while(1) {
761 if(next==0xffff) break;
762 if(next<CARD_SYSAREA || next>=card->blocks) return CARD_ERROR_BROKEN;
763
764 // Get the file's next block and clear the previous one from the fat
765 prev = next;
766 next = fatblock->fat[prev-CARD_SYSAREA];
767 fatblock->fat[prev-CARD_SYSAREA] = 0;
768 fatblock->freeblocks++;
769 }
770 return __card_updatefat(chn,fatblock,callback);
771 }
772
__card_unlockedhandler(s32 chn,s32 dev)773 static s32 __card_unlockedhandler(s32 chn,s32 dev)
774 {
775 s32 ret;
776 cardcallback cb = NULL;
777 card_block *card = NULL;
778
779 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
780 card = &cardmap[chn];
781
782 ret = CARD_ERROR_READY;
783 cb = card->card_unlock_cb;
784 if(cb) {
785 card->card_unlock_cb = NULL;
786 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
787 cb(chn,ret);
788 }
789 return CARD_ERROR_UNLOCKED;
790 }
791
__card_readstatus(s32 chn,u8 * pstatus)792 static s32 __card_readstatus(s32 chn,u8 *pstatus)
793 {
794 u8 val[2];
795 u32 err;
796 s32 ret;
797
798 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
799 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
800
801 err = 0;
802 val[0] = 0x83; val[1] = 0x00;
803 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
804 if(EXI_Sync(chn)==0) err |= 0x02;
805 if(EXI_Imm(chn,pstatus,1,EXI_READ,NULL)==0) err |= 0x04;
806 if(EXI_Sync(chn)==0) err |= 0x08;
807 if(EXI_Deselect(chn)==0) err |= 0x10;
808
809 if(err) ret = CARD_ERROR_NOCARD;
810 else ret = CARD_ERROR_READY;
811 return ret;
812 }
813
__card_clearstatus(s32 chn)814 static s32 __card_clearstatus(s32 chn)
815 {
816 u8 val;
817 u32 err;
818 s32 ret;
819 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
820 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
821
822 err = 0;
823 val = 0x89;
824 if(EXI_Imm(chn,&val,1,EXI_WRITE,NULL)==0) err |= 0x01;
825 if(EXI_Sync(chn)==0) err |= 0x02;
826 if(EXI_Deselect(chn)==0) err |= 0x04;
827
828 if(err) ret = CARD_ERROR_NOCARD;
829 else ret = CARD_ERROR_READY;
830
831 return ret;
832 }
833
__card_enableinterrupt(s32 chn,u32 enable)834 static s32 __card_enableinterrupt(s32 chn,u32 enable)
835 {
836 u8 val[2];
837 u32 err;
838 s32 ret;
839
840 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
841 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
842
843 err = 0;
844 val[0] = 0x81;
845 if(enable) val[1] = 0x01;
846 else val[1] = 0x00;
847 if(EXI_Imm(chn,val,2,EXI_WRITE,NULL)==0) err |= 0x01;
848 if(EXI_Sync(chn)==0) err |= 0x02;
849 if(EXI_Deselect(chn)==0) err |= 0x04;
850
851 if(err) ret = CARD_ERROR_BUSY;
852 else ret = CARD_ERROR_READY;
853
854 return ret;
855 }
856
__card_txhandler(s32 chn,s32 dev)857 static s32 __card_txhandler(s32 chn,s32 dev)
858 {
859 u32 err;
860 s32 ret = CARD_ERROR_READY;
861 cardcallback cb = NULL;
862 card_block *card = NULL;
863 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
864 card = &cardmap[chn];
865
866 err = 0;
867 if(EXI_Deselect(chn)==0) ret |= err;
868 if(EXI_Unlock(chn)==0) ret |= err;
869
870 cb = card->card_tx_cb;
871 if(cb) {
872 card->card_tx_cb = NULL;
873 if(!err) {
874 if(EXI_Probe(chn)==0) ret = CARD_ERROR_NOCARD;
875 } else ret = CARD_ERROR_NOCARD;
876 cb(chn,ret);
877 }
878 return 1;
879 }
880
__timeouthandler(syswd_t alarm,void * cbarg)881 static void __timeouthandler(syswd_t alarm,void *cbarg)
882 {
883 u32 chn;
884 s32 ret = CARD_ERROR_READY;
885 cardcallback cb;
886 card_block *card = NULL;
887 chn = 0;
888 while(chn<EXI_CHANNEL_2) {
889 card = &cardmap[chn];
890 if(card->timeout_svc==alarm) break;
891 chn++;
892 }
893 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
894
895 if(card->attached) {
896 EXI_RegisterEXICallback(chn,NULL);
897 cb = card->card_exi_cb;
898 if(cb) {
899 card->card_exi_cb = NULL;
900 ret = CARD_ERROR_IOERROR;
901 cb(chn,ret);
902 }
903 }
904 }
905
__setuptimeout(card_block * card)906 static void __setuptimeout(card_block *card)
907 {
908 struct timespec tb;
909 SYS_CancelAlarm(card->timeout_svc);
910
911 if(card->cmd[0]==0xf1 || card->cmd[0]==0xf4) {
912 tb.tv_sec = 1*(card->sector_size/8192);
913 tb.tv_nsec = 0;
914 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL);
915 } else if(card->cmd[0]==0xf2) {
916 tb.tv_sec = 0;
917 tb.tv_nsec = 100*TB_NSPERMS;
918 SYS_SetAlarm(card->timeout_svc,&tb,__timeouthandler,NULL);
919 }
920 }
921
__retry(s32 chn)922 static s32 __retry(s32 chn)
923 {
924 u32 len;
925 card_block *card = NULL;
926
927 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
928 card = &cardmap[chn];
929 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
930 EXI_Unlock(chn);
931 return CARD_ERROR_NOCARD;
932 }
933
934 __setuptimeout(card);
935
936 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
937 EXI_Deselect(chn);
938 EXI_Unlock(chn);
939 return CARD_ERROR_NOCARD;
940 }
941
942 if(card->cmd[0]==0x52) {
943 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) {
944 EXI_Deselect(chn);
945 EXI_Unlock(chn);
946 return CARD_ERROR_NOCARD;
947 }
948 }
949
950 if(card->cmd_mode==-1) {
951 EXI_Deselect(chn);
952 EXI_Unlock(chn);
953 return CARD_ERROR_READY;
954 }
955
956 len = 128;
957 if(card->cmd[0]==0x52) len = CARD_READSIZE;
958 if(EXI_Dma(chn,card->cmd_usr_buf,len,card->cmd_mode,__card_txhandler)==0) {
959 EXI_Deselect(chn);
960 EXI_Unlock(chn);
961 return CARD_ERROR_NOCARD;
962 }
963 return CARD_ERROR_READY;
964 }
965
__card_defaultapicallback(s32 chn,s32 result)966 static void __card_defaultapicallback(s32 chn,s32 result)
967 {
968 return;
969 }
970
__card_exihandler(s32 chn,s32 dev)971 static s32 __card_exihandler(s32 chn,s32 dev)
972 {
973 u8 status;
974 s32 ret = CARD_ERROR_READY;
975 card_block *card = NULL;
976 cardcallback cb;
977 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 1;
978 card = &cardmap[chn];
979
980 SYS_CancelAlarm(card->timeout_svc);
981 if(card->attached) {
982 if(EXI_Lock(chn,EXI_DEVICE_0,NULL)==1) {
983 if((ret=__card_readstatus(chn,&status))>=0
984 && (ret=__card_clearstatus(chn))>=0) {
985 if(status&0x18) ret = CARD_ERROR_IOERROR;
986 else ret = CARD_ERROR_READY;
987
988 if(ret==CARD_ERROR_IOERROR) {
989 if((--card->cmd_retries)>0) {
990 ret = __retry(chn);
991 if(ret<0) goto exit;
992 return 1;
993 }
994 }
995 }
996 EXI_Unlock(chn);
997 } else ret = CARD_ERROR_FATAL_ERROR;
998 exit:
999 cb = card->card_exi_cb;
1000 if(cb) {
1001 card->card_exi_cb = NULL;
1002 cb(chn,ret);
1003 }
1004 }
1005 return 1;
1006 }
1007
__card_exthandler(s32 chn,s32 dev)1008 static s32 __card_exthandler(s32 chn,s32 dev)
1009 {
1010 cardcallback cb;
1011 card_block *card = NULL;
1012 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return 0;
1013 card = &cardmap[chn];
1014
1015 if(card->attached) {
1016 if(card->card_tx_cb) {
1017 printf("error: card->card_tx_cb!=NULL\n");
1018 }
1019 card->attached = 0;
1020 EXI_RegisterEXICallback(chn,NULL);
1021 SYS_CancelAlarm(card->timeout_svc);
1022
1023 cb = card->card_exi_cb;
1024 if(cb) {
1025 card->card_exi_cb = NULL;
1026 cb(chn,CARD_ERROR_NOCARD);
1027 }
1028
1029 cb = card->card_ext_cb;
1030 if(cb) {
1031 card->card_ext_cb = NULL;
1032 cb(chn,CARD_ERROR_NOCARD);
1033 }
1034
1035 }
1036 return 1;
1037 }
1038
__write_callback(s32 chn,s32 result)1039 static void __write_callback(s32 chn,s32 result)
1040 {
1041 s32 ret;
1042 cardcallback cb = NULL;
1043 card_file *file = NULL;
1044 struct card_bat *fatblock = NULL;
1045 struct card_dat *dirblock = NULL;
1046 struct card_direntry *entry = NULL;
1047 card_block *card = &cardmap[chn];
1048 ret = result;
1049 if(ret>=0) {
1050 file = card->curr_file;
1051 if(file->len>=0) {
1052 file->len = (card->sector_size-file->len);
1053 if(file->len<=0) {
1054 dirblock = __card_getdirblock(card);
1055 entry = &dirblock->entries[file->filenum];
1056 entry->lastmodified = time(NULL);
1057 cb = card->card_api_cb;
1058 card->card_api_cb = NULL;
1059 if((ret=__card_updatedir(chn,cb))>=0) return;
1060 } else {
1061 fatblock = __card_getbatblock(card);
1062 file->offset += card->sector_size;
1063 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1064 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1065 ret = CARD_ERROR_BROKEN;
1066 goto exit;
1067 }
1068 if((ret=__card_sectorerase(chn,(file->iblock*card->sector_size),__erase_callback))>=0) return;
1069 }
1070 } else
1071 ret = CARD_ERROR_CANCELED;
1072 }
1073
1074 exit:
1075 cb = card->card_api_cb;
1076 card->card_api_cb = NULL;
1077 __card_putcntrlblock(card,ret);
1078 if(cb) cb(chn,ret);
1079 }
1080
__erase_callback(s32 chn,s32 result)1081 static void __erase_callback(s32 chn,s32 result)
1082 {
1083 s32 ret;
1084 cardcallback cb = NULL;
1085 card_file *file = NULL;
1086 card_block *card = &cardmap[chn];
1087 ret = result;
1088 if(ret>=0) {
1089 file = card->curr_file;
1090 if((ret=__card_write(chn,(file->iblock*card->sector_size),card->sector_size,card->cmd_usr_buf,__write_callback))>=0) return;
1091 }
1092
1093 cb = card->card_api_cb;
1094 card->card_api_cb = NULL;
1095 __card_putcntrlblock(card,ret);
1096 if(cb) cb(chn,ret);
1097 }
1098
__read_callback(s32 chn,s32 result)1099 static void __read_callback(s32 chn,s32 result)
1100 {
1101 s32 ret;
1102 s32 len;
1103 cardcallback cb = NULL;
1104 card_file *file = NULL;
1105 card_block *card = 0;
1106 struct card_bat *fatblock = NULL;
1107 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1108 card = &cardmap[chn];
1109
1110 ret = result;
1111 file = card->curr_file;
1112 if(ret>=0) {
1113 if(file->len>=0) {
1114 file->len = file->len-(((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1115 if(file->len>0) {
1116 fatblock = __card_getbatblock(card);
1117 file->offset += (((file->offset+card->sector_size)&~(card->sector_size-1))-file->offset);
1118 file->iblock = fatblock->fat[file->iblock-CARD_SYSAREA];
1119 if(file->iblock<CARD_SYSAREA || file->iblock>=card->blocks) {
1120 ret = CARD_ERROR_BROKEN;
1121 goto exit;
1122 }
1123 len = file->len<card->sector_size?card->sector_size:file->len;
1124 if(__card_read(chn,(file->iblock*card->sector_size),len,card->cmd_usr_buf,__read_callback)>=0) return;
1125
1126 }
1127 } else
1128 ret = CARD_ERROR_CANCELED;
1129 }
1130
1131 exit:
1132 cb = card->card_api_cb;
1133 card->card_api_cb = NULL;
1134 __card_putcntrlblock(card,ret);
1135 if(cb) cb(chn,ret);
1136 }
1137
__delete_callback(s32 chn,s32 result)1138 static void __delete_callback(s32 chn,s32 result)
1139 {
1140 s32 ret;
1141 cardcallback cb = NULL;
1142 card_block *card = &cardmap[chn];
1143 cb = card->card_api_cb;
1144 card->card_api_cb = NULL;
1145
1146 ret = result;
1147 if(ret>=0 && (ret=__card_freeblock(chn,card->curr_fileblock,cb))>=0) return;
1148
1149 __card_putcntrlblock(card,ret);
1150 if(cb) cb(chn,ret);
1151 }
1152
__format_callback(s32 chn,s32 result)1153 static void __format_callback(s32 chn,s32 result)
1154 {
1155 s32 ret;
1156 cardcallback cb = NULL;
1157 card_block *card = &cardmap[chn];
1158
1159 ret = result;
1160 if(ret>=0) {
1161 if((++card->format_step)<CARD_SYSAREA) {
1162 if((ret=__card_sectorerase(chn,(card->format_step*card->sector_size),__format_callback))>=0) return;
1163 goto exit;
1164 }
1165 if(card->format_step<10) {
1166 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;
1167 goto exit;
1168 }
1169
1170 card->curr_dir = card->workarea+CARD_SYSDIR;
1171 memcpy(card->curr_dir,card->workarea+CARD_SYSDIR_BACK,8192);
1172
1173 card->curr_fat = card->workarea+CARD_SYSBAT;
1174 memcpy(card->curr_fat,card->workarea+CARD_SYSBAT_BACK,8192);
1175 }
1176 exit:
1177 cb = card->card_api_cb;
1178 card->card_api_cb = NULL;
1179 __card_putcntrlblock(card,ret);
1180 if(cb) cb(chn,ret);
1181 }
1182
__blockwritecallback(s32 chn,s32 result)1183 static void __blockwritecallback(s32 chn,s32 result)
1184 {
1185 s32 ret = CARD_ERROR_READY;
1186 cardcallback cb = NULL;
1187 card_block *card = &cardmap[chn];
1188 ret = result;
1189 if(ret>=0) {
1190 card->transfer_cnt += 128;
1191 card->cmd_sector_addr += 128;
1192 card->cmd_usr_buf += 128;
1193 if((--card->cmd_blck_cnt)>0) {
1194 if((ret=__card_writepage(chn,__blockwritecallback))>=CARD_ERROR_READY) return;
1195 }
1196 }
1197
1198 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1199
1200 cb = card->card_xfer_cb;
1201 if(cb) {
1202 card->card_xfer_cb = NULL;
1203 cb(chn,ret);
1204 }
1205 }
1206
__blockreadcallback(s32 chn,s32 result)1207 static void __blockreadcallback(s32 chn,s32 result)
1208 {
1209 s32 ret = CARD_ERROR_READY;
1210 cardcallback cb = NULL;
1211 card_block *card = &cardmap[chn];
1212 ret = result;
1213 if(ret>=0) {
1214 card->transfer_cnt += CARD_READSIZE;
1215 card->cmd_sector_addr += CARD_READSIZE;
1216 card->cmd_usr_buf += CARD_READSIZE;
1217 if((--card->cmd_blck_cnt)>0) {
1218 if((ret=__card_readsegment(chn,__blockreadcallback))>=CARD_ERROR_READY) return;
1219 }
1220 }
1221
1222 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1223 cb = card->card_xfer_cb;
1224 if(cb) {
1225 card->card_xfer_cb = NULL;
1226 cb(chn,ret);
1227 }
1228 }
1229
__unlocked_callback(s32 chn,s32 result)1230 static void __unlocked_callback(s32 chn,s32 result)
1231 {
1232 s32 ret;
1233 card_block *card;
1234 cardcallback cb;
1235 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1236 card = &cardmap[chn];
1237
1238 ret = result;
1239 if(ret>=0) {
1240 card->card_unlock_cb = __unlocked_callback;
1241 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==1) {
1242 card->card_unlock_cb = NULL;
1243 ret = __retry(chn);
1244 } else
1245 ret = 0;
1246 }
1247 if(ret<0) {
1248 if(card->cmd[0]==0xf3 || card->cmd[0]>=0xf5) return;
1249 else if(card->cmd[0]==0x52) {
1250 cb = card->card_tx_cb;
1251 if(cb) {
1252 card->card_tx_cb = NULL;
1253 cb(chn,ret);
1254 }
1255 } else if(card->cmd[0]>=0xf1) {
1256 cb = card->card_exi_cb;
1257 if(cb) {
1258 card->card_exi_cb = NULL;
1259 cb(chn,ret);
1260 }
1261 }
1262 }
1263 }
1264
__card_start(s32 chn,cardcallback tx_cb,cardcallback exi_cb)1265 static s32 __card_start(s32 chn,cardcallback tx_cb,cardcallback exi_cb)
1266 {
1267 u32 level;
1268 card_block *card = NULL;
1269 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1270 card = &cardmap[chn];
1271
1272 _CPU_ISR_Disable(level);
1273 if(tx_cb) card->card_tx_cb = tx_cb;
1274 if(exi_cb) card->card_exi_cb = exi_cb;
1275
1276 card->card_unlock_cb = __unlocked_callback;
1277 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) {
1278 _CPU_ISR_Restore(level);
1279 return CARD_ERROR_BUSY;
1280 }
1281 card->card_unlock_cb = NULL;
1282
1283 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) {
1284 EXI_Unlock(chn);
1285 _CPU_ISR_Restore(level);
1286 return CARD_ERROR_NOCARD;
1287 }
1288
1289 __setuptimeout(card);
1290 _CPU_ISR_Restore(level);
1291
1292 return CARD_ERROR_READY;
1293 }
1294
__card_writepage(s32 chn,cardcallback callback)1295 static s32 __card_writepage(s32 chn,cardcallback callback)
1296 {
1297 s32 ret;
1298 card_block *card = NULL;
1299 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1300 card = &cardmap[chn];
1301
1302 card->cmd[0] = 0xf2;
1303 card->cmd[1] = (card->cmd_sector_addr>>17)&0x3f;
1304 card->cmd[2] = (card->cmd_sector_addr>>9)&0xff;
1305 card->cmd[3] = (card->cmd_sector_addr>>7)&3;
1306 card->cmd[4] = card->cmd_sector_addr&0x7f;
1307 card->cmd_len = 5;
1308 card->cmd_mode = EXI_WRITE;
1309 card->cmd_retries = 3;
1310
1311 ret = __card_start(chn,NULL,callback);
1312 if(ret<0) return ret;
1313
1314 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==1
1315 && EXI_Dma(chn,card->cmd_usr_buf,128,card->cmd_mode,__card_txhandler)==1) return CARD_ERROR_READY;
1316
1317 card->card_exi_cb = NULL;
1318 EXI_Deselect(chn);
1319 EXI_Unlock(chn);
1320 return CARD_ERROR_NOCARD;
1321 }
1322
__card_readsegment(s32 chn,cardcallback callback)1323 static s32 __card_readsegment(s32 chn,cardcallback callback)
1324 {
1325 u32 err;
1326 s32 ret;
1327 card_block *card = NULL;
1328 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1329 card = &cardmap[chn];
1330
1331 card->cmd[0] = 0x52;
1332 card->cmd[1] = (card->cmd_sector_addr&0xFE0000)>>17;
1333 card->cmd[2] = (card->cmd_sector_addr&0x01FE00)>>9;
1334 card->cmd[3] = (card->cmd_sector_addr&0x000180)>>7;
1335 card->cmd[4] = (card->cmd_sector_addr&0x00007F);
1336 card->cmd_len = 5;
1337 card->cmd_mode = EXI_READ;
1338 card->cmd_retries = 0;
1339
1340 ret = __card_start(chn,callback,NULL);
1341 if(ret<0) return ret;
1342
1343 err = 0;
1344 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) err |= 0x01;
1345 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
1346 if(EXI_Dma(chn,card->cmd_usr_buf,CARD_READSIZE,card->cmd_mode,__card_txhandler)==0) err |= 0x04;
1347
1348 if(err) {
1349 card->card_tx_cb = NULL;
1350 EXI_Deselect(chn);
1351 EXI_Unlock(chn);
1352 return CARD_ERROR_NOCARD;
1353 }
1354 return CARD_ERROR_READY;
1355 }
1356
__card_fatwritecallback(s32 chn,s32 result)1357 static void __card_fatwritecallback(s32 chn,s32 result)
1358 {
1359 s32 ret;
1360 cardcallback cb = NULL;
1361 struct card_bat *fat1,*fat2;
1362 card_block *card = &cardmap[chn];
1363 ret = result;
1364 if(ret>=0) {
1365 fat1 = (card->workarea+0x6000);
1366 fat2 = (card->workarea+0x8000);
1367 if(card->curr_fat==fat1) {
1368 card->curr_fat = fat2;
1369 memcpy(fat2,fat1,8192);
1370 } else {
1371 card->curr_fat = fat1;
1372 memcpy(fat1,fat2,8192);
1373 }
1374 }
1375 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1376 cb = card->card_erase_cb;
1377 if(cb) {
1378 card->card_erase_cb = NULL;
1379 cb(chn,ret);
1380 }
1381 }
1382
__card_dirwritecallback(s32 chn,s32 result)1383 static void __card_dirwritecallback(s32 chn,s32 result)
1384 {
1385 s32 ret;
1386 cardcallback cb = NULL;
1387 struct card_dat *dir1,*dir2;
1388 card_block *card = &cardmap[chn];
1389 ret = result;
1390 if(ret>=0) {
1391 dir1 = (card->workarea+0x2000);
1392 dir2 = (card->workarea+0x4000);
1393 if(card->curr_dir==dir1) {
1394 card->curr_dir = dir2;
1395 memcpy(dir2,dir1,8192);
1396 } else {
1397 card->curr_dir = dir1;
1398 memcpy(dir1,dir2,8192);
1399 }
1400 }
1401 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1402 cb = card->card_erase_cb;
1403 if(cb) {
1404 card->card_erase_cb = NULL;
1405 cb(chn,ret);
1406 }
1407 }
1408
__card_write(s32 chn,u32 address,u32 block_len,void * buffer,cardcallback callback)1409 static s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1410 {
1411 s32 ret;
1412 card_block *card = NULL;
1413 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1414 card = &cardmap[chn];
1415
1416 if(!card->attached) return CARD_ERROR_NOCARD;
1417
1418 card->cmd_blck_cnt = block_len>>7;
1419 card->cmd_sector_addr = address;
1420 card->cmd_usr_buf = buffer;
1421 card->card_xfer_cb = callback;
1422 ret = __card_writepage(chn,__blockwritecallback);
1423
1424 return ret;
1425 }
1426
__card_read(s32 chn,u32 address,u32 block_len,void * buffer,cardcallback callback)1427 static s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback)
1428 {
1429 s32 ret;
1430 card_block *card = NULL;
1431 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1432 card = &cardmap[chn];
1433
1434 card->cmd_sector_addr = address;
1435 card->cmd_blck_cnt = block_len>>9;
1436 card->cmd_usr_buf = buffer;
1437 card->card_xfer_cb = callback;
1438 ret = __card_readsegment(chn,__blockreadcallback);
1439
1440 return ret;
1441 }
1442
__card_formatregion(s32 chn,u32 encode,cardcallback callback)1443 static s32 __card_formatregion(s32 chn,u32 encode,cardcallback callback)
1444 {
1445 s32 ret;
1446 u16 tmp;
1447 u32 cnt;
1448 u64 time;
1449 u64 rnd_val;
1450 void *workarea,*memblock;
1451 cardcallback cb = NULL;
1452 card_block *card = NULL;
1453 struct card_header *header;
1454 struct card_bat *fatblock = NULL;
1455 struct card_dircntrl *dircntrl = NULL;
1456 syssram *sram;
1457 syssramex *sramex;
1458 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1459
1460 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
1461
1462 header = workarea = card->workarea;
1463 memset(header,0xff,8192);
1464
1465 tmp = _viReg[55];
1466 header->encoding = encode;
1467
1468 sram = __SYS_LockSram();
1469 header->serial[5] = sram->counter_bias;
1470 header->serial[6] = sram->lang;
1471 __SYS_UnlockSram(0);
1472
1473 cnt = 0;
1474 rnd_val = time = gettime();
1475 sramex = __SYS_LockSramEx();
1476 while(cnt<12) {
1477 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1478 ((u8*)header->serial)[cnt] = (sramex->flash_id[chn][cnt]+(u32)rnd_val);
1479
1480 rnd_val = (((rnd_val*(u64)0x0000000041c64e6d)+(u64)0x0000000000003039)>>16);
1481 rnd_val &= (u64)0x0000000000007fff;
1482
1483 cnt++;
1484 }
1485 __SYS_UnlockSramEx(0);
1486
1487 *(u64*)&(header->serial[3]) = time;
1488 header->serial[7] = tmp;
1489 header->device_id = 0;
1490 header->size = card->card_size;
1491 __card_checksum((u16*)header,508,&header->chksum1,&header->chksum2);
1492
1493 cnt = 0;
1494 while(cnt<2) {
1495 memblock = workarea+((cnt+1)<<13);
1496 dircntrl = memblock+8128;
1497 memset(memblock,0xff,8192);
1498 __card_checksum(memblock,8188,&dircntrl->chksum1,&dircntrl->chksum2);
1499 cnt++;
1500 }
1501
1502 cnt = 0;
1503 while(cnt<2) {
1504 memblock = workarea+((cnt+3)<<13);
1505 fatblock = memblock;
1506 memset(memblock,0,8192);
1507 fatblock->updated = cnt;
1508 fatblock->freeblocks = card->blocks-CARD_SYSAREA;
1509 fatblock->lastalloc = 4;
1510 __card_checksum(memblock+4,8188,&fatblock->chksum1,&fatblock->chksum2);
1511 cnt++;
1512 }
1513
1514 cb = callback;
1515 if(!cb) cb = __card_defaultapicallback;
1516 card->card_api_cb = cb;
1517
1518 DCStoreRange(card->workarea,0xA000);
1519
1520 card->format_step = 0;
1521 if((ret=__card_sectorerase(chn,(card->sector_size*card->format_step),__format_callback))>=0) return ret;
1522
1523 __card_putcntrlblock(card,ret);
1524 return ret;
1525 }
1526
__card_sectorerase(s32 chn,u32 sector,cardcallback callback)1527 static s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback)
1528 {
1529 s32 ret;
1530 card_block *card = NULL;
1531 if(chn<EXI_CHANNEL_0 || chn>= EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1532 card = &cardmap[chn];
1533
1534 if(sector%card->sector_size) return CARD_ERROR_FATAL_ERROR;
1535
1536 card->cmd[0] = 0xf1;
1537 card->cmd[1] = (sector>>17)&0x7f;
1538 card->cmd[2] = (sector>>9)&0xff;
1539 card->cmd_len = 3;
1540 card->cmd_mode = -1;
1541 card->cmd_retries = 3;
1542
1543 ret = __card_start(chn,NULL,callback);
1544 if(ret<0) return ret;
1545
1546 if(EXI_ImmEx(chn,card->cmd,card->cmd_len,EXI_WRITE)==0) {
1547 card->card_exi_cb = NULL;
1548 return CARD_ERROR_NOCARD;
1549 }
1550
1551 EXI_Deselect(chn);
1552 EXI_Unlock(chn);
1553 return ret;
1554 }
1555
__card_faterasecallback(s32 chn,s32 result)1556 static void __card_faterasecallback(s32 chn,s32 result)
1557 {
1558 s32 ret;
1559 cardcallback cb = NULL;
1560 struct card_bat *fatblock = NULL;
1561 card_block *card = &cardmap[chn];
1562 ret = result;
1563 if(ret>=0) {
1564 fatblock = __card_getbatblock(card);
1565 if((ret=__card_write(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,8192,fatblock,__card_fatwritecallback))>=0) return;
1566 }
1567 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1568
1569 cb = card->card_erase_cb;
1570 if(cb) {
1571 card->card_erase_cb = NULL;
1572 cb(chn,ret);
1573 }
1574 }
1575
__card_direrasecallback(s32 chn,s32 result)1576 static void __card_direrasecallback(s32 chn,s32 result)
1577 {
1578 s32 ret;
1579 cardcallback cb = NULL;
1580 struct card_dat *dirblock = NULL;
1581 card_block *card = &cardmap[chn];
1582 ret = result;
1583 if(ret>=0) {
1584 dirblock = __card_getdirblock(card);
1585 if((ret=__card_write(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,8192,dirblock,__card_dirwritecallback))>=0) return;
1586 }
1587 if(!card->card_api_cb) __card_putcntrlblock(card,ret);
1588
1589 cb = card->card_erase_cb;
1590 if(cb) {
1591 card->card_erase_cb = NULL;
1592 cb(chn,ret);
1593 }
1594 }
1595
__card_createfatcallback(s32 chn,s32 result)1596 static void __card_createfatcallback(s32 chn,s32 result)
1597 {
1598 s32 ret;
1599 cardcallback cb = NULL;
1600 card_file *file = NULL;
1601 struct card_direntry *entry = NULL;
1602 struct card_dat *dirblock = NULL;
1603 card_block *card = &cardmap[chn];
1604 cb = card->card_api_cb;
1605 card->card_api_cb = NULL;
1606
1607 dirblock = __card_getdirblock(card);
1608
1609 file = card->curr_file;
1610 entry = &dirblock->entries[file->filenum];
1611
1612 memset(entry->gamecode,0,4);
1613 memset(entry->company,0,2);
1614 if(card_gamecode[0]!=0xff) memcpy(entry->gamecode,card_gamecode,4);
1615 if(card_gamecode[0]!=0xff) memcpy(entry->company,card_company,2);
1616 entry->block = card->curr_fileblock;
1617 entry->permission = CARD_ATTRIB_PUBLIC;
1618 entry->pad_00 = 0xff;
1619 entry->copytimes = 0;
1620 entry->iconaddr = -1;
1621 entry->iconfmt = 0;
1622 entry->iconspeed = 0;
1623 entry->pad_01 = 0xffff;
1624 entry->iconspeed = (entry->iconspeed&~CARD_SPEED_MASK)|CARD_SPEED_FAST;
1625 entry->lastmodified = time(NULL);
1626
1627 file->offset = 0;
1628 file->iblock = card->curr_fileblock;
1629
1630 if((ret=__card_updatedir(chn,cb))<0) {
1631 __card_putcntrlblock(card,ret);
1632 if(cb) cb(chn,ret);
1633 }
1634 }
1635
__card_updatefat(s32 chn,struct card_bat * fatblock,cardcallback callback)1636 static s32 __card_updatefat(s32 chn,struct card_bat *fatblock,cardcallback callback)
1637 {
1638 card_block *card = NULL;
1639 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1640 card = &cardmap[chn];
1641
1642 if(!card->attached) return CARD_ERROR_NOCARD;
1643
1644 ++fatblock->updated;
1645 __card_checksum((u16*)(((u32)fatblock)+4),0x1ffc,&fatblock->chksum1,&fatblock->chksum2);
1646 DCStoreRange(fatblock,8192);
1647 card->card_erase_cb = callback;
1648
1649 return __card_sectorerase(chn,(((u32)fatblock-(u32)card->workarea)>>13)*card->sector_size,__card_faterasecallback);
1650 }
1651
__card_updatedir(s32 chn,cardcallback callback)1652 static s32 __card_updatedir(s32 chn,cardcallback callback)
1653 {
1654 card_block *card = NULL;
1655 void *dirblock = NULL;
1656 struct card_dircntrl *dircntrl = NULL;
1657 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
1658 card = &cardmap[chn];
1659
1660 if(!card->attached) return CARD_ERROR_NOCARD;
1661
1662 dirblock = __card_getdirblock(card);
1663 dircntrl = dirblock+8128;
1664 ++dircntrl->updated;
1665 __card_checksum((u16*)dirblock,0x1ffc,&dircntrl->chksum1,&dircntrl->chksum2);
1666 DCStoreRange(dirblock,0x2000);
1667 card->card_erase_cb = callback;
1668
1669 return __card_sectorerase(chn,(((u32)dirblock-(u32)card->workarea)>>13)*card->sector_size,__card_direrasecallback);
1670 }
1671
__card_dounmount(s32 chn,s32 result)1672 static void __card_dounmount(s32 chn,s32 result)
1673 {
1674 u32 level;
1675 card_block *card;
1676
1677 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return;
1678 card = &cardmap[chn];
1679
1680 _CPU_ISR_Disable(level);
1681 if(card->attached) {
1682 card->attached = 0;
1683 card->mount_step = 0;
1684 card->result = result;
1685 EXI_RegisterEXICallback(chn,NULL);
1686 EXI_Detach(chn);
1687 SYS_CancelAlarm(card->timeout_svc);
1688 }
1689 _CPU_ISR_Restore(level);
1690 }
1691
__card_domount(s32 chn)1692 static s32 __card_domount(s32 chn)
1693 {
1694 u8 status,kval;
1695 s32 ret = CARD_ERROR_READY;
1696 u32 sum;
1697 u32 id,idx,cnt;
1698 card_block *card;
1699 syssramex *sramex;
1700
1701 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
1702 card = &cardmap[chn];
1703 if(card->mount_step==0) {
1704 ret = 0;
1705 id = 0;
1706 if(EXI_GetID(chn,EXI_DEVICE_0,&id)==0) ret = CARD_ERROR_NOCARD;
1707 else if(!__card_iscard(id)) ret = CARD_ERROR_WRONGDEVICE;
1708
1709 if(ret<0) goto exit;
1710 card->cid = id;
1711 card->card_size = (id&0xfc);
1712 if(card->card_size) {
1713 idx = _ROTL(id,23)&0x1c;
1714 card->sector_size = card_sector_size[idx>>2];
1715 card->blocks = ((card->card_size<<20)>>3)/card->sector_size;
1716
1717 if(card->blocks>0x0008) {
1718 idx = _ROTL(id,26)&0x1c;
1719 card->latency = card_latency[idx>>2];
1720
1721 if((ret=__card_clearstatus(chn))<0) goto exit;
1722 if((ret=__card_readstatus(chn,&status))<0) goto exit;
1723
1724 if(EXI_Probe(chn)==0) {
1725 ret = CARD_ERROR_NOCARD;
1726 goto exit;
1727 }
1728 if(!(status&CARD_STATUS_UNLOCKED)) {
1729 if((ret=__dounlock(chn,card->key))<0) goto exit;
1730
1731 cnt = 0;
1732 sum = 0;
1733 sramex = __SYS_LockSramEx();
1734 while(cnt<12) {
1735 kval = ((u8*)card->key)[cnt];
1736 sramex->flash_id[chn][cnt] = kval;
1737 sum += kval;
1738 cnt++;
1739 }
1740 sum = (sum^-1)&0xff;
1741 sramex->flashID_chksum[chn] = (sum<<8)|sum;
1742 __SYS_UnlockSramEx(1);
1743 return ret;
1744 }
1745 card->mount_step = 1;
1746
1747 cnt = 0;
1748 sum = 0;
1749 sramex = __SYS_LockSramEx();
1750 while(cnt<12) {
1751 sum += sramex->flash_id[chn][cnt];
1752 cnt++;
1753 }
1754 cnt = sramex->flashID_chksum[chn];
1755 __SYS_UnlockSramEx(0);
1756
1757 sum = (sum^-1)&0xff;
1758 sum |= (sum<<8);
1759 if(cnt!=sum) {
1760 ret = CARD_ERROR_IOERROR;
1761 goto exit;
1762 }
1763 }
1764 }
1765 }
1766 if(card->mount_step==1) {
1767 card->mount_step = 2;
1768 if((ret=__card_enableinterrupt(chn,1))<0) goto exit;
1769 EXI_RegisterEXICallback(chn,__card_exihandler);
1770 EXI_Unlock(chn);
1771
1772 DCInvalidateRange(card->workarea,0xA000);
1773 }
1774
1775 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;
1776 return ret;
1777
1778 exit:
1779 EXI_Unlock(chn);
1780 __card_dounmount(chn,ret);
1781
1782 return ret;
1783 }
1784
__card_mountcallback(s32 chn,s32 result)1785 static void __card_mountcallback(s32 chn,s32 result)
1786 {
1787 s32 ret;
1788 cardcallback cb;
1789 card_block *card = &cardmap[chn];
1790
1791 ret = result;
1792 if(ret==CARD_ERROR_NOCARD || ret==CARD_ERROR_IOERROR) {
1793 __card_dounmount(chn,ret);
1794 __card_putcntrlblock(card,ret);
1795 }else if(ret==CARD_ERROR_UNLOCKED) {
1796 if((ret=__card_domount(chn))>=0) return;
1797 } else {
1798 if((++card->mount_step)<7) {
1799 if((ret=__card_domount(chn))>=0) return;
1800 } else {
1801 ret = __card_verify(card);
1802 __card_putcntrlblock(card,ret);
1803 }
1804 }
1805
1806 cb = card->card_api_cb;
1807 card->card_api_cb = NULL;
1808 if(cb) cb(chn,ret);
1809 }
1810
__card_srand(u32 val)1811 static __inline__ void __card_srand(u32 val)
1812 {
1813 crand_next = val;
1814 }
1815
__card_rand()1816 static __inline__ u32 __card_rand()
1817 {
1818 crand_next = (crand_next*0x41C64E6D)+12345;
1819 return _SHIFTR(crand_next,16,15);
1820 }
1821
__card_initval()1822 static u32 __card_initval()
1823 {
1824 u32 ticks = gettick();
1825
1826 __card_srand(ticks);
1827 return ((0x7FEC8000|__card_rand())&~0x00000fff);
1828 }
1829
__card_dummylen()1830 static u32 __card_dummylen()
1831 {
1832 u32 ticks = gettick();
1833 u32 val = 0,cnt = 0,shift = 1;
1834
1835 __card_srand(ticks);
1836 val = (__card_rand()&0x1f)+1;
1837
1838 do {
1839 ticks = gettick();
1840 val = ticks<<shift;
1841 shift++;
1842 if(shift>16) shift = 1;
1843 __card_srand(val);
1844 val = (__card_rand()&0x1f)+1;
1845 cnt++;
1846 }while(val<4 && cnt<10);
1847 if(val<4) val = 4;
1848
1849 return val;
1850
1851 }
1852
exnor_1st(u32 a,u32 b)1853 static u32 exnor_1st(u32 a,u32 b)
1854 {
1855 u32 c,d,e,f,r1,r2,r3,r4;
1856
1857 c = 0;
1858 while(c<b) {
1859 d = (a>>23);
1860 e = (a>>15);
1861 f = (a>>7);
1862 r1 = (a^f);
1863 r2 = (e^r1);
1864 r3 = ~(d^r2); //eqv(d,r2)
1865 e = (a>>1);
1866 r4 = ((r3<<30)&0x40000000);
1867 a = (e|r4);
1868 c++;
1869 };
1870 return a;
1871 }
1872
exnor(u32 a,u32 b)1873 static u32 exnor(u32 a,u32 b)
1874 {
1875 u32 c,d,e,f,r1,r2,r3,r4;
1876
1877 c = 0;
1878 while(c<b) {
1879 d = (a<<23);
1880 e = (a<<15);
1881 f = (a<<7);
1882 r1 = (a^f);
1883 r2 = (e^r1);
1884 r3 = ~(d^r2); //eqv(d,r2)
1885 e = (a<<1);
1886 r4 = ((r3>>30)&0x02);
1887 a = (e|r4);
1888 c++;
1889 };
1890 return a;
1891 }
1892
bitrev(u32 val)1893 static u32 bitrev(u32 val)
1894 {
1895 u32 cnt,val1,ret,shift,shift1;
1896
1897 cnt = 0;
1898 ret = 0;
1899 shift = 1;
1900 shift1 = 0;
1901 while(cnt<32) {
1902 if(cnt<=15) {
1903 val1 = val&(1<<cnt);
1904 val1 <<= ((31-cnt)-shift1);
1905 ret |= val1;
1906 shift1++;
1907 } else if(cnt==31) {
1908 val1 = val>>31;
1909 ret |= val1;
1910 } else {
1911 val1 = 1;
1912 val1 = val&(1<<cnt);
1913 val1 >>= shift;
1914 ret |= val1;
1915 shift += 2;
1916 }
1917 cnt++;
1918 }
1919 return ret;
1920 }
1921
__card_readarrayunlock(s32 chn,u32 address,void * buffer,u32 len,u32 flag)1922 static s32 __card_readarrayunlock(s32 chn,u32 address,void *buffer,u32 len,u32 flag)
1923 {
1924 s32 ret;
1925 u32 err;
1926 u8 regbuf[5];
1927 card_block *card = &cardmap[chn];
1928 if(EXI_Select(chn,EXI_DEVICE_0,EXI_SPEED16MHZ)==0) return CARD_ERROR_NOCARD;
1929
1930 address &= 0xFFFFF000;
1931 memset(regbuf,0,5);
1932
1933 regbuf[0] = 0x52;
1934 if(!flag) {
1935 regbuf[1] = ((address&0x60000000)>>29)&0xff;
1936 regbuf[2] = ((address&0x1FE00000)>>21)&0xff;
1937 regbuf[3] = ((address&0x00180000)>>19)&0xff;
1938 regbuf[4] = ((address&0x0007F000)>>12)&0xff;
1939 } else {
1940 regbuf[1] = (address>>24)&0xff;
1941 regbuf[2] = ((address&0x00FF0000)>>16)&0xff;
1942 }
1943
1944 err = 0;
1945 if(EXI_ImmEx(chn,regbuf,5,EXI_WRITE)==0) err |= 0x01;
1946 if(EXI_ImmEx(chn,card->workarea+CARD_READSIZE,card->latency,EXI_WRITE)==0) err |= 0x02;
1947 if(EXI_ImmEx(chn,buffer,len,EXI_READ)==0) err |= 0x04;
1948 if(EXI_Deselect(chn)==0) err |= 0x08;
1949
1950 if(err) ret = CARD_ERROR_NOCARD;
1951 else ret = CARD_ERROR_READY;
1952
1953 return ret;
1954 }
1955
__dsp_initcallback(dsptask_t * task)1956 static void __dsp_initcallback(dsptask_t *task)
1957 {
1958 u32 chn;
1959 card_block *card = NULL;
1960 chn = 0;
1961 while(chn<EXI_CHANNEL_2) {
1962 card = &cardmap[chn];
1963 if(&card->dsp_task==task) break;
1964 chn++;
1965 }
1966 if(chn>=EXI_CHANNEL_2) return;
1967
1968 DSP_SendMailTo(0xFF000000);
1969 while(DSP_CheckMailTo());
1970 DSP_SendMailTo((u32)card->workarea);
1971 while(DSP_CheckMailTo());
1972 }
1973
1974 static u8 tmp_buffer[64] ATTRIBUTE_ALIGN(32);
__dsp_donecallback(dsptask_t * task)1975 static void __dsp_donecallback(dsptask_t *task)
1976 {
1977
1978 u8 status;
1979 s32 ret;
1980 u32 chn,len,key;
1981 u32 workarea,val;
1982 card_block *card = NULL;
1983 chn = 0;
1984 while(chn<EXI_CHANNEL_2) {
1985 card = &cardmap[chn];
1986 if(&card->dsp_task==task) break;
1987 chn++;
1988 }
1989 if(chn>=EXI_CHANNEL_2) return;
1990
1991 workarea = (u32)card->workarea;
1992 workarea = ((workarea+47)&~0x1f);
1993 key = ((u32*)workarea)[8];
1994
1995 val = (key^card->cipher)&~0xffff;
1996 len = __card_dummylen();
1997 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
1998 EXI_Unlock(chn);
1999 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2000 return;
2001 }
2002
2003 val = exnor(card->cipher,((len+card->latency+4)<<3)+1);
2004 {
2005 u32 a,b,c,r1,r2,r3;
2006 a = (val<<23);
2007 b = (val<<15);
2008 c = (val<<7);
2009 r1 = (val^c);
2010 r2 = (b^r1);
2011 r3 = ~(a^r2); //eqv(a,r2)
2012 r1 = (val|(r3>>31));
2013 card->cipher = r1;
2014 }
2015
2016 val = ((key<<16)^card->cipher)&~0xffff;
2017 len = __card_dummylen();
2018 if(__card_readarrayunlock(chn,val,tmp_buffer,len,1)<0) {
2019 EXI_Unlock(chn);
2020 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2021 return;
2022 }
2023
2024 ret = __card_readstatus(chn,&status);
2025 if(EXI_Probe(chn)==0) {
2026 EXI_Unlock(chn);
2027 __card_mountcallback(chn,CARD_ERROR_NOCARD);
2028 return;
2029 }
2030 if(!ret && !(status&CARD_STATUS_UNLOCKED)) {
2031 EXI_Unlock(chn);
2032 ret = CARD_ERROR_IOERROR;
2033 }
2034 __card_mountcallback(chn,ret);
2035 }
2036
__dounlock(s32 chn,u32 * key)2037 static s32 __dounlock(s32 chn,u32 *key)
2038 {
2039 u32 array_addr,len,val;
2040 u32 a,b,c,d,e;
2041 card_block *card = &cardmap[chn];
2042 u32 *workarea = card->workarea;
2043 u32 *cipher1 = (u32*)(((u32)card->workarea+47)&~31);
2044 u32 *cipher2 = &cipher1[8];
2045 array_addr = __card_initval();
2046 len = __card_dummylen();
2047
2048 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len,0)<0) return CARD_ERROR_NOCARD;
2049
2050 val = exnor_1st(array_addr,(len<<3)+1);
2051 {
2052 u32 a,b,c,r1,r2,r3;
2053 a = (val>>23);
2054 b = (val>>15);
2055 c = (val>>7);
2056 r1 = (val^c);
2057 r2 = (b^r1);
2058 r3 = ~(a^r2); //eqv(a,r2)
2059 r1 = (val|(r3<<31));
2060 card->cipher = r1;
2061 }
2062 card->cipher = bitrev(card->cipher);
2063
2064 array_addr = 0;
2065 len = __card_dummylen();
2066 if(__card_readarrayunlock(chn,array_addr,tmp_buffer,len+20,1)<0) return CARD_ERROR_NOCARD;
2067
2068 a = ((u32*)tmp_buffer)[0];
2069 b = ((u32*)tmp_buffer)[1];
2070 c = ((u32*)tmp_buffer)[2];
2071 d = ((u32*)tmp_buffer)[3];
2072 e = ((u32*)tmp_buffer)[4];
2073
2074 a = a^card->cipher;
2075 val = exnor(card->cipher,32);
2076 {
2077 u32 a,b,c,r1,r2,r3;
2078 a = (val<<23);
2079 b = (val<<15);
2080 c = (val<<7);
2081 r1 = (val^c);
2082 r2 = (b^r1);
2083 r3 = ~(a^r2); //eqv(a,r2)
2084 r1 = (val|(r3>>31));
2085 card->cipher = r1;
2086 }
2087
2088 b = b^card->cipher;
2089 val = exnor(card->cipher,32);
2090 {
2091 u32 a,b,c,r1,r2,r3;
2092 a = (val<<23);
2093 b = (val<<15);
2094 c = (val<<7);
2095 r1 = (val^c);
2096 r2 = (b^r1);
2097 r3 = ~(a^r2); //eqv(a,r2)
2098 r1 = (val|(r3>>31));
2099 card->cipher = r1;
2100 }
2101
2102 c = c^card->cipher;
2103 val = exnor(card->cipher,32);
2104 {
2105 u32 a,b,c,r1,r2,r3;
2106 a = (val<<23);
2107 b = (val<<15);
2108 c = (val<<7);
2109 r1 = (val^c);
2110 r2 = (b^r1);
2111 r3 = ~(a^r2); //eqv(a,r2)
2112 r1 = (val|(r3>>31));
2113 card->cipher = r1;
2114 }
2115
2116 d = d^card->cipher;
2117 val = exnor(card->cipher,32);
2118 {
2119 u32 a,b,c,r1,r2,r3;
2120 a = (val<<23);
2121 b = (val<<15);
2122 c = (val<<7);
2123 r1 = (val^c);
2124 r2 = (b^r1);
2125 r3 = ~(a^r2); //eqv(a,r2)
2126 r1 = (val|(r3>>31));
2127 card->cipher = r1;
2128 }
2129
2130 e = e^card->cipher;
2131 val = exnor(card->cipher,(len<<3));
2132 {
2133 u32 a,b,c,r1,r2,r3;
2134 a = (val<<23);
2135 b = (val<<15);
2136 c = (val<<7);
2137 r1 = (val^c);
2138 r2 = (b^r1);
2139 r3 = ~(a^r2); //eqv(a,r2)
2140 r1 = (val|(r3>>31));
2141 card->cipher = r1;
2142 }
2143
2144 val = exnor(card->cipher,33);
2145 {
2146 u32 a,b,c,r1,r2,r3;
2147 a = (val<<23);
2148 b = (val<<15);
2149 c = (val<<7);
2150 r1 = (val^c);
2151 r2 = (b^r1);
2152 r3 = ~(a^r2); //eqv(a,r2)
2153 r1 = (val|(r3>>31));
2154 card->cipher = r1;
2155 }
2156
2157 cipher1[0] = d;
2158 cipher1[1] = e;
2159 workarea[0] = (u32)cipher1;
2160 workarea[1] = 8;
2161 #ifdef HW_RVL
2162 workarea[2] = 0x10000000; // use MEM2 base
2163 #else
2164 workarea[2] = 0; // use ARAM base
2165 #endif
2166 workarea[3] = (u32)cipher2;
2167 DCFlushRange(cipher1,8);
2168 DCInvalidateRange(cipher2,4);
2169 DCFlushRange(workarea,16);
2170
2171 card->dsp_task.prio = 255;
2172 card->dsp_task.iram_maddr = (u16*)MEM_VIRTUAL_TO_PHYSICAL(_cardunlockdata);
2173 card->dsp_task.iram_len = 352;
2174 card->dsp_task.iram_addr = 0x0000;
2175 card->dsp_task.init_vec = 16;
2176 card->dsp_task.res_cb = NULL;
2177 card->dsp_task.req_cb = NULL;
2178 card->dsp_task.init_cb = __dsp_initcallback;
2179 card->dsp_task.done_cb = __dsp_donecallback;
2180 DSP_AddTask(&card->dsp_task);
2181
2182 key[0] = a;
2183 key[1] = b;
2184 key[2] = c;
2185
2186 return CARD_ERROR_READY;
2187 }
2188
CARD_Init(const char * gamecode,const char * company)2189 s32 CARD_Init(const char *gamecode,const char *company)
2190 {
2191 u32 i,level;
2192
2193 if(card_inited) return CARD_ERROR_READY;
2194 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4);
2195 if(company && strlen(company)<=2) memcpy(card_company,company,2);
2196
2197 _CPU_ISR_Disable(level);
2198 DSP_Init();
2199
2200 memset(cardmap,0,sizeof(card_block)*2);
2201 for(i=0;i<2;i++) {
2202 cardmap[i].result = CARD_ERROR_NOCARD;
2203 LWP_InitQueue(&cardmap[i].wait_sync_queue);
2204 SYS_CreateAlarm(&cardmap[i].timeout_svc);
2205 }
2206 SYS_RegisterResetFunc(&card_resetinfo);
2207 card_inited = 1;
2208 _CPU_ISR_Restore(level);
2209 return CARD_ERROR_READY;
2210 }
2211
CARD_Probe(s32 chn)2212 s32 CARD_Probe(s32 chn)
2213 {
2214 return EXI_Probe(chn);
2215 }
2216
CARD_ProbeEx(s32 chn,s32 * mem_size,s32 * sect_size)2217 s32 CARD_ProbeEx(s32 chn,s32 *mem_size,s32 *sect_size)
2218 {
2219 s32 ret;
2220 u32 level,card_id;
2221 card_block *card = NULL;
2222 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2223 card = &cardmap[chn];
2224
2225 _CPU_ISR_Disable(level);
2226 ret = EXI_ProbeEx(chn);
2227 if(ret<=0) {
2228 if(!ret) ret = CARD_ERROR_BUSY;
2229 else ret = CARD_ERROR_NOCARD;
2230 _CPU_ISR_Restore(level);
2231 return ret;
2232 }
2233
2234 if(card->attached) {
2235 if(card->mount_step<1) {
2236 _CPU_ISR_Restore(level);
2237 return CARD_ERROR_BUSY;
2238 }
2239 if(mem_size) *mem_size = card->card_size;
2240 if(sect_size) *sect_size = card->sector_size;
2241
2242 _CPU_ISR_Restore(level);
2243 return CARD_ERROR_READY;
2244 }
2245
2246 if(EXI_GetState(chn)&EXI_FLAG_ATTACH) ret = CARD_ERROR_WRONGDEVICE;
2247 else {
2248 ret = CARD_ERROR_BUSY;
2249 if(EXI_GetID(chn,EXI_DEVICE_0,&card_id)) {
2250 if(!__card_iscard(card_id)) ret = CARD_ERROR_WRONGDEVICE;
2251 else {
2252 if(mem_size) *mem_size = card_id&0xFC;
2253 if(sect_size) {
2254 u32 idx = _ROTL(card_id,23)&0x1c;
2255 *sect_size = card_sector_size[idx>>2];
2256 }
2257 ret = CARD_ERROR_READY;
2258 }
2259 }
2260 }
2261
2262 _CPU_ISR_Restore(level);
2263 return ret;
2264 }
2265
CARD_MountAsync(s32 chn,void * workarea,cardcallback detach_cb,cardcallback attach_cb)2266 s32 CARD_MountAsync(s32 chn,void *workarea,cardcallback detach_cb,cardcallback attach_cb)
2267 {
2268 s32 ret = CARD_ERROR_READY;
2269 u32 level;
2270 cardcallback attachcb = NULL;
2271 card_block *card = NULL;
2272 if(!workarea) return CARD_ERROR_NOCARD;
2273 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
2274 card = &cardmap[chn];
2275
2276 _CPU_ISR_Disable(level);
2277 if(card->result==CARD_ERROR_BUSY) {
2278 _CPU_ISR_Restore(level);
2279 return CARD_ERROR_BUSY;
2280 }
2281 if(card->attached || !(EXI_GetState(chn)&EXI_FLAG_ATTACH)) {
2282 card->result = CARD_ERROR_BUSY;
2283 card->workarea = workarea;
2284 card->card_ext_cb = detach_cb;
2285
2286 attachcb = attach_cb;
2287 if(!attachcb) attachcb = __card_defaultapicallback;
2288 card->card_api_cb = attachcb;
2289 card->card_exi_cb = NULL;
2290
2291 if(!card->attached) {
2292 if(EXI_Attach(chn,__card_exthandler)==0) {
2293 card->result = CARD_ERROR_NOCARD;
2294 _CPU_ISR_Restore(level);
2295 return CARD_ERROR_NOCARD;
2296 }
2297 }
2298 card->mount_step = 0;
2299 card->attached = 1;
2300 EXI_RegisterEXICallback(chn,NULL);
2301 SYS_CancelAlarm(card->timeout_svc);
2302 card->curr_dir = NULL;
2303 card->curr_fat = NULL;
2304 _CPU_ISR_Restore(level);
2305
2306 card->card_unlock_cb = __card_mountcallback;
2307 if(EXI_Lock(chn,EXI_DEVICE_0,__card_unlockedhandler)==0) return 0;
2308
2309 card->card_unlock_cb = NULL;
2310 __card_domount(chn);
2311 return 1;
2312 }
2313
2314 ret = CARD_ERROR_WRONGDEVICE;
2315 _CPU_ISR_Restore(level);
2316 return ret;
2317 }
2318
CARD_Mount(s32 chn,void * workarea,cardcallback detach_cb)2319 s32 CARD_Mount(s32 chn,void *workarea,cardcallback detach_cb)
2320 {
2321 s32 ret;
2322 if((ret=CARD_MountAsync(chn,workarea,detach_cb,__card_synccallback))>=0) {
2323 ret = __card_sync(chn);
2324 }
2325 return ret;
2326 }
2327
CARD_Unmount(s32 chn)2328 s32 CARD_Unmount(s32 chn)
2329 {
2330 s32 ret;
2331 card_block *card = NULL;
2332
2333 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2334
2335 if((ret=__card_getcntrlblock(chn,&card))<0) ret = CARD_ERROR_NOCARD;
2336
2337 __card_dounmount(chn,ret);
2338 return CARD_ERROR_READY;
2339 }
2340
CARD_ReadAsync(card_file * file,void * buffer,u32 len,u32 offset,cardcallback callback)2341 s32 CARD_ReadAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2342 {
2343 s32 ret;
2344 cardcallback cb = NULL;
2345 card_block *card = NULL;
2346
2347 if(len<=0 || (len&0x1ff) || (offset>0 && (offset&0x1ff))) return CARD_ERROR_FATAL_ERROR;
2348 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2349
2350 DCInvalidateRange(buffer,len);
2351
2352 cb = callback;
2353 if(!cb) cb = __card_defaultapicallback;
2354 card->card_api_cb = cb;
2355
2356 if(len>=(card->sector_size-(file->offset&(card->sector_size-1)))) len = (card->sector_size-(file->offset&(card->sector_size-1)));
2357
2358 if((ret=__card_read(file->chn,(file->iblock*card->sector_size),len,buffer,__read_callback))<0) {
2359 __card_putcntrlblock(card,ret);
2360 return ret;
2361 }
2362 return 0;
2363 }
2364
CARD_Read(card_file * file,void * buffer,u32 len,u32 offset)2365 s32 CARD_Read(card_file *file,void *buffer,u32 len,u32 offset)
2366 {
2367 s32 ret;
2368
2369 if((ret=CARD_ReadAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2370 ret = __card_sync(file->chn);
2371 }
2372 return ret;
2373 }
2374
CARD_WriteAsync(card_file * file,void * buffer,u32 len,u32 offset,cardcallback callback)2375 s32 CARD_WriteAsync(card_file *file,void *buffer,u32 len,u32 offset,cardcallback callback)
2376 {
2377 s32 ret;
2378 cardcallback cb = NULL;
2379 card_block *card = NULL;
2380
2381 if((ret=__card_seek(file,len,offset,&card))<0) return ret;
2382 if(len<0 || (len&(card->sector_size-1)) || (offset>0 && offset&(card->sector_size-1))) {
2383 __card_putcntrlblock(card,CARD_ERROR_FATAL_ERROR);
2384 return CARD_ERROR_FATAL_ERROR;
2385 }
2386
2387 DCStoreRange(buffer,len);
2388 cb = callback;
2389 if(!cb) cb = __card_defaultapicallback;
2390 card->card_api_cb = cb;
2391
2392 card->cmd_usr_buf = buffer;
2393 if((ret=__card_sectorerase(file->chn,(file->iblock*card->sector_size),__erase_callback))>=0) return ret;
2394 __card_putcntrlblock(card,ret);
2395 return ret;
2396 }
2397
CARD_Write(card_file * file,void * buffer,u32 len,u32 offset)2398 s32 CARD_Write(card_file *file,void *buffer,u32 len,u32 offset)
2399 {
2400 s32 ret;
2401
2402 if((ret=CARD_WriteAsync(file,buffer,len,offset,__card_synccallback))>=0) {
2403 ret = __card_sync(file->chn);
2404 }
2405 return ret;
2406 }
2407
CARD_CreateAsync(s32 chn,const char * filename,u32 size,card_file * file,cardcallback callback)2408 s32 CARD_CreateAsync(s32 chn,const char *filename,u32 size,card_file *file,cardcallback callback)
2409 {
2410 u32 i,len;
2411 s32 ret,filenum;
2412 cardcallback cb = NULL;
2413 card_block *card = NULL;
2414 struct card_bat *fatblock = NULL;
2415 struct card_dat *dirblock = NULL;
2416 struct card_direntry *entry = NULL;
2417 len = strlen(filename);
2418 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2419
2420 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2421 if(size<=0 || size%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2422
2423 dirblock = __card_getdirblock(card);
2424
2425 filenum = -1;
2426 entry = dirblock->entries;
2427 for(i=0;i<CARD_MAXFILES;i++) {
2428 if(entry[i].gamecode[0]==0xff) {
2429 if(filenum==-1) filenum = i;
2430 } else if(memcmp(entry[i].filename,filename,len)==0) {
2431 if((card_gamecode[0]==0xff || card_company[0]==0xff)
2432 || ((card_gamecode[0]!=0xff && memcmp(entry[i].gamecode,card_gamecode,4)==0)
2433 && (card_company[0]!=0xff && memcmp(entry[i].company,card_company,2)==0))) {
2434 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2435 return CARD_ERROR_EXIST;
2436 }
2437 }
2438 }
2439 if(filenum==-1) {
2440 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2441 return CARD_ERROR_NOENT;
2442 }
2443
2444 fatblock = __card_getbatblock(card);
2445 if((fatblock->freeblocks*card->sector_size)<size) {
2446 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2447 return CARD_ERROR_INSSPACE;
2448 }
2449
2450 cb = callback;
2451 if(!cb) cb = __card_defaultapicallback;
2452 card->card_api_cb = cb;
2453
2454 entry[filenum].length = size/card->sector_size;
2455 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2456 memcpy(entry[filenum].filename,filename,len+1);
2457
2458 card->curr_file = file;
2459 file->chn = chn;
2460 file->filenum = filenum;
2461 if((ret=__card_allocblock(chn,(size/card->sector_size),__card_createfatcallback))<0) {
2462 __card_putcntrlblock(card,ret);
2463 return ret;
2464 }
2465
2466 return 0;
2467 }
2468
CARD_Create(s32 chn,const char * filename,u32 size,card_file * file)2469 s32 CARD_Create(s32 chn,const char *filename,u32 size,card_file *file)
2470 {
2471 s32 ret;
2472
2473 if((ret=CARD_CreateAsync(chn,filename,size,file,__card_synccallback))>=0) {
2474 ret = __card_sync(chn);
2475 }
2476 return ret;
2477 }
2478
CARD_CreateEntryAsync(s32 chn,card_dir * direntry,card_file * file,cardcallback callback)2479 s32 CARD_CreateEntryAsync(s32 chn,card_dir *direntry,card_file *file,cardcallback callback)
2480 {
2481 u32 i,len;
2482 s32 ret,filenum;
2483 cardcallback cb = NULL;
2484 card_block *card = NULL;
2485 struct card_bat *fatblock = NULL;
2486 struct card_dat *dirblock = NULL;
2487 struct card_direntry *entry = NULL;
2488 len = strlen((const char*)direntry->filename);
2489 if(len>CARD_FILENAMELEN) return CARD_ERROR_NAMETOOLONG;
2490
2491 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2492 if(direntry->filelen<=0 || direntry->filelen%card->sector_size) return CARD_ERROR_FATAL_ERROR;
2493
2494 dirblock = __card_getdirblock(card);
2495
2496 filenum = -1;
2497 entry = dirblock->entries;
2498 for(i=0;i<CARD_MAXFILES;i++) {
2499 if(entry[i].gamecode[0]==0xff) {
2500 if(filenum==-1) filenum = i;
2501 } else if(memcmp(entry[i].filename,direntry->filename,len)==0) {
2502 if((entry->gamecode[0]==0xff || entry->company[0]==0xff)
2503 || ((entry->gamecode[0]!=0xff && memcmp(entry[i].gamecode,entry->gamecode,4)==0)
2504 && (entry->company[0]!=0xff && memcmp(entry[i].company,entry->company,2)==0))) {
2505 __card_putcntrlblock(card,CARD_ERROR_EXIST);
2506 return CARD_ERROR_EXIST;
2507 }
2508 }
2509 }
2510 if(filenum==-1) {
2511 __card_putcntrlblock(card,CARD_ERROR_NOENT);
2512 return CARD_ERROR_NOENT;
2513 }
2514
2515 fatblock = __card_getbatblock(card);
2516 if((fatblock->freeblocks*card->sector_size)<direntry->filelen) {
2517 __card_putcntrlblock(card,CARD_ERROR_INSSPACE);
2518 return CARD_ERROR_INSSPACE;
2519 }
2520
2521 cb = callback;
2522 if(!cb) cb = __card_defaultapicallback;
2523 card->card_api_cb = cb;
2524
2525 entry[filenum].length = direntry->filelen/card->sector_size;
2526 memset(entry[filenum].filename,0,CARD_FILENAMELEN);
2527 memcpy(entry[filenum].filename,direntry->filename,len+1);
2528
2529 card->curr_file = file;
2530 file->chn = chn;
2531 file->filenum = filenum;
2532 if((ret=__card_allocblock(chn,(direntry->filelen/card->sector_size),__card_createfatcallback))<0) {
2533 __card_putcntrlblock(card,ret);
2534 return ret;
2535 }
2536
2537 return 0;
2538 }
2539
CARD_CreateEntry(s32 chn,card_dir * direntry,card_file * file)2540 s32 CARD_CreateEntry(s32 chn,card_dir *direntry,card_file *file)
2541 {
2542 s32 ret;
2543
2544 if((ret=CARD_CreateEntryAsync(chn,direntry,file,__card_synccallback))>=0) {
2545 ret = __card_sync(chn);
2546 }
2547 return ret;
2548 }
2549
CARD_Open(s32 chn,const char * filename,card_file * file)2550 s32 CARD_Open(s32 chn,const char *filename,card_file *file)
2551 {
2552 s32 ret,fileno;
2553 struct card_dat *dirblock = NULL;
2554 card_block *card = NULL;
2555
2556 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2557
2558 file->filenum = -1;
2559 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2560 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2561 __card_putcntrlblock(card,ret);
2562 return ret;
2563 }
2564 dirblock = __card_getdirblock(card);
2565 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2566 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2567 return CARD_ERROR_BROKEN;
2568 }
2569 file->chn = chn;
2570 file->filenum = fileno;
2571 file->offset = 0;
2572 file->len = dirblock->entries[fileno].length*card->sector_size;
2573 file->iblock = dirblock->entries[fileno].block;
2574
2575 __card_putcntrlblock(card,CARD_ERROR_READY);
2576 return CARD_ERROR_READY;
2577 }
2578
CARD_OpenEntry(s32 chn,card_dir * entry,card_file * file)2579 s32 CARD_OpenEntry(s32 chn,card_dir *entry,card_file *file)
2580 {
2581 s32 ret,fileno;
2582 struct card_dat *dirblock = NULL;
2583 card_block *card = NULL;
2584
2585 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2586
2587 file->filenum = -1;
2588 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2589 if((ret=__card_getfilenum(card,(const char*)entry->filename,(const char*)entry->gamecode,(const char*)entry->company,&fileno))<0) {
2590 __card_putcntrlblock(card,ret);
2591 return ret;
2592 }
2593
2594 dirblock = __card_getdirblock(card);
2595 if(dirblock->entries[fileno].block<5 || dirblock->entries[fileno].block>=card->blocks) {
2596 __card_putcntrlblock(card,CARD_ERROR_BROKEN);
2597 return CARD_ERROR_BROKEN;
2598 }
2599
2600 file->chn = chn;
2601 file->filenum = entry->fileno;
2602 file->offset = 0;
2603 file->len = dirblock->entries[fileno].length*card->sector_size;
2604 file->iblock = dirblock->entries[fileno].block;
2605
2606 __card_putcntrlblock(card,CARD_ERROR_READY);
2607 return CARD_ERROR_READY;
2608 }
2609
CARD_Close(card_file * file)2610 s32 CARD_Close(card_file *file)
2611 {
2612 s32 ret;
2613 card_block *card = NULL;
2614
2615 if(file->chn<EXI_CHANNEL_0 || file->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2616 if(file->filenum<0 || file->filenum>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
2617 if((ret=__card_getcntrlblock(file->chn,&card))<0) return ret;
2618
2619 file->chn = -1;
2620 __card_putcntrlblock(card,CARD_ERROR_READY);
2621 return CARD_ERROR_READY;
2622 }
2623
CARD_DeleteAsync(s32 chn,const char * filename,cardcallback callback)2624 s32 CARD_DeleteAsync(s32 chn,const char *filename,cardcallback callback)
2625 {
2626 s32 ret,fileno;
2627 cardcallback cb = NULL;
2628 card_block *card = NULL;
2629 struct card_dat *dirblock = NULL;
2630 struct card_direntry *entry = NULL;
2631 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2632 if((ret=__card_getfilenum(card,filename,(const char*)card_gamecode,(const char*)card_company,&fileno))<0) {
2633 __card_putcntrlblock(card,ret);
2634 return ret;
2635 }
2636
2637 dirblock = __card_getdirblock(card);
2638 entry = &dirblock->entries[fileno];
2639
2640 card->curr_fileblock = entry->block;
2641 memset(entry,-1,sizeof(struct card_direntry));
2642
2643 cb = callback;
2644 if(!cb) cb = __card_defaultapicallback;
2645 card->card_api_cb = cb;
2646
2647 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2648
2649 __card_putcntrlblock(card,ret);
2650 return ret;
2651 }
2652
CARD_Delete(s32 chn,const char * filename)2653 s32 CARD_Delete(s32 chn,const char *filename)
2654 {
2655 s32 ret;
2656 if((ret=CARD_DeleteAsync(chn,filename,__card_synccallback))>=0) {
2657 ret = __card_sync(chn);
2658 }
2659 return ret;
2660 }
2661
CARD_DeleteEntryAsync(s32 chn,card_dir * dir_entry,cardcallback callback)2662 s32 CARD_DeleteEntryAsync(s32 chn,card_dir *dir_entry,cardcallback callback)
2663 {
2664 s32 ret;
2665 cardcallback cb = NULL;
2666 card_block *card = NULL;
2667 struct card_dat *dirblock = NULL;
2668 struct card_direntry *entry = NULL;
2669 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2670 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2671
2672 dirblock = __card_getdirblock(card);
2673 entry = &dirblock->entries[dir_entry->fileno];
2674
2675 card->curr_fileblock = entry->block;
2676 memset(entry,-1,sizeof(struct card_direntry));
2677
2678 cb = callback;
2679 if(!cb) cb = __card_defaultapicallback;
2680 card->card_api_cb = cb;
2681
2682 if((ret=__card_updatedir(chn,__delete_callback))>=0) return ret;
2683
2684 __card_putcntrlblock(card,ret);
2685 return ret;
2686 }
2687
CARD_DeleteEntry(s32 chn,card_dir * dir_entry)2688 s32 CARD_DeleteEntry(s32 chn,card_dir *dir_entry)
2689 {
2690 s32 ret;
2691 if((ret=CARD_DeleteEntryAsync(chn,dir_entry,__card_synccallback))>=0) {
2692 ret = __card_sync(chn);
2693 }
2694 return ret;
2695 }
2696
CARD_FormatAsync(s32 chn,cardcallback callback)2697 s32 CARD_FormatAsync(s32 chn,cardcallback callback)
2698 {
2699 u32 enc;
2700
2701 enc = SYS_GetFontEncoding();
2702 return __card_formatregion(chn,enc,callback);
2703 }
2704
CARD_Format(s32 chn)2705 s32 CARD_Format(s32 chn)
2706 {
2707 s32 ret;
2708 u32 enc;
2709
2710 enc = SYS_GetFontEncoding();
2711 if((ret=__card_formatregion(chn,enc,__card_synccallback))>=0) {
2712 ret = __card_sync(chn);
2713 }
2714 return ret;
2715 }
2716
CARD_GetErrorCode(s32 chn)2717 s32 CARD_GetErrorCode(s32 chn)
2718 {
2719 card_block *card = NULL;
2720
2721 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2722 card = &cardmap[chn];
2723 return card->result;
2724 }
2725
__card_findnext(card_dir * dir)2726 s32 __card_findnext(card_dir *dir)
2727 {
2728 s32 ret;
2729 struct card_dat *dirblock = NULL;
2730 struct card_direntry *entries = NULL;
2731 card_block *card = NULL;
2732
2733 if(dir->chn<EXI_CHANNEL_0 || dir->chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2734 if(dir->fileno>=CARD_MAXFILES) return CARD_ERROR_NOFILE;
2735 if((ret=__card_getcntrlblock(dir->chn,&card))<0) return ret;
2736
2737 if(!card->attached) return CARD_ERROR_NOCARD;
2738 dirblock = __card_getdirblock(card);
2739
2740 entries = dirblock->entries;
2741 do {
2742 //printf("%s\n", entries[dir->fileno].filename);
2743 if(entries[dir->fileno].gamecode[0]!=0xff) {
2744 if ((dir->showall || memcmp(entries[dir->fileno].gamecode,card_gamecode,4)==0)
2745 && (dir->showall || memcmp(entries[dir->fileno].company,card_company,2)==0)) {
2746 dir->filelen = entries[dir->fileno].length*card->sector_size;
2747 memcpy(dir->filename, entries[dir->fileno].filename, CARD_FILENAMELEN);
2748 memcpy(dir->gamecode, entries[dir->fileno].gamecode, 4);
2749 memcpy(dir->company, entries[dir->fileno].company, 2);
2750
2751 __card_putcntrlblock(card,CARD_ERROR_READY);
2752 return CARD_ERROR_READY;
2753 }
2754 }
2755 dir->fileno++;
2756 } while (dir->fileno < CARD_MAXFILES);
2757 __card_putcntrlblock(card,CARD_ERROR_NOFILE);
2758 return CARD_ERROR_NOFILE;
2759 }
2760
CARD_FindFirst(s32 chn,card_dir * dir,bool showall)2761 s32 CARD_FindFirst(s32 chn, card_dir *dir, bool showall)
2762 {
2763 // initialise structure
2764 dir->chn = chn;
2765 dir->fileno = 0;
2766 dir->filelen = 0;
2767 dir->filename[0] = 0;
2768 dir->gamecode[0] = 0;
2769 dir->company[0] = 0;
2770 dir->showall = showall;
2771 return __card_findnext(dir);
2772 }
2773
CARD_FindNext(card_dir * dir)2774 s32 CARD_FindNext(card_dir *dir)
2775 {
2776 dir->fileno++;
2777
2778 return __card_findnext(dir);
2779 }
2780
CARD_GetDirectory(s32 chn,card_dir * dir_entries,s32 * count,bool showall)2781 s32 CARD_GetDirectory(s32 chn,card_dir *dir_entries,s32 *count,bool showall)
2782 {
2783 s32 i,cnt;
2784 s32 ret = CARD_ERROR_READY;
2785 struct card_dat *dirblock = NULL;
2786 struct card_direntry *entries = NULL;
2787 card_block *card = NULL;
2788
2789 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2790 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2791
2792 if(!card->attached) return CARD_ERROR_NOCARD;
2793 dirblock = __card_getdirblock(card);
2794
2795 entries = dirblock->entries;
2796 for(i=0,cnt=0;i<CARD_MAXFILES;i++) {
2797 if(entries[i].gamecode[0]!=0xff) {
2798 if(showall || ((card_gamecode[0]!=0xff && memcmp(entries[i].gamecode,card_gamecode,4)==0)
2799 && (card_company[0]!=0xff && memcmp(entries[i].company,card_company,2)==0))) {
2800 dir_entries[cnt].fileno = i;
2801 dir_entries[cnt].permissions = entries[i].permission;
2802 dir_entries[cnt].filelen = entries[i].length*card->sector_size;
2803 memcpy(dir_entries[cnt].gamecode,entries[i].gamecode,4);
2804 memcpy(dir_entries[cnt].company,entries[i].company,2);
2805 memcpy(dir_entries[cnt].filename,entries[i].filename,CARD_FILENAMELEN);
2806 cnt++;
2807 }
2808 }
2809 }
2810 if(count) *count = cnt;
2811 if(cnt==0) ret = CARD_ERROR_NOFILE;
2812 __card_putcntrlblock(card,ret);
2813 return ret;
2814 }
2815
CARD_GetSectorSize(s32 chn,u32 * sector_size)2816 s32 CARD_GetSectorSize(s32 chn,u32 *sector_size)
2817 {
2818 s32 ret;
2819 card_block *card = NULL;
2820
2821 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2822 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2823
2824 *sector_size = card->sector_size;
2825 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
2826
2827 return ret;
2828 }
2829
CARD_GetBlockCount(s32 chn,u32 * block_count)2830 s32 CARD_GetBlockCount(s32 chn,u32 *block_count)
2831 {
2832 s32 ret;
2833 card_block *card = NULL;
2834
2835 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2836 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2837
2838 *block_count = card->blocks;
2839 ret = __card_putcntrlblock(card,CARD_ERROR_READY);
2840
2841 return ret;
2842 }
2843
CARD_GetStatus(s32 chn,s32 fileno,card_stat * stats)2844 s32 CARD_GetStatus(s32 chn,s32 fileno,card_stat *stats)
2845 {
2846 s32 ret;
2847 card_block *card = NULL;
2848 struct card_dat *dirblock = NULL;
2849 struct card_direntry *entry = NULL;
2850
2851 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2852 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
2853
2854 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2855
2856 dirblock = __card_getdirblock(card);
2857 if(dirblock) {
2858 entry = &dirblock->entries[fileno];
2859 memcpy(stats->gamecode,entry->gamecode,4);
2860 memcpy(stats->company,entry->company,2);
2861 memcpy(stats->filename,entry->filename,CARD_FILENAMELEN);
2862 stats->len = entry->length*card->sector_size;
2863 stats->time = entry->lastmodified;
2864 stats->banner_fmt = entry->bannerfmt;
2865 stats->icon_addr = entry->iconaddr;
2866 stats->icon_fmt = entry->iconfmt;
2867 stats->icon_speed = entry->iconspeed;
2868 stats->comment_addr = entry->commentaddr;
2869 __card_updateiconoffsets(entry,stats);
2870 }
2871
2872 return __card_putcntrlblock(card,CARD_ERROR_READY);
2873 }
2874
CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat * stats,cardcallback callback)2875 s32 CARD_SetStatusAsync(s32 chn,s32 fileno,card_stat *stats,cardcallback callback)
2876 {
2877 s32 ret;
2878 card_block *card = NULL;
2879 struct card_dat *dirblock = NULL;
2880 struct card_direntry *entry = NULL;
2881
2882 if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_NOCARD;
2883 if(fileno<0 || fileno>=CARD_MAXFILES) return CARD_ERROR_FATAL_ERROR;
2884 if(stats->icon_addr!=-1 && stats->icon_addr>CARD_READSIZE) return CARD_ERROR_FATAL_ERROR;
2885 if(stats->comment_addr!=-1 && stats->comment_addr>8128) return CARD_ERROR_FATAL_ERROR;
2886 if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
2887
2888 ret = CARD_ERROR_BROKEN;
2889 dirblock = __card_getdirblock(card);
2890 if(dirblock) {
2891 entry = &dirblock->entries[fileno];
2892 entry->bannerfmt = stats->banner_fmt;
2893 entry->iconaddr = stats->icon_addr;
2894 entry->iconfmt = stats->icon_fmt;
2895 entry->iconspeed = stats->icon_speed;
2896 entry->commentaddr = stats->comment_addr;
2897 __card_updateiconoffsets(entry,stats);
2898
2899 if(entry->iconaddr==-1) entry->iconfmt = ((entry->iconfmt&~CARD_ICON_MASK)|CARD_ICON_CI);
2900
2901 entry->lastmodified = time(NULL);
2902 if((ret=__card_updatedir(chn,callback))>=0) return ret;
2903 }
2904
2905 return __card_putcntrlblock(card,ret);
2906 }
2907
CARD_SetStatus(s32 chn,s32 fileno,card_stat * stats)2908 s32 CARD_SetStatus(s32 chn,s32 fileno,card_stat *stats)
2909 {
2910 s32 ret;
2911
2912 if((ret=CARD_SetStatusAsync(chn,fileno,stats,__card_synccallback))>=0) {
2913 ret = __card_sync(chn);
2914 }
2915 return ret;
2916 }
2917
CARD_GetAttributes(s32 chn,s32 fileno,u8 * attr)2918 s32 CARD_GetAttributes(s32 chn,s32 fileno,u8 *attr)
2919 {
2920 s32 ret;
2921 struct card_direntry entry;
2922
2923 if((ret=__card_getstatusex(chn,fileno,&entry))==CARD_ERROR_READY) {
2924 *attr = entry.permission;
2925 }
2926 return ret;
2927 }
2928
CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback)2929 s32 CARD_SetAttributesAsync(s32 chn,s32 fileno,u8 attr,cardcallback callback)
2930 {
2931 s32 ret;
2932 struct card_direntry entry;
2933
2934 if((ret=__card_getstatusex(chn,fileno,&entry))>=0) {
2935 entry.permission = attr;
2936 ret = __card_setstatusexasync(chn,fileno,&entry,callback);
2937 }
2938 return ret;
2939 }
2940
CARD_SetAttributes(s32 chn,s32 fileno,u8 attr)2941 s32 CARD_SetAttributes(s32 chn,s32 fileno,u8 attr)
2942 {
2943 s32 ret;
2944
2945 if((ret=CARD_SetAttributesAsync(chn,fileno,attr,__card_synccallback))>=0) {
2946 ret = __card_sync(chn);
2947 }
2948 return ret;
2949 }
2950
CARD_SetCompany(const char * company)2951 s32 CARD_SetCompany(const char *company)
2952 {
2953 u32 level,i;
2954
2955 _CPU_ISR_Disable(level);
2956 for(i=0;i<2;i++) card_company[i] = 0xff;
2957 if(company && strlen(company)<=2) memcpy(card_company,company,2) ;
2958 _CPU_ISR_Restore(level);
2959
2960 return CARD_ERROR_READY;
2961 }
2962
CARD_SetGamecode(const char * gamecode)2963 s32 CARD_SetGamecode(const char *gamecode)
2964 {
2965 u32 level,i;
2966
2967 _CPU_ISR_Disable(level);
2968 for(i=0;i<4;i++) card_gamecode[i] = 0xff;
2969 if(gamecode && strlen(gamecode)<=4) memcpy(card_gamecode,gamecode,4) ;
2970 _CPU_ISR_Restore(level);
2971
2972 return CARD_ERROR_READY;
2973 }
2974