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