#include "Card.h"

FIL CardStat;
extern u32 FSTMode;
extern FIL GameFile;

void CardInit( void )
{
	FILINFO f;
	u32 i,wrote;
	CARDStat CStat;
	char GameID[0x20];
	

	memset32( (void*)CARD_BASE, 0xdeadbeef, 0x20 );
	memset32( (void*)CARD_SHADOW, 0, 0x20 );

//Create savefile dirs for the current game
	if( f_chdir("/saves") != FR_OK )
	{
		f_mkdir("/saves");
		f_chdir("/saves");
	}

	if( FSTMode )
	{
		FSTRead( (char*)GameID, 0x20, 0 );

	} else {						

		f_lseek( &GameFile, 0 );
		f_read( &GameFile, (char*)GameID, 0x20, &wrote );
	}

	if( f_chdir(GameID) != FR_OK )
	{
		f_mkdir(GameID);
		f_chdir(GameID);
	}	

	switch( f_stat( "stats.bin", &f ) )
	{
		case FR_NO_FILE:
		{
			if( f_open( &CardStat, "stats.bin", FA_CREATE_ALWAYS | FA_READ | FA_WRITE ) != FR_OK )
			{
				//dbgprintf("MC:Could not create stats file!\n");

			} else {
				
				memset32( &CStat, 0, sizeof( CARDStat ) );
				for( i=0; i < CARD_MAX_FILES; ++i )
				{
					f_write( &CardStat, &CStat, sizeof( CARDStat ), &wrote );
				}
				f_sync( &CardStat );
			}
		} break;
		case FR_OK:
		{
			if( f_open( &CardStat, "stats.bin", FA_OPEN_EXISTING | FA_READ | FA_WRITE ) != FR_OK )
			{
				;//dbgprintf("MC:Could not create stats file!\n");
			}
		} break;
		default:
		{
			;//dbgprintf("MC:CardInit fuck up\n");
		} break;
	}

	write32( 0x2FA0, 0 );
}
void LFNfy( char *str )
{
	u32 len = strlen(str);
	u32 i;

	for( i=0; i < len; ++i )
	{
		switch( str[i] )
		{
			case '\\':
			case '/':
			case '*':
			case '|':
			case '?':
			case '<':
			case '>':
			case '\"':
			case ':':
				str[i] = ' ';
			break;
			default:
				break;
		}
	}
}
s32 CardFindFreeEntry( void )
{
	CARDStat CStat;
	u32 i;
	u32 read;

	for( i=0; i < CARD_MAX_FILES; ++i )
	{
		f_lseek( &CardStat, sizeof(CARDStat) * i );
		f_read( &CardStat, &CStat, sizeof(CARDStat), &read );

		if( CStat.length == 0 )
		{
			//dbgprintf("CardFindFreeEntry(%d)\n", i );
			return i;
		}
	}

	return -1;
}

s32 CardFindEntryByName( char *Filename )
{
	CARDStat CStat;
	u32 i;
	u32 read;

	for( i=0; i < CARD_MAX_FILES; ++i )
	{
		f_lseek( &CardStat, sizeof(CARDStat) * i );
		f_read( &CardStat, &CStat, sizeof(CARDStat), &read );
				
		if( strcmp( Filename, CStat.fileName ) == 0 )
		{
			//dbgprintf("CardFindEntryByName(%d,%s,%s)\n", i, Filename, CStat.fileName );
			return i;
		}
	}
	return -1;	
}


s32 CardOpenFile( char *Filename, CARDFileInfo *CFInfo )
{
	FIL savefile;
	s32 Slot,fres;
	
	Slot = CardFindEntryByName(Filename);
	if( Slot < 0 )
	{	
		write32( CARD_SCMD_4, -1 );
		write32( CARD_SRETURN, CARD_NO_FILE );
		return -4;
	}
		
	LFNfy( Filename );
	fres = f_open( &savefile, Filename, FA_READ|FA_WRITE|FA_OPEN_EXISTING ) ;
	switch( fres )
	{
		case FR_NO_PATH:
		case FR_NO_FILE:
		{
			;//dbgprintf("MC:Failed to open:\"%s\":%d\n", Filename, fres );

			write32( CARD_SCMD_4, -1 );
			write32( CARD_SRETURN, CARD_NO_FILE );
		} break;
		default:
		{
			EXIControl(1);
			;//dbgprintf("MC:Failed to open:\"%s\":%d\n", Filename, fres );
			Shutdown();
		} break;
		case FR_OK:
		{
			f_close( &savefile );

			write32( CARD_SCMD_4, Slot );
			write32( CARD_SRETURN, CARD_SUCCESS );
		} break;
	}	

	return 0;
}
s32 CardFastOpenFile( u32 FileNo, CARDFileInfo *CFInfo )
{
	CARDStat CStat;
	FIL savefile;
	s32 Slot,fres;
	u32 read;

	if( FileNo >= CARD_MAX_FILES )
	{
		write32( CARD_SRETURN, CARD_NO_FILE );
		return 0;
	}
	
	f_lseek( &CardStat, sizeof(CARDStat) * FileNo );
	f_read( &CardStat, &CStat, sizeof(CARDStat), &read );

	if( CStat.length == 0 )
	{
		write32( CARD_SRETURN, CARD_NO_FILE );
		return 0;
	}
		
	LFNfy( CStat.fileName );
	fres = f_open( &savefile, CStat.fileName, FA_READ|FA_WRITE|FA_OPEN_EXISTING ) ;
	switch( fres )
	{
		case FR_NO_PATH:
		case FR_NO_FILE:
		{
			;//dbgprintf("MC:Failed to open:\"%s\":%d\n", CStat.fileName, fres );

			write32( CARD_SRETURN, CARD_NO_FILE );
		} break;
		default:
		{
			EXIControl(1);
			;//dbgprintf("MC:Failed to open:\"%s\":%d\n", CStat.fileName, fres );
			Shutdown();
		} break;
		case FR_OK:
		{
			write32( CARD_SCMD_4, savefile.fsize );

			f_close( &savefile );

			write32( CARD_SRETURN, CARD_SUCCESS );
		} break;
	}	

	return 0;
}
void CardDeleteFile( char *Filename )
{
	CARDStat CStat;
	u32 wrote;
	s32 Slot;

	Slot = CardFindEntryByName( Filename );
	if( Slot < 0 )
	{
		dbgprintf("MC:\"%s\" doesn't exists\n", Filename );
		write32( CARD_SRETURN, CARD_NO_FILE );
		return;
	}

	memset32( &CStat, 0, sizeof(CARDStat) );
	
	f_lseek( &CardStat, sizeof(CARDStat) * Slot );
	f_write( &CardStat, &CStat, sizeof(CARDStat), &wrote );
	f_sync( &CardStat );

	f_unlink( Filename );
	
	write32( CARD_SRETURN, CARD_SUCCESS );
}
void CardFastDelete( u32 FileNo )
{
	CARDStat CStat;
	u32 read;	

	if( FileNo >= CARD_MAX_FILES )
	{
		write32( CARD_SRETURN, CARD_NO_FILE );
		return;
	}
	
	f_lseek( &CardStat, sizeof(CARDStat) * FileNo );
	f_read( &CardStat, &CStat, sizeof(CARDStat), &read );

	if( f_unlink( CStat.fileName ) == FR_OK )
	{
		memset32( &CStat, 0, sizeof(CARDStat) );

		f_lseek( &CardStat, sizeof(CARDStat) * FileNo );
		f_write( &CardStat, &CStat, sizeof(CARDStat), &read );
		f_sync( &CardStat );

		write32( CARD_SRETURN, CARD_SUCCESS );

	} else {
		write32( CARD_SRETURN, CARD_NO_FILE );
	}

	return;
}
void CardRename( char *NameSrc, char *NameDst )
{
	CARDStat CStat;
	u32 wrote;
	s32 Slot;

	Slot = CardFindEntryByName( NameDst );
	if( Slot != -1 )
	{
		f_unlink( NameDst );
		
		f_lseek( &CardStat, sizeof(CARDStat) * Slot );
		f_read( &CardStat, &CStat, sizeof(CARDStat), &wrote );

		memset32( &CStat, 0, sizeof(CARDStat) );

		f_lseek( &CardStat, sizeof(CARDStat) * Slot );
		f_write( &CardStat, &CStat, sizeof(CARDStat), &wrote );
		f_sync( &CardStat );
	}

	Slot = CardFindEntryByName( NameSrc );
	if( Slot == -1 )
	{
		write32( CARD_SRETURN, CARD_NO_FILE );
		return;
	}

	switch( f_rename( NameSrc, NameDst ) )
	{
		case FR_OK:
		{
			f_lseek( &CardStat, sizeof(CARDStat) * Slot );
			f_read( &CardStat, &CStat, sizeof(CARDStat), &wrote );

			memcpy( CStat.fileName, NameDst, 32 );

			f_lseek( &CardStat, sizeof(CARDStat) * Slot );
			f_write( &CardStat, &CStat, sizeof(CARDStat), &wrote );
			f_sync( &CardStat );

			write32( CARD_SRETURN, CARD_SUCCESS );

		} break;
		//case FR_EXIST:
		//{
		//	write32( CARD_SRETURN, CARD_FILE_EXISTS );
		//} break;
		default:
		{
			write32( CARD_SRETURN, CARD_FATAL_ERROR );
		} break;
	}
}
void CardCreateFile( char *Filename, u32 Size, CARDFileInfo *CFInfo )
{
	CARDStat CStat;
	u32 i,fres,read;
	s32 Slot;
	FIL savefile;

	Slot = CardFindEntryByName( Filename );
	if( Slot >= 0 )
	{
		;//dbgprintf("MC:\"%s\" already exists\n", Filename );
		write32( CARD_SRETURN, CARD_FILE_EXISTS );
		return;
	}

	Slot = CardFindFreeEntry();
	if( Slot < 0 )
		return;
		
	char FName[32];
	memcpy( FName, Filename, 32 );

	LFNfy( FName );
	fres = f_open( &savefile, FName, FA_READ|FA_WRITE|FA_CREATE_NEW );
	switch( fres )
	{
		case FR_EXIST:
		{
			write32( CARD_SCMD_4, 0 );
			write32( CARD_SRETURN, CARD_FILE_EXISTS );
		} break;
		default:
		{
			EXIControl(1);
			;//dbgprintf("MC:Failed to create:\"%s\":%d\n", Filename, fres );
			Shutdown();
		} break;
		case FR_OK:
		{
			f_lseek( &CardStat, sizeof(CARDStat) * Slot );
			f_read( &CardStat, &CStat, sizeof(CARDStat), &read );
			
			memcpy( CStat.fileName, Filename, strlen(Filename) );

			CStat.length = Size;
			CStat.time   = 0x15745a1a;
			memcpy( CStat.gameName, (void*)0, 4 );
			memcpy( CStat.company, (void*)4, 2 );
			
			CStat.bannerFormat		= 0;
			CStat.iconAddr			= -1;
			CStat.iconFormat		= 0;
			CStat.iconSpeed			= 0;
			CStat.commentAddr		= -1;

			CStat.offsetBanner		= -1;
			CStat.offsetBannerTlut	= -1;
			for( i=0; i < 8; ++i )
				CStat.offsetIcon[i] = -1;
			CStat.offsetIconTlut	= -1;
			CStat.offsetData		=  0;
			
			f_lseek( &CardStat, sizeof(CARDStat) * Slot );
			f_write( &CardStat, &CStat, sizeof(CARDStat), &read );
			f_sync( &CardStat );
			
			CFInfo->chan   = 0;
			CFInfo->fileNo = Slot;
			CFInfo->iBlock = 0;
			CFInfo->length = Size;
			CFInfo->offset = 0;

			char *buf = (char*)malloc(512);
			memset32( buf, 0, 512 );
			
			//Create full file
			for( i=0; i < Size; i+=512 )
			{
				f_write( &savefile, buf, 512, &read);
			}

			f_close( &savefile );
			
			write32( CARD_SCMD_4, Slot );
			write32( CARD_SRETURN, CARD_SUCCESS );
		} break;
	}
}
void CardReadFile( u32 FileNo, u8 *Buffer, u32 Length, u32 Offset )
{
	u32 read;
	CARDStat CStat;

	FIL savefile;

	f_lseek( &CardStat, sizeof(CARDStat) * FileNo );
	f_read( &CardStat, &CStat, sizeof(CARDStat), &read );
	
	LFNfy( CStat.fileName );
	if( f_open( &savefile, CStat.fileName, FA_OPEN_EXISTING | FA_READ ) == FR_OK )
	{
		f_lseek( &savefile, Offset );
		f_read( &savefile, (void*)Buffer, Length, &read );
		f_close( &savefile );
	}
}
void CardWriteFile( u32 FileNo, u8 *Buffer, u32 Length, u32 Offset )
{
	u32 read;
	CARDStat CStat;

	FIL savefile;

	f_lseek( &CardStat, sizeof(CARDStat) * FileNo );
	f_read( &CardStat, &CStat, sizeof(CARDStat), &read );
	
	LFNfy( CStat.fileName );
	switch( f_open( &savefile, CStat.fileName, FA_OPEN_EXISTING | FA_WRITE ) )
	{
		case FR_OK:
		{
#ifdef CARD_DEBUG
			if( f_lseek( &savefile, Offset ) != FR_OK )
			{
				EXIControl(1);
				dbgprintf("Failed to seek to %08x\n", Offset );
				Shutdown();
			} else {
				if( f_write( &savefile, (void*)Buffer, Length, &read ) != FR_OK )
				{
					EXIControl(1);
					dbgprintf("Failed to write %d bytes to %p\n", Length, Buffer );
					Shutdown();					
				}
				if( read != Length )
				{
					EXIControl(1);
					dbgprintf("Short write; %d of %d bytes written!\n", read, Length );
					Shutdown();			
				}
			}
#else
			f_lseek( &savefile, Offset );
			f_write( &savefile, (void*)Buffer, Length, &read );
#endif
			f_close( &savefile );
		} break;
		default:
		{
			EXIControl(1);
			dbgprintf("Failed to open:\"%s\"\n", CStat.fileName );
			Shutdown();
		} break;
	}
}
void CardUpdateStats( CARDStat *CStat )
{
	u32 IconSize,BannerSize,Format,Offset,i,TLut=0;

	BannerSize	= CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
	IconSize	= CARD_ICON_WIDTH * CARD_ICON_HEIGHT;
	Offset		= CStat->iconAddr;

	if( CStat->bannerFormat & CARD_STAT_BANNER_C8 )
	{
		CStat->offsetBanner		= Offset;
		CStat->offsetBannerTlut	= Offset + BannerSize;

		Offset += BannerSize + 512;

	} else if( CStat->bannerFormat & CARD_STAT_BANNER_RGB5A3 ) {

		CStat->offsetBanner		=  Offset;
		CStat->offsetBannerTlut	= -1;

		Offset += BannerSize * 2;

	} else {
					
		CStat->offsetBanner		= -1;
		CStat->offsetBannerTlut	= -1;
	}
				
	for( i=0; i < CARD_ICON_MAX; ++i )
	{
		Format = CStat->iconFormat >> ( i * 2 );

		if( Format & CARD_STAT_ICON_C8 )
		{
			CStat->offsetIcon[i] = Offset;
			Offset += IconSize;
			TLut = 1;

		} else if ( Format & CARD_STAT_ICON_RGB5A3 ) {
						
			CStat->offsetIcon[i] = Offset;
			Offset += IconSize * 2;

		} else {
			CStat->offsetIcon[i] = -1;
		}
	}

	if( TLut )
	{
		CStat->offsetIconTlut = Offset;
		Offset += 512;
	} else {
		CStat->offsetIconTlut = -1;
	}

	CStat->offsetData = Offset;
}
void CARDUpdateRegisters( void )
{
	u32 read,i;
	u32 CARDOK=0;

	if( read32(CARD_CONTROL) != 0xdeadbeef )
	{
		if( read32( CARD_CONTROL ) & (~3) )
		{
			write32( CARD_CONTROL, 0xdeadbeef );
			return;			
		}

		write32( CARD_SCONTROL, read32(CARD_CONTROL) & 3 );
		
		clear32( CARD_SSTATUS, 0x14 );

		write32( CARD_CONTROL, 0xdeadbeef );
		
		if( ConfigGetConfig(DML_CFG_ACTIVITY_LED) )
			set32( HW_GPIO_OUT, 1<<5 );

		while( read32(CARD_CMD) == 0xdeadbeef );
		write32( CARD_SCMD, read32(CARD_CMD) );
		write32( CARD_CMD, 0xdeadbeef );

		while( read32(CARD_CMD_1) == 0xdeadbeef );
		write32( CARD_SCMD_1, read32(CARD_CMD_1) );
		write32( CARD_CMD_1, 0xdeadbeef );
		
		if( read32(CARD_CMD_2) != 0xdeadbeef )
		{
			write32( CARD_SCMD_2, read32(CARD_CMD_2) );
			write32( CARD_CMD_2, 0xdeadbeef );
		}

		if( read32(CARD_CMD_3) != 0xdeadbeef )
		{
			write32( CARD_SCMD_3, read32(CARD_CMD_3) );
			write32( CARD_CMD_3, 0xdeadbeef );
		}
		
		if( read32(CARD_CMD_4) != 0xdeadbeef )
		{
			write32( CARD_SCMD_4, read32(CARD_CMD_4) );
			write32( CARD_CMD_4, 0xdeadbeef );
		}

		switch( read32(CARD_SCMD) >> 24 )
		{
			case 0x00:
			{
				;//dbgprintf("CARD:Warning unknown command!\n");
			} break;
			default:
			{
				//EXIControl(1);
				dbgprintf("CARD:Unknown CMD:%08X %08X %08X %08X %08X %08X\n", read32(CARD_SCMD), read32(CARD_SCMD_1), read32(CARD_SCMD_2), read32(CARD_SCMD_3), read32(CARD_SCMD_4), read32(CARD_SCONTROL) );
				Shutdown();
			} break;
			/* CARDOpen( char *FileName ) */
			case 0xC0:
			{
				char FileName[32];

				u32 FInfo = P2C(read32(CARD_SCMD_2));

				memcpy( FileName, (void*)0x17E0, 32 );
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDOpen( \"%s\", 0x%08x )", FileName, FInfo );
#endif										
				CardOpenFile( (char*)FileName, (CARDFileInfo*)FInfo );

				CARDOK = 1;
			} break;
			case 0xC1:
			{
				u32 FileNo = read32(CARD_SCMD_1);
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDClose( %d )", FileNo );
#endif
				if( FileNo < 0 )
					write32( CARD_SRETURN, -128 );
				else
					write32( CARD_SRETURN, 0 );

				CARDOK = 1;
			} break;
			case 0xC2:
			{
				char FileName[32];
				u32 Size	=	  read32(CARD_SCMD_2);
				u32 FInfo	= P2C(read32(CARD_SCMD_3));
				
				memcpy( FileName, (void*)0x17E0, 32 );
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDCreate( \"%s\", 0x%04x, 0x%08x )", FileName, Size, FInfo );
#endif
				CardCreateFile( (char*)FileName, Size, (CARDFileInfo*)FInfo );

				write32( 0x2FA0, read32(0x2FA0) + CARD_XFER_CREATE );

				CARDOK = 1;
			} break;
			case 0xC3:
			{
				CARDStat CS;
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDGetState( %d, 0x%08x, ",  read32(CARD_SCMD_1), P2C(read32(CARD_SCMD_2)) );
#endif
					
				if( read32(CARD_SCMD_1) >= CARD_MAX_FILES )
				{
					EXIControl(1);
					dbgprintf("MC: Invalid file slot!:%d\n", read32(CARD_SCMD_1) );
					Shutdown();
				}

				f_lseek( &CardStat, sizeof(CARDStat) * read32(CARD_SCMD_1) );
				f_read( &CardStat, &CS, sizeof(CARDStat), &read );
				
				if( CS.length == 0 )
				{
#ifdef CARDDEBUG
				//	dbgprintf(")");
#endif
					write32( CARD_SRETURN, CARD_NO_FILE );
				} else {

					CardUpdateStats( &CS );
				
					memcpy( (void*)0x1780, &CS, sizeof(CARDStat) );
			
#ifdef CARDDEBUG	
					CARDStat *CSTAT = (CARDStat*)0x1780;
					
					dbgprintf("\nMC:Card Status:\n");
					dbgprintf("\tFilename:%.32s\n", CSTAT->fileName );
					dbgprintf("\tGameName:%.4s\n", CSTAT->gameName );
					dbgprintf("\tCompany :%.2s\n", CSTAT->company );
					dbgprintf("\tLength  :%d\n", CSTAT->length );
					dbgprintf("\tTime    :%d\n\n", CSTAT->time );
					
					dbgprintf("\tBannerFormat:%d\n", CSTAT->bannerFormat );
					dbgprintf("\tIconAddress :0x%04X\n", CSTAT->iconAddr );
					dbgprintf("\tIconFormat  :0x%02X\n", CSTAT->iconFormat );
					dbgprintf("\tIconSpeed   :0x%02X\n", CSTAT->iconSpeed );
					dbgprintf("\tComntAddress:0x%04X\n\n", CSTAT->commentAddr );
					
					dbgprintf("\tOffsetBanner :0x%04X\n", CSTAT->offsetBanner );
					dbgprintf("\tOffsetBnrTlt :0x%04X\n", CSTAT->offsetBannerTlut );

					for( i=0; i < CARD_ICON_MAX; ++i)
						dbgprintf("\tOffsetIcon[%d]:0x%04X\n", i, CSTAT->offsetIcon[i] );

					dbgprintf("\tOffsetIconTlt:0x%04X\n", CSTAT->offsetIconTlut );
					dbgprintf("\tOffsetData   :0x%04X\n", CSTAT->offsetData );
#endif
									
					write32( CARD_SRETURN, CARD_SUCCESS );
				}
				CARDOK = 1;
			} break;
			case 0xC4:
			{
				CARDStat CS;
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDSetState( %d, 0x%08x )",  read32(CARD_SCMD_1), P2C(read32(CARD_SCMD_2)) );
#endif
				if( read32(CARD_SCMD_1) >= CARD_MAX_FILES )
				{
					EXIControl(1);
					dbgprintf("\nMC: Invalid file slot!\n");
					Shutdown();
				}

				CARDStat *CStat = (CARDStat *) P2C(read32(CARD_SCMD_2));

				f_lseek( &CardStat, sizeof(CARDStat) * read32(CARD_SCMD_1) );
				f_read( &CardStat, &CS, sizeof(CARDStat), &read );

				if( CS.length == 0 )
				{
#ifdef CARDDEBUG
					dbgprintf(")");
#endif
					write32( CARD_SRETURN, CARD_NO_FILE );

				} else {

					CS.bannerFormat	= CStat->bannerFormat;
					CS.iconAddr		= CStat->iconAddr;
					CS.iconFormat	= CStat->iconFormat;
					CS.iconSpeed	= CStat->iconSpeed;
					CS.commentAddr	= CStat->commentAddr;
				
#ifdef CARDDEBUG
					dbgprintf("\nMC:Card Status:\n");
					dbgprintf("\tFilename:%.32s\n", CS.fileName );
					dbgprintf("\tGameName:%.4s\n", CS.gameName );
					dbgprintf("\tCompany :%.2s\n", CS.company );
					dbgprintf("\tLength  :%d\n", CS.length );
					dbgprintf("\tTime    :%d\n\n", CS.time );
					
					dbgprintf("\tBannerFormat:%d\n", CS.bannerFormat );
					dbgprintf("\tIconAddress :0x%04X\n", CS.iconAddr );
					dbgprintf("\tIconFormat  :0x%02X\n", CS.iconFormat );
					dbgprintf("\tIconSpeed   :0x%02X\n", CS.iconSpeed );
					dbgprintf("\tComntAddress:0x%04X\n\n", CS.commentAddr );
#endif

					CardUpdateStats( &CS );
					
#ifdef CARDDEBUG
					dbgprintf("\tOffsetBanner :0x%04X\n", CS.offsetBanner );
					dbgprintf("\tOffsetBnrTlt :0x%04X\n", CS.offsetBannerTlut );

					for( i=0; i < CARD_ICON_MAX; ++i)
						dbgprintf("\tOffsetIcon[%d]:0x%04X\n", i, CS.offsetIcon[i] );

					dbgprintf("\tOffsetIconTlt:0x%04X\n", CS.offsetIconTlut );
					dbgprintf("\tOffsetData   :0x%04X\n", CS.offsetData );
#endif
				
					f_lseek( &CardStat, sizeof(CARDStat) * read32(CARD_SCMD_1) );
					f_write( &CardStat, &CS, sizeof(CARDStat), &read );
					f_sync( &CardStat );

					write32( 0x2FA0, read32(0x2FA0) + CARD_XFER_SETSTATUS );
					
					write32( CARD_SRETURN, CARD_SUCCESS );
				}

				CARDOK = 1;
			} break;
			/* CARDFastOpen( u32 FileNO, CARDFileInfo *CFInfo ) */			
			case 0xC5:
			{
				u32 FileNo	= read32(CARD_SCMD_1);
				u32 FInfo	= P2C(read32(CARD_SCMD_2));
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDFastOpen( %d, 0x%08X )", FileNo, FInfo );
#endif				
				CardFastOpenFile( FileNo, (CARDFileInfo*)FInfo );
				
				CARDOK = 1;
			} break;
			case 0xC6:
			{
				char FileName[32];

				memcpy( FileName, (void*)0x17E0, 32 );
#ifdef CARDDEBUG
				dbgprintf("MC:CARDDelete( \"%s\" )", FileName );
#endif

				CardDeleteFile( (char*)FileName );

				write32( 0x2FA0, read32(0x2FA0) + CARD_XFER_DELETE );

				CARDOK = 1;
			} break;
			case 0xC8:
			{
				u32 Buffer	= P2C(read32(CARD_SCMD_1));
				u32 Length	= read32(CARD_SCMD_2);
				u32 Offset	= read32(CARD_SCMD_3);
				u32 FileNo	= read32(CARD_SCMD_4);
				
#ifdef CARDDEBUG
				dbgprintf("MC:CARDWrite( %d, 0x%08x, 0x%04x, 0x%04x )", FileNo, Buffer, Offset, Length );
#endif
				if( FileNo >= CARD_MAX_FILES )
				{
					EXIControl(1);
					dbgprintf("\nMC: Invalid file slot!:%d\n", FileNo );
					Shutdown();
				}

				CardWriteFile( FileNo, (u8*)Buffer, Length, Offset );

				write32( 0x2FA0, read32(0x2FA0) + CARD_XFER_WRITE + Length );
					
				write32( CARD_SRETURN, 0 );

				CARDOK = 1;
			} break;
			case 0xC9:
			{
				u32 Buffer	= P2C(read32(CARD_SCMD_1));
				u32 Length	= read32(CARD_SCMD_2);
				u32 Offset	= read32(CARD_SCMD_3);
				u32 FileNo	= read32(CARD_SCMD_4);
					
#ifdef CARDDEBUG
				dbgprintf("MC:CARDRead( %d, 0x%08x, 0x%04x, 0x%04x )", FileNo, Buffer, Offset, Length );
#endif
				if( FileNo >= CARD_MAX_FILES )
				{
					EXIControl(1);
					dbgprintf("\nMC: Invalid file slot!:%d\n", FileNo );
					Shutdown();
				}

				CardReadFile( FileNo, (u8*)Buffer, Length, Offset );

				write32( 0x2FA0, read32(0x2FA0) + Length );

				write32( CARD_SRETURN, 0 );
				
				CARDOK = 1;
			} break;
			case 0xCA:
			{
				u32 FileNo = read32( CARD_SCMD_1 );
#ifdef CARDDEBUG
				dbgprintf("MC:CARDFastDelete( %u )", FileNo );
#endif
				CardFastDelete( FileNo );

				write32( 0x2FA0, read32(0x2FA0) + CARD_XFER_DELETE );

				CARDOK = 1;
			} break;
			case 0xCB:
			{
				char NameSrc[32];
				char NameDst[32];

				memcpy( NameSrc, (void*)0x17C0, 32 );
				memcpy( NameDst, (void*)0x17E0, 32 );

#ifdef CARDDEBUG
				dbgprintf("MC:CARDRename( \"%s\", \"%s\" )", NameSrc, NameDst );
#endif
				CardRename( NameSrc, NameDst );

				CARDOK = 1;
			} break;
		}

		if(CARDOK)
		{
#ifdef CARDDEBUG
			dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
			while( read32(CARD_SCONTROL) & 1 )
				clear32( CARD_SCONTROL, 1 );

			set32( CARD_SSTATUS, 0x10 );
		}

		if( ConfigGetConfig(DML_CFG_ACTIVITY_LED) )
			clear32( HW_GPIO_OUT, 1<<5 );
	}
}
