Cheating:

*Due space limitations only the debug version of kenobigc is supported, this means there is a bit less space for cheats.


git-svn-id: svn://localhost/Users/andi/Downloads/code/trunk@2 be6c1b03-d731-4111-a574-e37d80d43941
This commit is contained in:
crediar@rypp.net 2012-06-23 18:08:56 +00:00
parent e635dd34dc
commit 7f75f5eb1e
87 changed files with 16403 additions and 0 deletions

949
Card.c Normal file
View File

@ -0,0 +1,949 @@
#include "Card.h"
FIL CardStat;
void CardInit( void )
{
FILINFO f;
u32 i,wrote;
CARDStat CStat;
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( f_chdir((const TCHAR*)0) != FR_OK )
{
f_mkdir((const TCHAR*)0);
f_chdir((const TCHAR*)0);
}
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 );
}
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( memcmp( Filename, CStat.fileName, strlen(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;
}
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 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;
}
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;
fres = f_open( &savefile, Filename, 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 );
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 );
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;
}
u32 Device = 0;
void CARDUpdateRegisters( void )
{
u32 read;
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 );
#ifdef ACTIVITYLED
set32( HW_GPIO_OUT, 1<<5 );
#endif
while( read32(CARD_CMD) == 0xdeadbeef );
write32( CARD_SCMD, read32(CARD_CMD) );
write32( CARD_CMD, 0xdeadbeef );
if( 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 );
while( read32(CARD_CONTROL) & 1 )
clear32( CARD_CONTROL, 1 );
while( (read32(CARD_SSTATUS) & 0x10) != 0x10 )
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32(CARD_SRETURN) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} 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 {
#ifdef CARDDEBUG
// dbgprintf("\"%s\")", CS.fileName );
dbgprintf("MC:CARDGetState( %d, 0x%08x, \"%s\"):0", read32(CARD_SCMD_1), P2C(read32(CARD_SCMD_2)), CS.fileName );
#endif
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 );
}
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
// dbgprintf("MC:CARDGetState( %d, 0x%08x, ):%d\n", read32(CARD_SCMD_1), P2C(read32(CARD_SCMD_2)), read32( CARD_SRETURN) );
#endif
} 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 );
}
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":1\n");
#endif
} 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 );
while( read32(CARD_CONTROL) & 1 )
clear32( CARD_CONTROL, 1 );
while( (read32(CARD_SSTATUS) & 0x10) != 0x10 )
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%u\n", read32(CARD_SRETURN) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%u\n", read32(CARD_SRETURN) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} 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 );
while( read32(CARD_SCONTROL) & 1 )
clear32( CARD_SCONTROL, 1 );
set32( CARD_SSTATUS, 0x10 );
#ifdef CARDDEBUG
dbgprintf(":%d\n", read32( CARD_SRETURN ) );
#endif
} break;
}
#ifdef ACTIVITYLED
clear32( HW_GPIO_OUT, 1<<5 );
#endif
}
}

114
Card.h Normal file
View File

@ -0,0 +1,114 @@
#ifndef _CARD_
#define _CARD_
#include "string.h"
#include "global.h"
#include "alloc.h"
#include "ff.h"
#include "vsprintf.h"
#include "HW.h"
#include "vsprintf.h"
#ifdef TRIFORCE
#include "JVSIOMessage.h"
#endif
#define CARD_MAX_FILES 128
#define CARD_BASE 0x00002F60
#define CARD_CMD (CARD_BASE+0x00)
#define CARD_CMD_1 (CARD_BASE+0x04)
#define CARD_CMD_2 (CARD_BASE+0x08)
#define CARD_CMD_3 (CARD_BASE+0x0C)
#define CARD_CMD_4 (CARD_BASE+0x10)
#define CARD_RETURN (CARD_BASE+0x14)
#define CARD_CONTROL (CARD_BASE+0x18)
#define CARD_STATUS (CARD_BASE+0x1C)
#define CARD_SHADOW (CARD_BASE + 0x20)
#define CARD_SCMD (CARD_SHADOW+0x00)
#define CARD_SCMD_1 (CARD_SHADOW+0x04)
#define CARD_SCMD_2 (CARD_SHADOW+0x08)
#define CARD_SCMD_3 (CARD_SHADOW+0x0C)
#define CARD_SCMD_4 (CARD_SHADOW+0x10)
#define CARD_SRETURN (CARD_SHADOW+0x14)
#define CARD_SCONTROL (CARD_SHADOW+0x18)
#define CARD_SSTATUS (CARD_SHADOW+0x1C)
// internal API command xfer bytes
#define CARD_XFER_CREATE (2 * 8 * 1024) // CARDCreate[Async]
#define CARD_XFER_DELETE (2 * 8 * 1024) // CARD[Fast]Delete[Async]
#define CARD_XFER_MOUNT (5 * 8 * 1024) // CARDMount[Async]
#define CARD_XFER_FORMAT (5 * 8 * 1024) // CARDFormat[Async]
#define CARD_XFER_RENAME (1 * 8 * 1024) // CARDRename[Async]
#define CARD_XFER_SETSTATUS (1 * 8 * 1024) // CARDSetStatus[Async]
#define CARD_XFER_SETATTRIBUTES (1 * 8 * 1024) // CARDSetAttributes[Async]
#define CARD_XFER_WRITE (1 * 8 * 1024) // CARDWrite[Async]
#define CARD_FILENAME_MAX 32
#define CARD_ICON_MAX 8
#define CARD_ICON_WIDTH 32
#define CARD_ICON_HEIGHT 32
#define CARD_BANNER_WIDTH 96
#define CARD_BANNER_HEIGHT 32
#define CARD_STAT_ICON_NONE 0
#define CARD_STAT_ICON_C8 1
#define CARD_STAT_ICON_RGB5A3 2
#define CARD_STAT_BANNER_NONE 0
#define CARD_STAT_BANNER_C8 1
#define CARD_STAT_BANNER_RGB5A3 2
enum CardStatus
{
CARD_SUCCESS = 0,
CARD_NO_FILE = -4,
CARD_FILE_EXISTS = -7,
CARD_FATAL_ERROR =-128,
};
typedef struct CARDFileInfo
{
/* 0x00 */ s32 chan;
/* 0x04 */ s32 fileNo;
/* 0x08 */ s32 offset;
/* 0x0C */ s32 length;
/* 0x10 */ u16 iBlock;
} CARDFileInfo;
typedef struct CARDStat
{
// read-only (Set by CARDGetStatus)
/* 0x00 */ char fileName[32];
/* 0x20 */ u32 length;
/* 0x24 */ u32 time; // seconds since 01/01/2000 midnight
/* 0x28 */ u8 gameName[4];
/* 0x2C */ u8 company[2];
// read/write (Set by CARDGetStatus/CARDSetStatus)
/* 0x2E */ u8 bannerFormat;
/* 0x30 */ u32 iconAddr; // offset to the banner, bannerTlut, icon, iconTlut data set.
/* 0x34 */ u16 iconFormat;
/* 0x36 */ u16 iconSpeed;
/* 0x38 */ u32 commentAddr; // offset to the pair of 32 byte character strings.
// read-only (Set by CARDGetStatus)
/* 0x3C */ u32 offsetBanner;
/* 0x40 */ u32 offsetBannerTlut;
/* 0x44 */ u32 offsetIcon[8];
/* 0x64 */ u32 offsetIconTlut;
/* 0x68 */ u32 offsetData;
} CARDStat;
void CardInit( void );
void CARDUpdateRegisters( void );
s32 CardFindFreeEntry( void );
s32 CardOpenFile( char *Filename, CARDFileInfo *CFInfo );
void CardCreateFile( char *Filename, u32 Size, CARDFileInfo *CFInfo );
#endif

30
CardPatches.c Normal file
View File

@ -0,0 +1,30 @@
#ifndef __CARDPATCHES__
#define __CARDPATCHES__
#include "asm\__CARDSync.h"
#include "asm\CARDCheck.h"
#include "asm\CARDCheckAsync.h"
#include "asm\CARDCheckEX.h"
#include "asm\CARDClose.h"
#include "asm\CARDCreate.h"
#include "asm\CARDDelete.h"
#include "asm\CARDFastOpen.h"
#include "asm\CARDFreeBlocks.h"
#include "asm\CARDGetEncoding.h"
#include "asm\CARDGetMemSize.h"
#include "asm\CARDGetSerialNo.h"
#include "asm\CARDGetStats.h"
#include "asm\CARDMount.h"
#include "asm\CARDMountAsync.h"
#include "asm\CARDOpen.h"
#include "asm\CARDProbe.h"
#include "asm\CARDProbeEX.h"
#include "asm\CARDRead.h"
#include "asm\CARDSetStats.h"
#include "asm\CARDWrite.h"
#include "asm\CARDGetResultCode.h"
#include "asm\CARDGetXferredBytes.h"
#include "asm\CARDFastDelete.h"
#include "asm\CARDRename.h"
#endif

448
CheatCode.c Normal file
View File

@ -0,0 +1,448 @@
#include "global.h"
unsigned char kenobigcDBG[4288] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x27, 0x74, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08,
0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c,
0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14,
0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff,
0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00,
0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10,
0x48, 0x00, 0x06, 0x55, 0x3a, 0xa0, 0x00, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0,
0x3f, 0x00, 0xcc, 0x00, 0x63, 0xf2, 0x27, 0x74, 0x80, 0x01, 0x00, 0xac, 0x90, 0x12, 0x00, 0x04,
0x92, 0xb8, 0x64, 0x3c, 0x48, 0x00, 0x04, 0x2d, 0x41, 0x82, 0x05, 0xa4, 0x2c, 0x1d, 0x00, 0x04,
0x40, 0x80, 0x00, 0x10, 0x2c, 0x1d, 0x00, 0x01, 0x41, 0x80, 0x05, 0x94, 0x48, 0x00, 0x03, 0x4c,
0x41, 0x82, 0x04, 0xf0, 0x2c, 0x1d, 0x00, 0x06, 0x41, 0x82, 0x00, 0x8c, 0x2c, 0x1d, 0x00, 0x07,
0x41, 0x82, 0x03, 0x30, 0x2c, 0x1d, 0x00, 0x08, 0x41, 0x82, 0x05, 0x80, 0x2c, 0x1d, 0x00, 0x09,
0x41, 0x82, 0x00, 0xa0, 0x2c, 0x1d, 0x00, 0x10, 0x41, 0x82, 0x00, 0x98, 0x2c, 0x1d, 0x00, 0x2f,
0x41, 0x82, 0x00, 0x70, 0x2c, 0x1d, 0x00, 0x30, 0x41, 0x82, 0x00, 0x78, 0x2c, 0x1d, 0x00, 0x38,
0x41, 0x82, 0x05, 0x28, 0x2c, 0x1d, 0x00, 0x40, 0x41, 0x82, 0x03, 0x40, 0x2c, 0x1d, 0x00, 0x41,
0x41, 0x82, 0x03, 0x58, 0x2c, 0x1d, 0x00, 0x44, 0x41, 0x82, 0x00, 0x68, 0x2c, 0x1d, 0x00, 0x50,
0x41, 0x82, 0x00, 0x20, 0x2c, 0x1d, 0x00, 0x60, 0x41, 0x82, 0x00, 0x24, 0x2c, 0x1d, 0x00, 0x89,
0x41, 0x82, 0x00, 0x50, 0x2c, 0x1d, 0x00, 0x99, 0x41, 0x82, 0x05, 0x0c, 0x48, 0x00, 0x05, 0x10,
0x80, 0x72, 0x00, 0x00, 0x48, 0x00, 0x04, 0x29, 0x48, 0x00, 0x05, 0x04, 0x48, 0x00, 0x05, 0x89,
0x48, 0x00, 0x04, 0xfc, 0x38, 0x80, 0x00, 0x01, 0x90, 0x92, 0x00, 0x00, 0x48, 0x00, 0x04, 0xf0,
0x48, 0x00, 0x04, 0x09, 0x3a, 0x00, 0x00, 0xa0, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0x14,
0x38, 0x60, 0x01, 0x20, 0x63, 0xec, 0x27, 0x98, 0x48, 0x00, 0x03, 0xc9, 0x48, 0x00, 0x04, 0xd0,
0x2f, 0x1d, 0x00, 0x10, 0x2e, 0x9d, 0x00, 0x44, 0x63, 0xe4, 0x1a, 0xb4, 0x3c, 0x60, 0x80, 0x00,
0x60, 0x63, 0x03, 0x00, 0x48, 0x00, 0x05, 0x09, 0x38, 0x63, 0x0a, 0x00, 0x48, 0x00, 0x05, 0x01,
0x38, 0x63, 0x06, 0x00, 0x48, 0x00, 0x04, 0xf9, 0x63, 0xec, 0x27, 0x88, 0x92, 0xac, 0x00, 0x00,
0x92, 0xac, 0x00, 0x04, 0x92, 0xac, 0x00, 0x08, 0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18,
0x80, 0x72, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x02, 0x40, 0x82, 0x00, 0x0c, 0x41, 0x96, 0x00, 0x0c,
0x48, 0x00, 0x00, 0x20, 0x38, 0x60, 0x00, 0x00, 0x90, 0x6c, 0x00, 0x0c, 0x40, 0x82, 0x00, 0x14,
0x40, 0x96, 0x00, 0x10, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x02, 0x14,
0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18, 0x41, 0x96, 0x04, 0x54, 0x41, 0x9a, 0x00, 0x08,
0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x03, 0x09, 0x40, 0x99, 0x00, 0x10,
0x39, 0x8c, 0x00, 0x04, 0x38, 0x60, 0x00, 0x04, 0x48, 0x00, 0x02, 0xf9, 0x63, 0xe4, 0x27, 0x88,
0x80, 0x64, 0x00, 0x00, 0x80, 0x84, 0x00, 0x04, 0x7c, 0x72, 0xfb, 0xa6, 0x7c, 0x95, 0xfb, 0xa6,
0x48, 0x00, 0x04, 0x1c, 0x7c, 0x32, 0x43, 0xa6, 0x7c, 0x3a, 0x02, 0xa6, 0x7c, 0x73, 0x43, 0xa6,
0x7c, 0x7b, 0x02, 0xa6, 0x54, 0x63, 0x05, 0xa8, 0x90, 0x60, 0x27, 0xb0, 0x54, 0x63, 0x06, 0x1e,
0x60, 0x63, 0x20, 0x00, 0x7c, 0x7b, 0x03, 0xa6, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x1a, 0xe8,
0x7c, 0x7a, 0x03, 0xa6, 0x4c, 0x00, 0x00, 0x64, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x27, 0x98,
0x90, 0x23, 0x00, 0x14, 0x7c, 0x61, 0x1b, 0x78, 0x7c, 0x73, 0x42, 0xa6, 0xbc, 0x41, 0x00, 0x24,
0x7c, 0x24, 0x0b, 0x78, 0x7c, 0x32, 0x42, 0xa6, 0x90, 0x04, 0x00, 0x1c, 0x90, 0x24, 0x00, 0x20,
0x7c, 0x68, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x9c, 0x7c, 0x60, 0x00, 0x26, 0x90, 0x64, 0x00, 0x00,
0x7c, 0x61, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x04, 0x7c, 0x69, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x08,
0x7c, 0x72, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x0c, 0x7c, 0x73, 0x02, 0xa6, 0x90, 0x64, 0x00, 0x10,
0x39, 0x20, 0x00, 0x00, 0x7d, 0x32, 0xfb, 0xa6, 0x7d, 0x35, 0xfb, 0xa6, 0x3c, 0xa0, 0x80, 0x00,
0x60, 0xa5, 0x1b, 0x70, 0x3f, 0xe0, 0xd0, 0x04, 0x63, 0xff, 0x00, 0xa0, 0x93, 0xe5, 0x00, 0x00,
0x7c, 0x00, 0x28, 0x6c, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac, 0x4c, 0x00, 0x01, 0x2c,
0xd0, 0x04, 0x00, 0xa0, 0x3b, 0xff, 0x00, 0x04, 0x3f, 0xff, 0x00, 0x20, 0x57, 0xf0, 0x01, 0x4b,
0x41, 0x82, 0xff, 0xdc, 0x3f, 0xe0, 0x80, 0x00, 0x63, 0xe5, 0x27, 0x88, 0x82, 0x05, 0x00, 0x00,
0x82, 0x25, 0x00, 0x04, 0x82, 0x65, 0x00, 0x0c, 0x2c, 0x13, 0x00, 0x00, 0x41, 0x82, 0x00, 0x74,
0x2c, 0x13, 0x00, 0x02, 0x40, 0x82, 0x00, 0x18, 0x81, 0x24, 0x00, 0x14, 0x39, 0x33, 0x00, 0x03,
0x91, 0x25, 0x00, 0x00, 0x91, 0x25, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x6c, 0x7c, 0x10, 0x98, 0x00,
0x41, 0x82, 0x00, 0x38, 0x7c, 0x11, 0x98, 0x00, 0x41, 0x82, 0x00, 0x30, 0x7d, 0x30, 0x8a, 0x14,
0x91, 0x25, 0x00, 0x0c, 0x82, 0x05, 0x00, 0x08, 0x2c, 0x10, 0x00, 0x00, 0x41, 0x82, 0x00, 0x48,
0x80, 0x64, 0x00, 0x10, 0x7c, 0x10, 0x18, 0x00, 0x40, 0x82, 0x00, 0x10, 0x3a, 0x00, 0x00, 0x00,
0x92, 0x05, 0x00, 0x08, 0x48, 0x00, 0x00, 0x30, 0x3a, 0x20, 0x00, 0x00, 0x92, 0x25, 0x00, 0x0c,
0x81, 0x24, 0x00, 0x18, 0x61, 0x29, 0x04, 0x00, 0x91, 0x24, 0x00, 0x18, 0x48, 0x00, 0x00, 0x30,
0x7e, 0x12, 0xfb, 0xa6, 0x7e, 0x35, 0xfb, 0xa6, 0x39, 0x20, 0x00, 0x01, 0x91, 0x25, 0x00, 0x0c,
0x48, 0x00, 0x00, 0x1c, 0x38, 0xa0, 0x00, 0x02, 0x63, 0xe4, 0x27, 0x74, 0x90, 0xa4, 0x00, 0x00,
0x38, 0x60, 0x00, 0x11, 0x48, 0x00, 0x01, 0xb9, 0x4b, 0xff, 0xfc, 0x71, 0x7c, 0x20, 0x00, 0xa6,
0x54, 0x21, 0x07, 0xfa, 0x54, 0x21, 0x04, 0x5e, 0x7c, 0x20, 0x01, 0x24, 0x63, 0xe1, 0x27, 0x98,
0x80, 0x61, 0x00, 0x00, 0x7c, 0x6f, 0xf1, 0x20, 0x80, 0x61, 0x00, 0x14, 0x7c, 0x7a, 0x03, 0xa6,
0x80, 0x61, 0x00, 0x18, 0x7c, 0x7b, 0x03, 0xa6, 0x80, 0x61, 0x00, 0x9c, 0x7c, 0x68, 0x03, 0xa6,
0xb8, 0x41, 0x00, 0x24, 0x80, 0x01, 0x00, 0x1c, 0x80, 0x21, 0x00, 0x20, 0x4c, 0x00, 0x00, 0x64,
0x92, 0xb2, 0x00, 0x00, 0x48, 0x00, 0x02, 0x54, 0x2e, 0x9d, 0x00, 0x02, 0x38, 0x60, 0x00, 0x08,
0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xfd, 0x80, 0xac, 0x00, 0x00, 0x80, 0x6c, 0x00, 0x04,
0x98, 0x65, 0x00, 0x00, 0x41, 0x94, 0x00, 0x10, 0xb0, 0x65, 0x00, 0x00, 0x41, 0x96, 0x00, 0x08,
0x90, 0x65, 0x00, 0x00, 0x7c, 0x00, 0x28, 0xac, 0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x2f, 0xac,
0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x02, 0x08, 0x48, 0x00, 0x01, 0x21, 0x38, 0x60, 0x00, 0x04,
0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0xbd, 0x82, 0x0c, 0x00, 0x00, 0x3d, 0x80, 0x80, 0x00,
0x61, 0x8c, 0x28, 0xb8, 0x48, 0x00, 0x00, 0x1c, 0x48, 0x00, 0x01, 0x01, 0x38, 0x60, 0x00, 0x08,
0x63, 0xec, 0x27, 0x7c, 0x48, 0x00, 0x00, 0x9d, 0x82, 0x0c, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00,
0x63, 0xfb, 0x27, 0x84, 0x3a, 0x20, 0x0f, 0x80, 0x48, 0x00, 0x02, 0x39, 0x41, 0x82, 0x00, 0x20,
0x7e, 0x23, 0x8b, 0x78, 0x48, 0x00, 0x00, 0x7d, 0x48, 0x00, 0x00, 0xd1, 0x41, 0x82, 0xff, 0xfc,
0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff, 0x41, 0x81, 0xff, 0xe8, 0x80, 0x7b, 0x00, 0x00,
0x2c, 0x03, 0x00, 0x00, 0x41, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x59, 0x7c, 0x00, 0x60, 0xac,
0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x67, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x48, 0x00, 0x01, 0x80,
0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xa0, 0x00, 0x48, 0x00, 0x00, 0x15, 0x76, 0x03, 0x08, 0x00,
0x56, 0x1d, 0x86, 0x3e, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x92, 0xf8, 0x68, 0x14,
0x90, 0x78, 0x68, 0x24, 0x92, 0xd8, 0x68, 0x20, 0x80, 0xb8, 0x68, 0x20, 0x70, 0xa5, 0x00, 0x01,
0x40, 0x82, 0xff, 0xf8, 0x82, 0x18, 0x68, 0x24, 0x90, 0xb8, 0x68, 0x14, 0x4e, 0x80, 0x00, 0x20,
0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x48, 0x00, 0x00, 0x79,
0x48, 0x00, 0x00, 0x75, 0x4b, 0xff, 0xff, 0xad, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xae, 0x61, 0xae,
0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xe8, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20,
0x7d, 0x48, 0x02, 0xa6, 0x7c, 0x69, 0x03, 0xa6, 0x39, 0xc0, 0x00, 0x00, 0x7c, 0x6c, 0x70, 0xae,
0x48, 0x00, 0x00, 0x1d, 0x41, 0x82, 0xff, 0xf8, 0x39, 0xce, 0x00, 0x01, 0x42, 0x00, 0xff, 0xf0,
0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x38, 0x60, 0x00, 0xaa, 0x7f, 0xc8, 0x02, 0xa6,
0x54, 0x63, 0xa0, 0x16, 0x64, 0x63, 0xb0, 0x00, 0x3a, 0xc0, 0x00, 0x19, 0x3a, 0xe0, 0x00, 0xd0,
0x3f, 0x00, 0xcc, 0x00, 0x4b, 0xff, 0xff, 0x69, 0x56, 0x03, 0x37, 0xff, 0x7f, 0xc8, 0x03, 0xa6,
0x4e, 0x80, 0x00, 0x20, 0x7f, 0xc8, 0x02, 0xa6, 0x3c, 0x60, 0xd0, 0x00, 0x4b, 0xff, 0xff, 0x51,
0x56, 0x03, 0x37, 0xff, 0x41, 0x82, 0xff, 0xf4, 0x7f, 0xc8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20,
0x4b, 0xff, 0xff, 0xb9, 0x38, 0x60, 0x00, 0x08, 0x63, 0xec, 0x27, 0x7c, 0x4b, 0xff, 0xff, 0x55,
0x80, 0xac, 0x00, 0x04, 0x81, 0x8c, 0x00, 0x00, 0x63, 0xfb, 0x27, 0x84, 0x62, 0xb1, 0xf8, 0x00,
0x7e, 0x0c, 0x28, 0x50, 0x48, 0x00, 0x00, 0xed, 0x41, 0x81, 0x00, 0x10, 0x82, 0x3b, 0x00, 0x00,
0x2c, 0x11, 0x00, 0x00, 0x41, 0x82, 0x00, 0x68, 0x7e, 0x23, 0x8b, 0x78, 0x4b, 0xff, 0xff, 0x55,
0x4b, 0xff, 0xff, 0xa5, 0x4b, 0xff, 0xff, 0xa1, 0x4b, 0xff, 0xfe, 0xd9, 0x41, 0x82, 0xff, 0xf4,
0x2c, 0x1d, 0x00, 0xcc, 0x41, 0x82, 0x00, 0x48, 0x2c, 0x1d, 0x00, 0xbb, 0x41, 0x82, 0xff, 0xdc,
0x2c, 0x1d, 0x00, 0xaa, 0x40, 0x82, 0xff, 0xdc, 0x7d, 0x8c, 0x72, 0x14, 0x35, 0x6b, 0xff, 0xff,
0x41, 0x80, 0x00, 0x2c, 0x4b, 0xff, 0xff, 0xb4, 0x7e, 0xb5, 0xfb, 0xa6, 0x7e, 0xb2, 0xfb, 0xa6,
0x63, 0xe4, 0x27, 0x98, 0x81, 0x24, 0x00, 0x18, 0x55, 0x29, 0x05, 0xa8, 0x91, 0x24, 0x00, 0x18,
0x48, 0x00, 0x00, 0x0c, 0x38, 0x60, 0x00, 0x80, 0x4b, 0xff, 0xff, 0x25, 0x80, 0x92, 0x00, 0x00,
0x2c, 0x04, 0x00, 0x00, 0x40, 0x82, 0xfa, 0x50, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98,
0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6,
0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6,
0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08,
0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x7e, 0x23, 0x20, 0x50,
0x3c, 0xa0, 0x48, 0x00, 0x52, 0x25, 0x01, 0xba, 0x90, 0xa3, 0x00, 0x00, 0x7c, 0x00, 0x18, 0xac,
0x7c, 0x00, 0x04, 0xac, 0x7c, 0x00, 0x1f, 0xac, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20,
0x7d, 0x70, 0x8b, 0xd7, 0x7d, 0x4b, 0x89, 0xd6, 0x7d, 0x4a, 0x80, 0x50, 0x91, 0x5b, 0x00, 0x00,
0x4e, 0x80, 0x00, 0x20, 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x28, 0xb8,
0x63, 0xe7, 0x18, 0x08, 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00,
0x3c, 0x60, 0x00, 0xd0, 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00,
0x40, 0x82, 0x00, 0x18, 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c,
0x39, 0xef, 0x00, 0x08, 0x48, 0x00, 0x00, 0x0c, 0x7f, 0xa8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20,
0x80, 0x6f, 0x00, 0x00, 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01,
0x2f, 0x89, 0x00, 0x00, 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e,
0x74, 0x6b, 0x10, 0x00, 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c,
0x48, 0x00, 0x00, 0x08, 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01,
0x41, 0xa0, 0x00, 0x2c, 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac,
0x41, 0x82, 0x02, 0x50, 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0,
0x2c, 0x0a, 0x00, 0x07, 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14,
0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84,
0x2e, 0x05, 0x00, 0x01, 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10,
0x7c, 0x89, 0x61, 0xae, 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e,
0x39, 0x29, 0x00, 0x02, 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54,
0x55, 0x8c, 0x00, 0x3a, 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78,
0x40, 0x9e, 0x04, 0xc8, 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae,
0x7c, 0xa9, 0x61, 0xae, 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24,
0x80, 0xaf, 0xff, 0xf8, 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e,
0x54, 0xa5, 0x27, 0x3e, 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14,
0x7c, 0x89, 0x61, 0xae, 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08,
0x7c, 0x89, 0x61, 0x2e, 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff,
0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10,
0x55, 0x08, 0xf8, 0x7e, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04,
0x2d, 0x8a, 0x00, 0x05, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8,
0x7d, 0x8c, 0x1a, 0x14, 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c,
0x40, 0x94, 0x00, 0x10, 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c,
0x55, 0x8c, 0x00, 0x3c, 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e,
0x7d, 0x6b, 0x48, 0x38, 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03,
0x41, 0x82, 0x00, 0x18, 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c,
0x40, 0x9a, 0x00, 0x20, 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10,
0x41, 0x99, 0x00, 0x10, 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01,
0x40, 0x8e, 0xfe, 0x40, 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20,
0x70, 0x6c, 0x00, 0x08, 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10,
0x39, 0x8b, 0x00, 0x10, 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16,
0x91, 0x6f, 0xff, 0xf8, 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba,
0x54, 0x6e, 0x87, 0xfe, 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03,
0x2e, 0x8e, 0x00, 0x02, 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34,
0x7c, 0x84, 0x7a, 0x14, 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c,
0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14,
0x2e, 0x8e, 0x00, 0x01, 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff,
0x41, 0x82, 0x00, 0x3c, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30,
0x7c, 0x84, 0x82, 0x14, 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c,
0x7d, 0x27, 0x48, 0x2e, 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e,
0x4b, 0xff, 0xfd, 0x80, 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c,
0x7c, 0x86, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64,
0x54, 0x89, 0x1e, 0x78, 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48,
0x54, 0x6b, 0x50, 0x03, 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10,
0x41, 0xbe, 0xfd, 0x40, 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03,
0x41, 0x81, 0x00, 0x10, 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24,
0x7d, 0xe7, 0x49, 0x2e, 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14,
0x4b, 0xff, 0xfd, 0x10, 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14,
0x54, 0x64, 0x04, 0x3e, 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4,
0x81, 0x25, 0x00, 0x04, 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff,
0x91, 0x25, 0x00, 0x04, 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4,
0x54, 0x6b, 0x16, 0xba, 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe,
0x41, 0x92, 0x00, 0x84, 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03,
0x40, 0x90, 0x00, 0x90, 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08,
0x7c, 0x8c, 0x22, 0x14, 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18,
0x41, 0x9a, 0x00, 0x0c, 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00,
0x48, 0x00, 0x00, 0xf0, 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e,
0x41, 0xb9, 0x00, 0x20, 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01,
0x48, 0x00, 0x00, 0x18, 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c,
0x91, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4,
0x4b, 0xff, 0xfc, 0x40, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14,
0x71, 0xc5, 0x00, 0x01, 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94,
0x54, 0x6a, 0x87, 0xbe, 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08,
0x3a, 0x6f, 0xff, 0xfc, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01,
0x41, 0x82, 0x00, 0x08, 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10,
0x7d, 0x33, 0x4b, 0x78, 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f,
0x2c, 0x05, 0x00, 0x09, 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14,
0x48, 0x00, 0x00, 0x40, 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78,
0x48, 0x00, 0x00, 0x30, 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78,
0x48, 0x00, 0x00, 0x20, 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30,
0x48, 0x00, 0x00, 0x10, 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30,
0x90, 0x9a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84,
0xc0, 0x5a, 0x00, 0x00, 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a,
0x48, 0x00, 0x00, 0x08, 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64,
0x7d, 0x48, 0x02, 0xa6, 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00,
0x81, 0x33, 0x00, 0x00, 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44,
0x54, 0x69, 0xc0, 0x3e, 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c,
0x7e, 0x31, 0x22, 0x14, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f,
0x38, 0xa0, 0x00, 0x00, 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae,
0x38, 0xa5, 0x00, 0x01, 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04,
0x55, 0x31, 0x36, 0xba, 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08,
0x7d, 0xd1, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba,
0x2c, 0x09, 0x00, 0x3c, 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78,
0x41, 0x96, 0x00, 0x08, 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04,
0x40, 0x80, 0x00, 0x28, 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c,
0x4b, 0xff, 0xff, 0xad, 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38,
0x7e, 0x24, 0x20, 0x38, 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc,
0x7c, 0x9a, 0x23, 0x78, 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c,
0x7d, 0xe8, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07,
0x55, 0xef, 0x00, 0x38, 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c,
0x3c, 0xa0, 0x48, 0x00, 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20,
0x40, 0xbe, 0xfa, 0x50, 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba,
0x50, 0x65, 0x07, 0xfe, 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc,
0x7d, 0x2c, 0x78, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04,
0x7d, 0x6f, 0x22, 0x14, 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba,
0x90, 0xab, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28,
0x4b, 0xff, 0xfb, 0x28, 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e,
0x7c, 0x0c, 0x20, 0x00, 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0,
0x4b, 0xff, 0xf9, 0xe0, 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01,
0x7c, 0x05, 0x18, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02,
0x57, 0x45, 0xff, 0xff, 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc,
0x53, 0x48, 0x07, 0xfe, 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38,
0x2c, 0x05, 0x00, 0x01, 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14,
0x2c, 0x05, 0x00, 0x03, 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x80, 0x54, 0xcc, 0x00, 0x0c,
0x54, 0x97, 0x46, 0x3e, 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc,
0x56, 0xf9, 0x06, 0x31, 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a,
0x41, 0x82, 0x00, 0x18, 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02,
0x3b, 0x39, 0x00, 0x04, 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c,
0x3b, 0x20, 0x00, 0x00, 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78,
0x3b, 0x5a, 0x00, 0x02, 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac,
0x4b, 0xff, 0xfe, 0x90, 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03,
0x41, 0x81, 0x00, 0x88, 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02,
0x54, 0x97, 0x00, 0x1e, 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08,
0x62, 0xf7, 0x30, 0x00, 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50,
0x3b, 0x20, 0x00, 0x00, 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e,
0x3b, 0x39, 0x00, 0x01, 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00,
0x41, 0x81, 0x00, 0x14, 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04,
0x4b, 0xff, 0xff, 0xd0, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8,
0x92, 0xef, 0xff, 0xfc, 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8,
0x60, 0x63, 0x01, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08,
0x7c, 0x90, 0x23, 0x78, 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14,
0x4b, 0xff, 0xf8, 0x70, 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14,
0x54, 0x69, 0x06, 0xff, 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff,
0x40, 0x82, 0x00, 0x08, 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08,
0x7c, 0xa6, 0x2b, 0x78, 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78,
0x4b, 0xff, 0xf8, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//unsigned char kenobigc[2736] =
//{
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x21, 0x60, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x21, 0xff, 0x58, 0x90, 0x01, 0x00, 0x08,
// 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0xac, 0x7c, 0x00, 0x00, 0x26, 0x90, 0x01, 0x00, 0x0c,
// 0x7c, 0x09, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x10, 0x7c, 0x01, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x14,
// 0xbc, 0x61, 0x00, 0x18, 0x7f, 0x20, 0x00, 0xa6, 0x63, 0x3a, 0x20, 0x00, 0x73, 0x5a, 0xf9, 0xff,
// 0x7f, 0x40, 0x01, 0x24, 0xd8, 0x41, 0x00, 0x98, 0xd8, 0x61, 0x00, 0xa0, 0x3f, 0xe0, 0x80, 0x00,
// 0x3e, 0x80, 0xcc, 0x00, 0xa3, 0x94, 0x40, 0x10, 0x63, 0x95, 0x00, 0xff, 0xb2, 0xb4, 0x40, 0x10,
// 0x7f, 0xa8, 0x02, 0xa6, 0x3d, 0xe0, 0x80, 0x00, 0x61, 0xef, 0x22, 0xa8, 0x63, 0xe7, 0x18, 0x08,
// 0x3c, 0xc0, 0x80, 0x00, 0x7c, 0xd0, 0x33, 0x78, 0x39, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x00, 0xd0,
// 0x60, 0x63, 0xc0, 0xde, 0x80, 0x8f, 0x00, 0x00, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x18,
// 0x80, 0x8f, 0x00, 0x04, 0x7c, 0x03, 0x20, 0x00, 0x40, 0x82, 0x00, 0x0c, 0x39, 0xef, 0x00, 0x08,
// 0x48, 0x00, 0x00, 0x4c, 0x7f, 0xa8, 0x03, 0xa6, 0xb3, 0x94, 0x40, 0x10, 0xc8, 0x41, 0x00, 0x98,
// 0xc8, 0x61, 0x00, 0xa0, 0x7f, 0x20, 0x00, 0xa6, 0x80, 0x01, 0x00, 0xac, 0x7c, 0x08, 0x03, 0xa6,
// 0x80, 0x01, 0x00, 0x0c, 0x7c, 0x0f, 0xf1, 0x20, 0x80, 0x01, 0x00, 0x10, 0x7c, 0x09, 0x03, 0xa6,
// 0x80, 0x01, 0x00, 0x14, 0x7c, 0x01, 0x03, 0xa6, 0xb8, 0x61, 0x00, 0x18, 0x80, 0x01, 0x00, 0x08,
// 0x38, 0x21, 0x00, 0xa8, 0x4c, 0x00, 0x01, 0x2c, 0x4e, 0x80, 0x00, 0x20, 0x80, 0x6f, 0x00, 0x00,
// 0x80, 0x8f, 0x00, 0x04, 0x39, 0xef, 0x00, 0x08, 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00,
// 0x39, 0x20, 0x00, 0x00, 0x54, 0x6a, 0x1f, 0x7e, 0x54, 0x65, 0x3f, 0x7e, 0x74, 0x6b, 0x10, 0x00,
// 0x54, 0x63, 0x01, 0xfe, 0x40, 0x82, 0x00, 0x0c, 0x54, 0xcc, 0x00, 0x0c, 0x48, 0x00, 0x00, 0x08,
// 0x7e, 0x0c, 0x83, 0x78, 0x2e, 0x05, 0x00, 0x00, 0x2c, 0x0a, 0x00, 0x01, 0x41, 0xa0, 0x00, 0x2c,
// 0x41, 0xa2, 0x00, 0xe4, 0x2c, 0x0a, 0x00, 0x03, 0x41, 0xa0, 0x01, 0xac, 0x41, 0x82, 0x02, 0x50,
// 0x2c, 0x0a, 0x00, 0x05, 0x41, 0x80, 0x02, 0xd4, 0x41, 0xa2, 0x04, 0xe0, 0x2c, 0x0a, 0x00, 0x07,
// 0x41, 0xa0, 0x05, 0x0c, 0x48, 0x00, 0x05, 0xf0, 0x7d, 0x8c, 0x1a, 0x14, 0x2c, 0x05, 0x00, 0x03,
// 0x41, 0x82, 0x00, 0x48, 0x41, 0x81, 0x00, 0x60, 0x40, 0xbe, 0xff, 0x84, 0x2e, 0x05, 0x00, 0x01,
// 0x41, 0x91, 0x00, 0x2c, 0x54, 0x8a, 0x84, 0x3e, 0x41, 0x92, 0x00, 0x10, 0x7c, 0x89, 0x61, 0xae,
// 0x39, 0x29, 0x00, 0x01, 0x48, 0x00, 0x00, 0x0c, 0x7c, 0x89, 0x63, 0x2e, 0x39, 0x29, 0x00, 0x02,
// 0x35, 0x4a, 0xff, 0xff, 0x40, 0xa0, 0xff, 0xe4, 0x4b, 0xff, 0xff, 0x54, 0x55, 0x8c, 0x00, 0x3a,
// 0x90, 0x8c, 0x00, 0x00, 0x4b, 0xff, 0xff, 0x48, 0x7c, 0x89, 0x23, 0x78, 0x40, 0x9e, 0x04, 0xc8,
// 0x35, 0x29, 0xff, 0xff, 0x41, 0x80, 0x04, 0xc0, 0x7c, 0xa9, 0x78, 0xae, 0x7c, 0xa9, 0x61, 0xae,
// 0x4b, 0xff, 0xff, 0xf0, 0x39, 0xef, 0x00, 0x08, 0x40, 0xbe, 0xff, 0x24, 0x80, 0xaf, 0xff, 0xf8,
// 0x81, 0x6f, 0xff, 0xfc, 0x54, 0xb1, 0x04, 0x3e, 0x54, 0xaa, 0x85, 0x3e, 0x54, 0xa5, 0x27, 0x3e,
// 0x2e, 0x85, 0x00, 0x01, 0x41, 0x96, 0x00, 0x10, 0x41, 0xb5, 0x00, 0x14, 0x7c, 0x89, 0x61, 0xae,
// 0x48, 0x00, 0x00, 0x10, 0x7c, 0x89, 0x63, 0x2e, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x89, 0x61, 0x2e,
// 0x7c, 0x84, 0x5a, 0x14, 0x7d, 0x29, 0x8a, 0x14, 0x35, 0x4a, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4,
// 0x4b, 0xff, 0xfe, 0xdc, 0x54, 0x69, 0x07, 0xff, 0x41, 0x82, 0x00, 0x10, 0x55, 0x08, 0xf8, 0x7e,
// 0x71, 0x09, 0x00, 0x01, 0x2f, 0x89, 0x00, 0x00, 0x2e, 0x85, 0x00, 0x04, 0x2d, 0x8a, 0x00, 0x05,
// 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x78, 0x41, 0x8d, 0x04, 0xb8, 0x7d, 0x8c, 0x1a, 0x14,
// 0x41, 0x8c, 0x00, 0x0c, 0x41, 0x94, 0x00, 0x30, 0x48, 0x00, 0x00, 0x1c, 0x40, 0x94, 0x00, 0x10,
// 0x55, 0x8c, 0x00, 0x3a, 0x81, 0x6c, 0x00, 0x00, 0x48, 0x00, 0x00, 0x1c, 0x55, 0x8c, 0x00, 0x3c,
// 0xa1, 0x6c, 0x00, 0x00, 0x7c, 0x89, 0x20, 0xf8, 0x55, 0x29, 0x84, 0x3e, 0x7d, 0x6b, 0x48, 0x38,
// 0x54, 0x84, 0x04, 0x3e, 0x7f, 0x0b, 0x20, 0x40, 0x70, 0xa9, 0x00, 0x03, 0x41, 0x82, 0x00, 0x18,
// 0x2c, 0x09, 0x00, 0x02, 0x41, 0x82, 0x00, 0x18, 0x41, 0x81, 0x00, 0x1c, 0x40, 0x9a, 0x00, 0x20,
// 0x48, 0x00, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x18, 0x48, 0x00, 0x00, 0x10, 0x41, 0x99, 0x00, 0x10,
// 0x48, 0x00, 0x00, 0x08, 0x41, 0x98, 0x00, 0x08, 0x61, 0x08, 0x00, 0x01, 0x40, 0x8e, 0xfe, 0x40,
// 0x41, 0x94, 0xfe, 0x3c, 0x81, 0x6f, 0xff, 0xf8, 0x40, 0x9e, 0x00, 0x20, 0x70, 0x6c, 0x00, 0x08,
// 0x41, 0x82, 0x00, 0x0c, 0x71, 0x0c, 0x00, 0x01, 0x41, 0x82, 0x00, 0x10, 0x39, 0x8b, 0x00, 0x10,
// 0x51, 0x8b, 0x03, 0x36, 0x48, 0x00, 0x00, 0x08, 0x55, 0x6b, 0x07, 0x16, 0x91, 0x6f, 0xff, 0xf8,
// 0x4b, 0xff, 0xfe, 0x0c, 0x40, 0xbe, 0xfe, 0x08, 0x54, 0x69, 0x16, 0xba, 0x54, 0x6e, 0x87, 0xfe,
// 0x2d, 0x8e, 0x00, 0x00, 0x2e, 0x05, 0x00, 0x04, 0x70, 0xae, 0x00, 0x03, 0x2e, 0x8e, 0x00, 0x02,
// 0x41, 0x94, 0x00, 0x14, 0x41, 0x96, 0x00, 0x50, 0x7c, 0x64, 0x07, 0x34, 0x7c, 0x84, 0x7a, 0x14,
// 0x48, 0x00, 0x00, 0x68, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
// 0x7c, 0x84, 0x4a, 0x14, 0x41, 0x8e, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14, 0x2e, 0x8e, 0x00, 0x01,
// 0x41, 0x96, 0x00, 0x08, 0x80, 0x84, 0x00, 0x00, 0x54, 0x63, 0x67, 0xff, 0x41, 0x82, 0x00, 0x3c,
// 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x84, 0x32, 0x14, 0x48, 0x00, 0x00, 0x30, 0x7c, 0x84, 0x82, 0x14,
// 0x48, 0x00, 0x00, 0x28, 0x54, 0x65, 0xa7, 0xff, 0x41, 0x82, 0x00, 0x0c, 0x7d, 0x27, 0x48, 0x2e,
// 0x7c, 0x84, 0x4a, 0x14, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0xcc, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x80,
// 0x7e, 0x0c, 0x21, 0x2e, 0x4b, 0xff, 0xfd, 0x78, 0x40, 0x90, 0x00, 0x0c, 0x7c, 0x86, 0x23, 0x78,
// 0x4b, 0xff, 0xfd, 0x6c, 0x7c, 0x90, 0x23, 0x78, 0x4b, 0xff, 0xfd, 0x64, 0x54, 0x89, 0x1e, 0x78,
// 0x39, 0x29, 0x00, 0x40, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x80, 0x00, 0x48, 0x54, 0x6b, 0x50, 0x03,
// 0x41, 0x82, 0x00, 0x14, 0x41, 0x81, 0x00, 0x08, 0x48, 0x00, 0x00, 0x10, 0x41, 0xbe, 0xfd, 0x40,
// 0x48, 0x00, 0x00, 0x08, 0x40, 0xbe, 0xfd, 0x38, 0x2c, 0x05, 0x00, 0x03, 0x41, 0x81, 0x00, 0x10,
// 0x41, 0xa2, 0x00, 0x10, 0x7d, 0xe7, 0x48, 0x2e, 0x4b, 0xff, 0xfd, 0x24, 0x7d, 0xe7, 0x49, 0x2e,
// 0x7c, 0x64, 0x07, 0x34, 0x54, 0x84, 0x1a, 0x78, 0x7d, 0xef, 0x22, 0x14, 0x4b, 0xff, 0xfd, 0x10,
// 0x40, 0xbe, 0xfd, 0x0c, 0x7c, 0xa7, 0x4a, 0x14, 0x40, 0x92, 0x00, 0x14, 0x54, 0x64, 0x04, 0x3e,
// 0x91, 0xe5, 0x00, 0x00, 0x90, 0x85, 0x00, 0x04, 0x4b, 0xff, 0xfc, 0xf4, 0x81, 0x25, 0x00, 0x04,
// 0x2c, 0x09, 0x00, 0x00, 0x41, 0xa2, 0xfc, 0xe8, 0x39, 0x29, 0xff, 0xff, 0x91, 0x25, 0x00, 0x04,
// 0x81, 0xe5, 0x00, 0x00, 0x4b, 0xff, 0xfc, 0xd8, 0x40, 0xbe, 0xfc, 0xd4, 0x54, 0x6b, 0x16, 0xba,
// 0x7f, 0x47, 0x5a, 0x14, 0x81, 0x3a, 0x00, 0x00, 0x54, 0x6e, 0x67, 0xbe, 0x41, 0x92, 0x00, 0x84,
// 0x2e, 0x05, 0x00, 0x05, 0x40, 0x90, 0x01, 0x74, 0x2e, 0x05, 0x00, 0x03, 0x40, 0x90, 0x00, 0x90,
// 0x2e, 0x05, 0x00, 0x01, 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x8c, 0x22, 0x14,
// 0x2f, 0x0e, 0x00, 0x01, 0x40, 0x92, 0x00, 0x24, 0x41, 0xb9, 0x00, 0x18, 0x41, 0x9a, 0x00, 0x0c,
// 0x88, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf8, 0xa0, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xf0,
// 0x80, 0x84, 0x00, 0x00, 0x48, 0x00, 0x00, 0xe8, 0x54, 0x73, 0xe5, 0x3e, 0x41, 0xb9, 0x00, 0x20,
// 0x41, 0x9a, 0x00, 0x10, 0x99, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x01, 0x48, 0x00, 0x00, 0x18,
// 0xb1, 0x24, 0x00, 0x00, 0x38, 0x84, 0x00, 0x02, 0x48, 0x00, 0x00, 0x0c, 0x91, 0x24, 0x00, 0x00,
// 0x38, 0x84, 0x00, 0x04, 0x36, 0x73, 0xff, 0xff, 0x40, 0x80, 0xff, 0xd4, 0x4b, 0xff, 0xfc, 0x40,
// 0x54, 0x65, 0x87, 0xff, 0x41, 0x82, 0x00, 0x08, 0x7c, 0x84, 0x62, 0x14, 0x71, 0xc5, 0x00, 0x01,
// 0x41, 0x82, 0x00, 0x9c, 0x7c, 0x84, 0x4a, 0x14, 0x48, 0x00, 0x00, 0x94, 0x54, 0x6a, 0x87, 0xbe,
// 0x54, 0x8e, 0x16, 0xba, 0x7e, 0x67, 0x72, 0x14, 0x40, 0x92, 0x00, 0x08, 0x3a, 0x6f, 0xff, 0xfc,
// 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00, 0x71, 0x4b, 0x00, 0x01, 0x41, 0x82, 0x00, 0x08,
// 0x7c, 0x9a, 0x23, 0x78, 0x71, 0x4b, 0x00, 0x02, 0x41, 0x82, 0x00, 0x10, 0x7d, 0x33, 0x4b, 0x78,
// 0x40, 0xb2, 0x00, 0x08, 0x7e, 0x6c, 0x9a, 0x14, 0x54, 0x65, 0x67, 0x3f, 0x2c, 0x05, 0x00, 0x09,
// 0x40, 0x80, 0x00, 0x54, 0x48, 0x00, 0x00, 0x79, 0x7c, 0x89, 0x22, 0x14, 0x48, 0x00, 0x00, 0x40,
// 0x7c, 0x89, 0x21, 0xd6, 0x48, 0x00, 0x00, 0x38, 0x7d, 0x24, 0x23, 0x78, 0x48, 0x00, 0x00, 0x30,
// 0x7d, 0x24, 0x20, 0x38, 0x48, 0x00, 0x00, 0x28, 0x7d, 0x24, 0x22, 0x78, 0x48, 0x00, 0x00, 0x20,
// 0x7d, 0x24, 0x20, 0x30, 0x48, 0x00, 0x00, 0x18, 0x7d, 0x24, 0x24, 0x30, 0x48, 0x00, 0x00, 0x10,
// 0x5d, 0x24, 0x20, 0x3e, 0x48, 0x00, 0x00, 0x08, 0x7d, 0x24, 0x26, 0x30, 0x90, 0x9a, 0x00, 0x00,
// 0x4b, 0xff, 0xfb, 0x8c, 0x2c, 0x05, 0x00, 0x0a, 0x41, 0x81, 0xfb, 0x84, 0xc0, 0x5a, 0x00, 0x00,
// 0xc0, 0x73, 0x00, 0x00, 0x41, 0x82, 0x00, 0x0c, 0xec, 0x43, 0x10, 0x2a, 0x48, 0x00, 0x00, 0x08,
// 0xec, 0x43, 0x00, 0xb2, 0xd0, 0x5a, 0x00, 0x00, 0x4b, 0xff, 0xfb, 0x64, 0x7d, 0x48, 0x02, 0xa6,
// 0x54, 0xa5, 0x1e, 0x78, 0x7d, 0x4a, 0x2a, 0x14, 0x80, 0x9a, 0x00, 0x00, 0x81, 0x33, 0x00, 0x00,
// 0x7d, 0x48, 0x03, 0xa6, 0x4e, 0x80, 0x00, 0x20, 0x40, 0xbe, 0xfb, 0x44, 0x54, 0x69, 0xc0, 0x3e,
// 0x7d, 0x8e, 0x63, 0x78, 0x48, 0x00, 0x00, 0x35, 0x41, 0x92, 0x00, 0x0c, 0x7e, 0x31, 0x22, 0x14,
// 0x48, 0x00, 0x00, 0x08, 0x7d, 0x29, 0x22, 0x14, 0x54, 0x64, 0xc4, 0x3f, 0x38, 0xa0, 0x00, 0x00,
// 0x41, 0x82, 0xfb, 0x1c, 0x7d, 0x45, 0x88, 0xae, 0x7d, 0x45, 0x49, 0xae, 0x38, 0xa5, 0x00, 0x01,
// 0x7c, 0x05, 0x20, 0x00, 0x4b, 0xff, 0xff, 0xec, 0x2e, 0x8a, 0x00, 0x04, 0x55, 0x31, 0x36, 0xba,
// 0x2c, 0x11, 0x00, 0x3c, 0x7e, 0x27, 0x88, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xd1, 0x73, 0x78,
// 0x41, 0x96, 0x00, 0x08, 0xa2, 0x31, 0x00, 0x00, 0x55, 0x29, 0x56, 0xba, 0x2c, 0x09, 0x00, 0x3c,
// 0x7d, 0x27, 0x48, 0x2e, 0x40, 0x82, 0x00, 0x08, 0x7d, 0xc9, 0x73, 0x78, 0x41, 0x96, 0x00, 0x08,
// 0xa1, 0x29, 0x00, 0x00, 0x4e, 0x80, 0x00, 0x20, 0x2c, 0x05, 0x00, 0x04, 0x40, 0x80, 0x00, 0x28,
// 0x7c, 0x89, 0x23, 0x78, 0x7d, 0xc3, 0x62, 0x14, 0x55, 0xce, 0x00, 0x3c, 0x4b, 0xff, 0xff, 0xad,
// 0x7c, 0x84, 0x20, 0xf8, 0x54, 0x84, 0x04, 0x3e, 0x7d, 0x2b, 0x20, 0x38, 0x7e, 0x24, 0x20, 0x38,
// 0x4b, 0xff, 0xfb, 0xc4, 0x54, 0x6b, 0xe4, 0x3e, 0x4b, 0xff, 0xfb, 0xbc, 0x7c, 0x9a, 0x23, 0x78,
// 0x54, 0x84, 0x18, 0x38, 0x40, 0x92, 0x00, 0x20, 0x40, 0x9e, 0x00, 0x0c, 0x7d, 0xe8, 0x03, 0xa6,
// 0x4e, 0x80, 0x00, 0x21, 0x7d, 0xe4, 0x7a, 0x14, 0x39, 0xef, 0x00, 0x07, 0x55, 0xef, 0x00, 0x38,
// 0x4b, 0xff, 0xfa, 0x6c, 0x2e, 0x05, 0x00, 0x03, 0x41, 0x91, 0x00, 0x5c, 0x3c, 0xa0, 0x48, 0x00,
// 0x7d, 0x83, 0x62, 0x14, 0x55, 0x8c, 0x00, 0x3a, 0x40, 0x92, 0x00, 0x20, 0x40, 0xbe, 0xfa, 0x50,
// 0x57, 0x44, 0x00, 0x3a, 0x7c, 0x8c, 0x20, 0x50, 0x50, 0x85, 0x01, 0xba, 0x50, 0x65, 0x07, 0xfe,
// 0x90, 0xac, 0x00, 0x00, 0x4b, 0xff, 0xfa, 0x38, 0x40, 0xbe, 0xff, 0xbc, 0x7d, 0x2c, 0x78, 0x50,
// 0x51, 0x25, 0x01, 0xba, 0x90, 0xac, 0x00, 0x00, 0x39, 0x8c, 0x00, 0x04, 0x7d, 0x6f, 0x22, 0x14,
// 0x39, 0x6b, 0xff, 0xfc, 0x7d, 0x2b, 0x60, 0x50, 0x51, 0x25, 0x01, 0xba, 0x90, 0xab, 0x00, 0x00,
// 0x4b, 0xff, 0xff, 0x94, 0x2e, 0x05, 0x00, 0x06, 0x41, 0x92, 0x00, 0x28, 0x4b, 0xff, 0xfb, 0x28,
// 0x55, 0x8c, 0x84, 0x3e, 0x57, 0x44, 0x84, 0x3e, 0x57, 0x5a, 0x04, 0x3e, 0x7c, 0x0c, 0x20, 0x00,
// 0x41, 0x80, 0xfb, 0xa8, 0x7c, 0x0c, 0xd0, 0x00, 0x40, 0x80, 0xfb, 0xa0, 0x4b, 0xff, 0xf9, 0xe0,
// 0x57, 0x45, 0xff, 0xfe, 0x68, 0xa5, 0x00, 0x01, 0x71, 0x03, 0x00, 0x01, 0x7c, 0x05, 0x18, 0x00,
// 0x41, 0x82, 0x00, 0x1c, 0x51, 0x1a, 0x0f, 0xbc, 0x6b, 0x5a, 0x00, 0x02, 0x57, 0x45, 0xff, 0xff,
// 0x41, 0x82, 0x00, 0x08, 0x6b, 0x5a, 0x00, 0x01, 0x93, 0x4f, 0xff, 0xfc, 0x53, 0x48, 0x07, 0xfe,
// 0x4b, 0xff, 0xf9, 0xac, 0x2c, 0x0b, 0x00, 0x00, 0x41, 0x82, 0x01, 0x38, 0x2c, 0x05, 0x00, 0x01,
// 0x41, 0x82, 0x00, 0x18, 0x2c, 0x05, 0x00, 0x02, 0x41, 0x82, 0x00, 0x14, 0x2c, 0x05, 0x00, 0x03,
// 0x41, 0x82, 0x00, 0x70, 0x4b, 0xff, 0xf9, 0x40, 0x54, 0xcc, 0x00, 0x0c, 0x54, 0x97, 0x46, 0x3e,
// 0x54, 0x98, 0xc4, 0x3e, 0x54, 0x84, 0x06, 0x3e, 0x40, 0x9e, 0x00, 0xfc, 0x56, 0xf9, 0x06, 0x31,
// 0x7d, 0x9a, 0x63, 0x78, 0x7f, 0x43, 0xd2, 0x14, 0x57, 0x5a, 0x00, 0x3a, 0x41, 0x82, 0x00, 0x18,
// 0x7e, 0xf7, 0x07, 0x74, 0x7e, 0xf7, 0x00, 0xd0, 0x1f, 0x37, 0x00, 0x02, 0x3b, 0x39, 0x00, 0x04,
// 0x7f, 0x59, 0xd0, 0x50, 0x2c, 0x17, 0x00, 0x00, 0x41, 0x82, 0x00, 0x1c, 0x3b, 0x20, 0x00, 0x00,
// 0x7e, 0xe9, 0x03, 0xa6, 0xa3, 0x7a, 0x00, 0x04, 0x7f, 0x79, 0xca, 0x78, 0x3b, 0x5a, 0x00, 0x02,
// 0x42, 0x00, 0xff, 0xf4, 0x7c, 0x18, 0xc8, 0x00, 0x40, 0x82, 0x00, 0xac, 0x4b, 0xff, 0xfe, 0x90,
// 0x51, 0x08, 0x08, 0x3c, 0x40, 0x9e, 0x00, 0x9c, 0x54, 0x77, 0xb0, 0x03, 0x41, 0x81, 0x00, 0x88,
// 0x41, 0x80, 0x00, 0x8c, 0x54, 0x7e, 0x06, 0x3e, 0x1f, 0xde, 0x00, 0x02, 0x54, 0x97, 0x00, 0x1e,
// 0x6e, 0xf8, 0x80, 0x00, 0x2c, 0x18, 0x00, 0x00, 0x40, 0x82, 0x00, 0x08, 0x62, 0xf7, 0x30, 0x00,
// 0x54, 0x98, 0x80, 0x1e, 0x1f, 0x3e, 0x00, 0x04, 0x7f, 0x19, 0xc0, 0x50, 0x3b, 0x20, 0x00, 0x00,
// 0x1f, 0x59, 0x00, 0x04, 0x7f, 0x6f, 0xd0, 0x2e, 0x7f, 0x57, 0xd0, 0x2e, 0x3b, 0x39, 0x00, 0x01,
// 0x7c, 0x17, 0xc0, 0x40, 0x41, 0x81, 0x00, 0x34, 0x7c, 0x19, 0xf0, 0x00, 0x41, 0x81, 0x00, 0x14,
// 0x7c, 0x1a, 0xd8, 0x00, 0x41, 0x82, 0xff, 0xdc, 0x3a, 0xf7, 0x00, 0x04, 0x4b, 0xff, 0xff, 0xd0,
// 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x03, 0x00, 0x90, 0x6f, 0xff, 0xf8, 0x92, 0xef, 0xff, 0xfc,
// 0x7e, 0xf0, 0xbb, 0x78, 0x48, 0x00, 0x00, 0x1c, 0x80, 0x6f, 0xff, 0xf8, 0x60, 0x63, 0x01, 0x00,
// 0x90, 0x6f, 0xff, 0xf8, 0x61, 0x08, 0x00, 0x01, 0x48, 0x00, 0x00, 0x08, 0x7c, 0x90, 0x23, 0x78,
// 0x54, 0x64, 0x06, 0x3e, 0x1c, 0x84, 0x00, 0x08, 0x7d, 0xe4, 0x7a, 0x14, 0x4b, 0xff, 0xf8, 0x70,
// 0x40, 0x92, 0x00, 0x0c, 0x39, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x14, 0x54, 0x69, 0x06, 0xff,
// 0x54, 0x65, 0x67, 0xfe, 0x7d, 0x08, 0x4c, 0x30, 0x55, 0x17, 0xff, 0xff, 0x40, 0x82, 0x00, 0x08,
// 0x7d, 0x08, 0x2a, 0x78, 0x54, 0x85, 0x00, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xa6, 0x2b, 0x78,
// 0x54, 0x85, 0x80, 0x1f, 0x41, 0x82, 0x00, 0x08, 0x7c, 0xb0, 0x2b, 0x78, 0x4b, 0xff, 0xf8, 0x30,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
//};

74
Config.c Normal file
View File

@ -0,0 +1,74 @@
#include "Config.h"
DML_CFG *DMLCfg;
void ConfigInit( DML_CFG *Cfg )
{
DMLCfg = (DML_CFG*)0xFFFE4200;
memset32( DMLCfg, 0, sizeof(DML_CFG) );
//If a loader supplied any options we use them otherwise use the code defines
if( Cfg->Magicbytes == 0xD1050CF6 && Cfg->Version == CONFIG_VERSION )
{
memcpy( DMLCfg, Cfg, sizeof( DML_CFG ) );
} else {
dbgprintf("No config found in RAM\n");
dbgprintf("Version:%08X\n", DMLCfg->Version );
dbgprintf("Config:%08X\n", DMLCfg->Config );
DMLCfg->Config = 0;
#ifdef CHEATHOOK
DMLCfg->Config |= DML_CFG_CHEATS;
#endif
#ifdef DEBUGGER
DMLCfg->Config |= DML_CFG_DEBUGGER;
#endif
#ifdef DEBUGGERWAIT
DMLCfg->Config |= DML_CFG_DEBUGWAIT;
#endif
#ifdef CARDMODE
DMLCfg->Config |= DML_CFG_NMM;
#endif
#ifdef CARDDEBUG
DMLCfg->Config |= DML_CFG_NMM_DEBUG;
#endif
#ifdef ACTIVITYLED
DMLCfg->Config |= DML_CFG_ACTIVITY_LED;
#endif
#ifdef PADHOOK
DMLCfg->Config |= DML_CFG_PADHOOK;
#endif
DMLCfg->VideoMode = DML_VID_DML_AUTO;
DMLCfg->Version = CONFIG_VERSION;
DMLCfg->Magicbytes = 0xD1050CF6;
}
//Check if a memcard is inserted in Slot A
if( (read32(0xD806800) & 0x1000) == 0x1000 )
{
DMLCfg->Config &= ~DML_CFG_NMM; // disable NMM
}
dbgprintf("Config:%08X\n", DMLCfg->Config );
}
inline u32 ConfigGetConfig( u32 Config )
{
return !!(DMLCfg->Config & Config);
}
u32 ConfigGetVideMode( void )
{
return DMLCfg->VideoMode;
}
char *ConfigGetGamePath( void )
{
return DMLCfg->GamePath;
}
char *ConfigGetCheatPath( void )
{
return DMLCfg->CheatPath;
}

97
Config.h Normal file
View File

@ -0,0 +1,97 @@
#ifndef _CFG_
#define _CFG_
#include "string.h"
#include "global.h"
#include "ipc.h"
#include "alloc.h"
#include "vsprintf.h"
#include "HW.h"
#define EXI_BASE 0x0D806800
typedef struct GC_SRAM
{
/* 0x00 */ u16 CheckSum1;
/* 0x02 */ u16 CheckSum2;
/* 0x04 */ u32 ead0;
/* 0x08 */ u32 ead1;
/* 0x0C */ u32 CounterBias;
/* 0x10 */ u8 DisplayOffsetH;
/* 0x11 */ u8 BootMode; // Bit 6 PAL60 flag
/* 0x12 */ u8 Language;
/* 0x13 */ u8 Flags;
/*
bit desc 0 1
0 -\_ Video mode
1 -/
2 Sound mode Mono Stereo
3 always 1
4 always 0
5 always 1
6 ?
7 Prog mode off on
*/
/* 0x14 */ u8 FlashID[2*12];
/* 0x2C */ u32 WirelessKBID;
/* 0x30 */ u16 WirlessPADID[4];
/* 0x38 */ u8 LastDVDError;
/* 0x39 */ u8 Reserved;
/* 0x3A */ u16 FlashIDChecksum[2];
/* 0x3C */ u16 Unused;
} GC_SRAM;
typedef struct DML_CFG
{
u32 Magicbytes; // 0xD1050CF6
u32 Version; // 0x00000001
u32 VideoMode;
u32 Config;
char GamePath[255];
char CheatPath[255];
} DML_CFG;
enum dmlconfig
{
DML_CFG_CHEATS = (1<<0),
DML_CFG_DEBUGGER = (1<<1),
DML_CFG_DEBUGWAIT = (1<<2),
DML_CFG_NMM = (1<<3),
DML_CFG_NMM_DEBUG = (1<<4),
DML_CFG_GAME_PATH = (1<<5),
DML_CFG_CHEAT_PATH = (1<<6),
DML_CFG_ACTIVITY_LED= (1<<7),
DML_CFG_PADHOOK = (1<<8),
DML_CFG_NODISC = (1<<9),
DML_CFG_BOOT_DISC = (1<<10),
DML_CFG_BOOT_DOL = (1<<11),
};
enum dmlvideomode
{
DML_VID_DML_AUTO = (0<<16),
DML_VID_FORCE = (1<<16),
DML_VID_NONE = (2<<16),
DML_VID_FORCE_PAL50 = (1<<0),
DML_VID_FORCE_PAL60 = (1<<1),
DML_VID_FORCE_NTSC = (1<<2),
DML_VID_FORCE_PROG = (1<<3),
};
enum VideoModes
{
GCVideoModeNone = 0,
GCVideoModePAL60 = 1,
GCVideoModeNTSC = 2,
GCVideoModePROG = 3,
};
void ConfigInit( DML_CFG *Cfg );
u32 ConfigGetConfig( u32 Config );
u32 ConfigGetVideMode( void );
char *ConfigGetGamePath( void );
char *ConfigGetCheatPath( void );
#endif

398
DVD.c Normal file
View File

@ -0,0 +1,398 @@
#include "DVD.h"
DVDConfig *DICfg = (DVDConfig *)NULL;
u32 read;
static char GamePath[256];
extern FIL GameFile;
extern u32 FSTMode;
extern u32 DOLMaxOff;
extern u32 DOLOffset;
u8 HardDriveConnected;
FATFS fatfs;
static u8 *FSTable ALIGNED(32);
u32 ApploaderSize=0;
u32 dolOffset=0;
u32 FSTableSize=0;
u32 FSTableOffset=0;
u32 FCEntry=0;
FileCache FC[FILECACHE_MAX];
u32 FCState[FILECACHE_MAX];
void DVDInit( void )
{
int i=0;
s32 fres = FR_DISK_ERR;
int MountFail=0;
HardDriveConnected = 0;
while(!HardDriveConnected)
{
while(1)
{
fres = f_mount(0, &fatfs );
dbgprintf( "DIP:f_mount():%d\n", fres );
if( fres == FR_OK )
break;
else
MountFail++;
if( MountFail == 10 )
{
dbgprintf( "DIP:too much fail! looping now!\n");
while(1);
}
udelay(500000);
}
//try to open a file, it doesn't have to exist, just testing if FS works
FIL f;
fres = f_open( &f, "/randmb.in", FA_READ|FA_OPEN_EXISTING );
switch(fres)
{
case FR_OK:
f_close( &f );
case FR_NO_PATH:
case FR_NO_FILE:
{
HardDriveConnected = 1;
fres = FR_OK;
} break;
default:
case FR_DISK_ERR:
{
dbgprintf( "DIP: Disk error\n", fres );
while(1);
} break;
}
}
if( fres != FR_OK )
{
dbgprintf( "Could not find any USB device!");
}
return;
}
s32 DVDSelectGame( void )
{
char *str = (char*)malloca( 256, 32 );
if( ConfigGetConfig(DML_CFG_GAME_PATH) )
{
sprintf( str, "%s", ConfigGetGamePath() );
} else {
dbgprintf("No game path was supplied!\n");
free(str);
return -1;
}
s32 fres = f_open( &GameFile, str, FA_READ );
if( fres != FR_OK )
{
sprintf( GamePath, "%s", str );
//Try to switch to FST mode
if( !FSTInit() )
{
dbgprintf("Failed to open:\"%s\" fres:%d\n", str, fres );
free(str);
return -2;
}
} else {
f_lseek( &GameFile, 0 );
f_read( &GameFile, (void*)0, 0x20, &read );
f_lseek( &GameFile, 0 );
f_read( &GameFile, str, 0x400, &read );
dbgprintf("DIP:Loading game %.6s: %s\n", str, (char *)(str+0x20));
f_lseek( &GameFile, 0x420 );
f_read( &GameFile, str, 0x40, &read );
}
free( str );
return DI_SUCCESS;
}
u32 FSTInit( void )
{
char Path[256];
FIL fd;
u32 read;
sprintf( Path, "%ssys/boot.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return 0;
} else {
u8 *rbuf = (u8*)malloc( 0x100 );
f_lseek( &fd, 0 );
f_read( &fd, rbuf, 0x100, &read );
dbgprintf("DIP:Loading game %.6s: %s\n", rbuf, (char *)(rbuf+0x20));
//Read DOL/FST offset/sizes for later usage
f_lseek( &fd, 0x0420 );
f_read( &fd, rbuf, 0x20, &read );
dolOffset = *(u32*)(rbuf);
FSTableOffset = *(u32*)(rbuf+4);
FSTableSize = *(u32*)(rbuf+8);
free( rbuf );
dbgprintf( "DIP:FSTableOffset:%08X\n", FSTableOffset );
dbgprintf( "DIP:FSTableSize: %08X\n", FSTableSize );
dbgprintf( "DIP:DolOffset: %08X\n", dolOffset );
FSTMode = 1;
f_close( &fd );
}
//Init cache
u32 count = 0;
for( count=0; count < FILECACHE_MAX; ++count )
{
FCState[count] = 0xdeadbeef;
}
return 1;
}
void Asciify( char *str )
{
int i=0;
for( i=0; i < strlen(str); i++ )
if( str[i] < 0x20 || str[i] > 0x7F )
str[i] = '_';
}
void FSTRead( char *Buffer, u32 Length, u32 Offset )
{
char Path[256];
FIL fd;
u32 read;
int i,j;
if( Offset >= FSTableOffset+FSTableSize ) {
//Get FSTTable offset from low memory, must be set by apploader
if( FSTable == NULL )
{
FSTable = (u8*)((*(vu32*)0x38) & 0x7FFFFFFF);
//dbgprintf("DIP:FSTOffset: %08X\n", (u32)FSTable );
}
//try cache first!
for( i=0; i < FILECACHE_MAX; ++i )
{
if( FCState[i] == 0xdeadbeef )
continue;
if( Offset >= FC[i].Offset )
{
u64 nOffset = Offset - FC[i].Offset;
if( nOffset < FC[i].Size )
{
//dbgprintf("DIP:[Cache:%02d][%08X:%05X]\n", i, (u32)(nOffset>>2), Length );
f_lseek( &(FC[i].File), nOffset );
f_read( &(FC[i].File), Buffer, ((Length)+31)&(~31), &read );
return;
}
}
}
//The fun part!
u32 Entries = *(u32*)(FSTable+0x08);
char *NameOff = (char*)(FSTable + Entries * 0x0C);
FEntry *fe = (FEntry*)(FSTable);
u32 Entry[16];
u32 LEntry[16];
u32 level=0;
for( i=1; i < Entries; ++i )
{
if( level )
{
while( LEntry[level-1] == i )
{
//printf("[%03X]leaving :\"%s\" Level:%d\n", i, buffer + NameOff + swap24( fe[Entry[level-1]].NameOffset ), level );
level--;
}
}
if( fe[i].Type )
{
//Skip empty folders
if( fe[i].NextOffset == i+1 )
continue;
//printf("[%03X]Entering:\"%s\" Level:%d leave:%04X\n", i, buffer + NameOff + swap24( fe[i].NameOffset ), level, swap32( fe[i].NextOffset ) );
Entry[level] = i;
LEntry[level++] = fe[i].NextOffset;
if( level > 15 ) // something is wrong!
break;
} else {
if( Offset >= fe[i].FileOffset )
{
u32 nOffset = (Offset - fe[i].FileOffset);
if( nOffset < fe[i].FileLength )
{
// dbgprintf("DIP:Offset:%08X FOffset:%08X Dif:%08X Flen:%08X nOffset:%08X\n", Offset, fe[i].FileOffset, Offset-fe[i].FileOffset, fe[i].FileLength, nOffset );
//Do not remove!
memset( Path, 0, 256 );
sprintf( Path, "%sroot/", GamePath );
for( j=0; j<level; ++j )
{
if( j )
Path[strlen(Path)] = '/';
memcpy( Path+strlen(Path), NameOff + fe[Entry[j]].NameOffset, strlen(NameOff + fe[Entry[j]].NameOffset ) );
}
if( level )
Path[strlen(Path)] = '/';
memcpy( Path+strlen(Path), NameOff + fe[i].NameOffset, strlen(NameOff + fe[i].NameOffset) );
if( FCEntry >= FILECACHE_MAX )
FCEntry = 0;
if( FCState[FCEntry] != 0xdeadbeef )
{
f_close( &(FC[FCEntry].File) );
FCState[FCEntry] = 0xdeadbeef;
}
Asciify( Path );
f_open( &(FC[FCEntry].File), Path, FA_READ );
FC[FCEntry].Size = fe[i].FileLength;
FC[FCEntry].Offset = fe[i].FileOffset;
FCState[FCEntry] = 0x23;
f_lseek( &(FC[FCEntry].File), nOffset );
f_read( &(FC[FCEntry].File), Buffer, Length, &read );
FCEntry++;
}
}
}
}
} else if ( Offset >= FSTableOffset ) {
Offset -= FSTableOffset;
sprintf( Path, "%ssys/fst.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[fst.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
if( FSTable == NULL )
{
FSTable = (u8*)Buffer;
}
return;
}
} else if ( Offset >= dolOffset ) {
Offset -= dolOffset;
sprintf( Path, "%ssys/main.dol", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[main.dol] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else if ( Offset >= 0x2440 ) {
Offset -= 0x2440;
sprintf( Path, "%ssys/apploader.img", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[apploader.img] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else if ( Offset >= 0x440 ) {
Offset -= 0x440;
sprintf( Path, "%ssys/bi2.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[bi2.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
} else {
sprintf( Path, "%ssys/boot.bin", GamePath );
if( f_open( &fd, Path, FA_READ ) != FR_OK )
{
dbgprintf( "DIP:[%s] Failed to open!\n", Path );
return;
} else {
//dbgprintf( "DIP:[boot.bin] Offset:%08X Size:%08X\n", Offset, Length );
f_lseek( &fd, Offset );
f_read( &fd, Buffer, Length, &read );
f_close( &fd );
return;
}
}
}

29
DVD.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef _DVD_
#define _DVD_
#include "global.h"
#include "HW.h"
#include "Config.h"
#include "ff.h"
#include "dol.h"
#include "Drive.h"
typedef struct
{
u32 SlotID;
u32 Region;
u32 Gamecount;
u32 Config;
u8 GameInfo[][0x80];
} DVDConfig;
void DVDInit( void );
void DVDReadConfig( void );
s32 DVDSelectGame( void );
void DVDUpdateFSTRAM( void );
void DiscBackup( u32 FrameBuffer );
u32 FSTInit( void );
void FSTRead( char *Buffer, u32 Length, u32 Offset );
#endif

10
DVDPatches.c Normal file
View File

@ -0,0 +1,10 @@
#ifndef __DVDPATCHES__
#define __DVDPATCHES__
#include "global.h"
#include "asm\DVDInquiryAsync.h"
#include "asm\DVDSeekAbsAsyncPrio.h"
#include "asm\padipc.h"
#endif

124
Drive.c Normal file
View File

@ -0,0 +1,124 @@
#include "Drive.h"
void DVDLowReset( void )
{
clear32( HW_RESETS, (1<<10) | (1<<17) );
set32( HW_RESETS, (1<<10) | (1<<17) );
}
u32 DVDLowGetError( void )
{
write32( 0x0D806000, 0x2E );
write32( 0x0D806008, 0xE0000000 );
write32( 0x0D806020, 0 );
write32( 0x0D80601c, 1 );
while( read32(0x0D80601c) & 1 );
set32( 0x0D806000, (1<<4) );
return read32( 0x0D806020 );
}
u32 DVDLowSeek( void )
{
write32( 0x0D806000, 0x2E );
write32( 0x0D806008, 0xAB000000 );
write32( 0x0D806020, 0 );
write32( 0x0D80601c, 1 );
while( read32(0x0D80601c) & 1 );
set32( 0x0D806000, (1<<4) );
return read32( 0x0D806020 );
}
u32 DVDLowStopMotor( void )
{
write32( 0x0D806000, 0x2E );
write32( 0x0D806008, 0xE3000000 );
write32( 0x0D806020, 0 );
write32( 0x0D80601c, 1 );
while( read32(0x0D80601c) & 1 );
set32( 0x0D806000, (1<<4) );
return read32( 0x0D806020 );
}
u32 LowReadDiscID( void *data )
{
write32( 0x0D806008, 0xA8000040 );
write32( 0x0D80600C, 0 );
write32( 0x0D806010, 0x20 );
write32( 0x0D806018, 0x20 );
write32( 0x0D806014, (u32)data );
write32( 0x0D806000, 0x3A );
write32( 0x0D80601C, 3 );
while (1)
{
if( read32( 0x0D806000 ) & (1<<2) )
{
set32( 0x0D806000, (1<<2) );
return 1;
}
if( read32( 0x0D806000 ) & (1<<4) )
{
set32( 0x0D806000, (1<<4) );
return 0;
}
}
return 0;
}
u32 LowRead( void *data, u32 Offset, u32 Length )
{
write32( 0x0D806008, 0xA8000000 );
write32( 0x0D80600C, Offset>>2 );
write32( 0x0D806010, Length );
write32( 0x0D806018, Length );
write32( 0x0D806014, (u32)data );
write32( 0x0D806000, 0x3A );
write32( 0x0D80601C, 3 );
while (1)
{
if( read32( 0x0D806000 ) & (1<<2) )
{
set32( 0x0D806000, (1<<2) );
return 1;
}
if( read32( 0x0D806000 ) & (1<<4) )
{
set32( 0x0D806000, (1<<4) );
return 0;
}
}
return 0;
}
u32 DVDEnableAudioStreaming( u32 Enable )
{
write32( 0x0D806004, read32( 0x0D806004 ) );
write32( 0x0D806008, 0xE4000000 | (Enable<<16) | 0x0A );
write32( 0x0D80601C, 1 );
while( read32(0x0D80601C) & 1 );
while(1)
{
if( read32( 0x0D806000 ) & 4 )
return DI_ERROR;
if(!read32(0x0D806018))
return DI_SUCCESS;
}
return DI_FATAL;
}

16
Drive.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _DRIVE_
#define _DRIVE_
#include "global.h"
#include "HW.h"
#include "memory.h"
void DVDLowReset( void );
u32 DVDEnableAudioStreaming( u32 Enable );
u32 DVDLowGetError( void );
u32 DVDLowStopMotor( void );
u32 LowReadDiscID( void *data );
u32 LowRead( void *data, u32 Offset, u32 Length );
u32 DVDLowSeek( void );
#endif

42
FwritePatches.c Normal file
View File

@ -0,0 +1,42 @@
unsigned char VIFlush[8] =
{
0x7C, 0x80, 0x03, 0x78,
0x7C, 0xA3, 0x1B, 0x78,
} ;
//unsigned char __fwrite[] =
//{
// 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0x88, 0x40, 0x86, 0x00, 0x24,
//} ;
//
//unsigned char __fwriteGC[] =
//{
// 0x94, 0x21, 0xFF, 0xD0, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x34, 0xBF, 0x21, 0x00, 0x14,
// 0x7C, 0x99, 0x23, 0x78, 0x7C, 0xDA, 0x33, 0x78, 0x7C, 0x7B, 0x1B, 0x78, 0x7C, 0xBC, 0x2B, 0x78,
// 0x38, 0x80, 0x00, 0x00, 0x7F, 0x43, 0xD3, 0x78,
//} ;
//unsigned char __fwriteGCB[] =
//{
// 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x94, 0x21, 0xFF, 0xB8, 0xBF, 0x21, 0x00, 0x2C,
// 0x3B, 0x44, 0x00, 0x00, 0x3B, 0x66, 0x00, 0x00, 0x3B, 0x83, 0x00, 0x00, 0x3B, 0x25, 0x00, 0x00,
// 0x38, 0x7B, 0x00, 0x00, 0x38, 0x80, 0x00, 0x00,
//} ;
//unsigned char __fwriteGCC[32] =
//{
// 0x94, 0x21, 0xFF, 0xB0, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x54, 0xBE, 0x81, 0x00, 0x20,
// 0x7C, 0x97, 0x23, 0x78, 0x7C, 0xDF, 0x33, 0x78, 0x38, 0x80, 0x00, 0x00, 0x90, 0x61, 0x00, 0x08,
//} ;
unsigned char patch_fwrite_GC[144] =
{
0x7C, 0x85, 0x21, 0xD7, 0x40, 0x81, 0x00, 0x84, 0x3C, 0xE0, 0xCC, 0x00, 0x3D, 0x40, 0xCC, 0x00,
0x3D, 0x60, 0xCC, 0x00, 0x60, 0xE7, 0x68, 0x14, 0x61, 0x4A, 0x68, 0x24, 0x61, 0x6B, 0x68, 0x20,
0x38, 0xC0, 0x00, 0x00, 0x7C, 0x06, 0x18, 0xAE, 0x54, 0x00, 0xA0, 0x16, 0x64, 0x08, 0xB0, 0x00,
0x38, 0x00, 0x00, 0xD0, 0x90, 0x07, 0x00, 0x00, 0x7C, 0x00, 0x06, 0xAC, 0x91, 0x0A, 0x00, 0x00,
0x7C, 0x00, 0x06, 0xAC, 0x38, 0x00, 0x00, 0x19, 0x90, 0x0B, 0x00, 0x00, 0x7C, 0x00, 0x06, 0xAC,
0x80, 0x0B, 0x00, 0x00, 0x7C, 0x00, 0x04, 0xAC, 0x70, 0x09, 0x00, 0x01, 0x40, 0x82, 0xFF, 0xF4,
0x80, 0x0A, 0x00, 0x00, 0x7C, 0x00, 0x04, 0xAC, 0x39, 0x20, 0x00, 0x00, 0x91, 0x27, 0x00, 0x00,
0x7C, 0x00, 0x06, 0xAC, 0x74, 0x09, 0x04, 0x00, 0x41, 0x82, 0xFF, 0xB8, 0x38, 0xC6, 0x00, 0x01,
0x7F, 0x86, 0x20, 0x00, 0x40, 0x9E, 0xFF, 0xA0, 0x7C, 0xA3, 0x2B, 0x78, 0x4E, 0x80, 0x00, 0x20,
};

47
GCPad.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef __GCPAD__
#define __GCPAD__
typedef struct
{
union
{
struct
{
bool ErrorStatus :1;
bool ErrorLatch :1;
u32 Reserved :1;
bool Start :1;
bool Y :1;
bool X :1;
bool B :1;
bool A :1;
u32 AlwaysSet :1;
bool R :1;
bool L :1;
bool Z :1;
bool Up :1;
bool Down :1;
bool Right :1;
bool Left :1;
s16 StickX :8;
s16 StickY :8;
};
u32 Buttons;
};
union
{
struct
{
s16 CStickX;
s16 CStickY;
s16 LShoulder;
s16 RShoulder;
};
u32 Sticks;
};
} GCPadStatus;
#endif

1045
HW.c Normal file

File diff suppressed because it is too large Load Diff

89
HW.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef _HW_
#define _HW_
#include "string.h"
#include "global.h"
#include "memory.h"
#include "ipc.h"
#include "alloc.h"
#include "dip.h"
#include "GCPad.h"
#define P2C(x) ((x)&0x7FFFFFFF)
#define HW_BASE 0x0d800000
#define HW_MEMIRR (HW_BASE+0x60)
#define HW_AHBPROT (HW_BASE+0x64)
#define HW_DDRCTRL_ADDR (HW_BASE+0x74)
#define HW_DDRCTRL_VAL (HW_BASE+0x76)
#define HW_GPIO_ENABLE (HW_BASE+0xDC)
#define HW_GPIO_OUT (HW_BASE+0xE0)
#define HW_GPIO_DIR (HW_BASE+0xE4)
#define HW_GPIO_IN (HW_BASE+0xE8)
#define HW_GPIO_INTLVL (HW_BASE+0xEC)
#define HW_GPIO_INTFLAG (HW_BASE+0xF0)
#define HW_GPIO_INTMASK (HW_BASE+0xF4)
#define HW_GPIO_INMIR (HW_BASE+0xF8)
#define HW_GPIO_OWNER (HW_BASE+0xFC)
#define HW_ACRPLLSYS (HW_BASE+0x1B0)
#define HW_ACRPLLSYSEXT (HW_BASE+0x1B4)
#define DIFLAGS_PPCBOOT (1<<20)
#define IRQ_TIMER (1<<0)
#define IRQ_NAND (1<<1)
#define IRQ_AES (1<<2)
#define IRQ_SHA1 (1<<3)
#define IRQ_EHCI (1<<4)
#define IRQ_OHCI0 (1<<5)
#define IRQ_OHCI1 (1<<6)
#define IRQ_SDHC (1<<7)
#define IRQ_WIFI (1<<8)
#define IRQ_GPIO1B (1<<10)
#define IRQ_GPIO1 (1<<11)
#define IRQ_RESET (1<<17)
#define IRQ_PPCIPC (1<<30)
#define IRQ_IPC (1<<31)
#define GPIO_POWER (1<<1)
#define GPIO_EJECT (1<<9)
extern void DRAMCTRLWrite( u32 Register, u32 Value );
extern u32 DRAMCTRLRead( u32 Register );
void EHCIInit( void );
void EXIControl( u32 value );
void MIOSHWInit( u32 A, u32 B );
void MIOSInit( void );
void MEMInitLow( void );
void BootPPC( void );
void UNKInit( u32 A, u32 B );
void DRAMInit( u32 A, u32 B );
void ChangeClock( void );
void PPCReset( void );
void HWResetDisable( void );
void HWResetEnable( void );
void HW_184( void );
void HW_184_2( void );
void GetRevision( u32 *Version, u32 *Revision );
void HWMAgic( u32 R0, u32 R1, u32 R2, u32 R3 );
u32 DRAMRead( u32 ValueA );
void DRAMWrite( u32 ValueA, u32 ValueB );
u32 RegRead( u32 Register );
void RegWrite( u32 Register, u32 Value );
void HWRegWriteBatch( u32 A, u32 B, u32 C, u32 D, u32 delay );
void Shutdown( void );
#endif

53
Makefile Normal file
View File

@ -0,0 +1,53 @@
PREFIX = $(DEVKITARM)/bin/arm-eabi-
CC = $(PREFIX)gcc
AS = $(PREFIX)as
LD = $(PREFIX)gcc
SSTRIP = $(DEVKITARM)/bin/arm-eabi-strip
CFLAGS = -mbig-endian -fomit-frame-pointer -O2 -Wall -I. -mcpu=arm926ej-s -mthumb
CFLAGS += -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-toupper -fno-builtin-memcmp -fno-builtin-malloc -fno-builtin-free
ASFLAGS = -mbig-endian -mcpu=arm926ej-s
LDFLAGS = -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,iosmodule.ld,-Map,iosmodule.map -n
LIBS = -lgcc
TARGET = iosmodule.elf
OBJECTS = start.o utils_asm.o HW.o Card.o memory.o memory_asm.o Config.o common.o ff.o diskio.o alloc.o Drive.o DVD.o dip.o Patches.o main.o vsprintf.o string.o tiny_ehci_glue.o usb_os.o
.PHONY: FORCE
all: $(TARGET)
$(TARGET) : iosmodule.ld $(OBJECTS)
@echo "LD $@"
@$(LD) $(LDFLAGS) $(OBJECTS) $(LIBS) -o $@
@echo $(SSTRIP) -s $@
%.o : %.s
@echo "AS $@"
@$(CC) $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c -x assembler-with-cpp -o $@ $<
%.o : %.S
@echo "AS $@"
@$(CC) $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c -x assembler-with-cpp -o $@ $<
%.o : %.c
@echo "CC $@"
@$(CC) $(CFLAGS) -c -o $@ $<
%.d: %.c
@echo "DEP $@"
@set -e; $(CC) -M $(CFLAGS) $< \
| sed 's?\($*\)\.o[ :]*?\1.o $@ : ?g' > $@; \
[ -s $@ ] || rm -f $@
%.d: %.S
@echo "DEP $@"
@touch $@
-include $(OBJECTS:.o=.d)
clean:
-rm -f *.elf *.o *.bin *.d *.map

874
Patches.c Normal file
View File

@ -0,0 +1,874 @@
#include "Patches.h"
#include "CardPatches.c"
#include "DVDPatches.c"
#include "FwritePatches.c"
#include "CheatCode.c"
extern u32 DOLSize;
unsigned char OSReportDM[] =
{
0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x04, 0x90, 0xE1, 0x00, 0x08, 0x3C, 0xE0, 0xC0, 0x00,
0x90, 0x67, 0x18, 0x60, 0x90, 0x87, 0x18, 0x64, 0x90, 0xA7, 0x18, 0x68, 0x90, 0xC7, 0x18, 0x6C,
0x90, 0xE7, 0x18, 0x70, 0x91, 0x07, 0x18, 0x74, 0x80, 0x07, 0x18, 0x60, 0x7C, 0x00, 0x18, 0x00,
0x41, 0x82, 0xFF, 0xF8, 0x80, 0xE1, 0x00, 0x08, 0x80, 0x01, 0x00, 0x04, 0x7C, 0x08, 0x03, 0xA6,
0x4E, 0x80, 0x00, 0x20,
} ;
// Audio streaming replacement functions copied from Swiss r92
u32 __dvdLowAudioStatusNULL[17] = {
// execute function(1); passed in on r4
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7C8903A6, // mtctr r4
0x3C80CC00, // lis r4, 0xCC00
0x2E830000, // cmpwi cr5, r3, 0
0x4196000C, // beq- cr5, +0xC ?
0x38600001, // li r3, 1
0x48000008, // b +0x8 ?
0x38600000, // li r3, 0
0x90646020, // stw r3, 0x6020 (r4)
0x38600001, // li r3, 1
0x4E800421, // bctrl
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020 // blr
};
u32 __dvdLowAudioConfigNULL[10] = {
// execute callback(1); passed in on r5 without actually touching the drive!
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7CA903A6, // mtctr r5
0x38600001, // li r3, 1
0x4E800421, // bctrl
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020 // blr
};
u32 __dvdLowReadAudioNULL[] = {
// execute callback(1); passed in on r6 without actually touching the drive!
0x9421FFC0, // stwu sp, -0x0040 (sp)
0x7C0802A6, // mflr r0
0x90010000, // stw r0, 0 (sp)
0x7CC903A6, // mtctr r6
0x38600001, // li r3, 1
0x4E800421, // bctr;
0x80010000, // lwz r0, 0 (sp)
0x7C0803A6, // mtlr r0
0x38210040, // addi sp, sp, 64
0x4E800020
};
u32 __GXSetVAT_patch[31] = {
/*0x8122ce00,*/ 0x39400000, 0x896904f2, 0x7d284b78,
0x556007ff, 0x41820050, 0x38e00008, 0x3cc0cc01,
0x98e68000, 0x61400070, 0x61440080, 0x61430090,
0x98068000, 0x38000000, 0x80a8001c, 0x90a68000,
0x98e68000, 0x98868000, 0x8088003c, 0x90868000,
0x98e68000, 0x98668000, 0x8068005c, 0x90668000,
0x98068000, 0x556bf87f, 0x394a0001, 0x39080004,
0x4082ffa0, 0x38000000, 0x980904f2, 0x4e800020
};
FuncPattern FPatterns[] =
{
{ 0xCC, 17, 10, 5, 3, 2, DVDInquiryAsync, sizeof(DVDInquiryAsync), "DVDInquiryAsync", 0, 0 },
{ 0xC8, 16, 9, 5, 3, 3, DVDSeekAbsAsyncPrio, sizeof(DVDSeekAbsAsyncPrio), "DVDSeekAbsAsyncPrio", 0, 0 },
{ 0xD4, 13, 8, 11, 2, 7, (u8*)NULL, 0xdead0004, "AIResetStreamSampleCount", 0, 0 },
{ 0x94, 18, 10, 2, 0, 2, (u8*)__dvdLowReadAudioNULL, sizeof(__dvdLowReadAudioNULL), "DVDLowReadAudio", 0, 0 },
{ 0x88, 18, 8, 2, 0, 2, (u8*)__dvdLowAudioStatusNULL, sizeof(__dvdLowAudioStatusNULL), "DVDLowAudioStatus", 0, 0 },
{ 0x98, 19, 8, 2, 1, 3, (u8*)__dvdLowAudioConfigNULL, sizeof(__dvdLowAudioConfigNULL), "DVDLowAudioConfig", 0, 0 },
{ 0x308, 40, 18, 10, 23, 17, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite A", 1, 0 },
{ 0x338, 48, 20, 10, 24, 16, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite B", 1, 0 },
{ 0x2D8, 41, 17, 8, 21, 13, patch_fwrite_GC, sizeof(patch_fwrite_GC), "__fwrite C", 1, 0 },
{ 0x98, 8, 3, 0, 3, 5, (u8*)NULL, 0xdead0001, "__GXSetVAT", 0, 0 },
{ 0x3A8, 86, 13, 27, 17, 24, (u8*)NULL, 0xdead000B, "PADRead A", 2, 0 },
{ 0x2FC, 73, 8, 23, 16, 15, (u8*)NULL, 0xdead000B, "PADRead B", 2, 0 },
{ 0x3B0, 87, 13, 27, 17, 25, (u8*)NULL, 0xdead000B, "PADRead C", 2, 0 },
{ 0x334, 78, 7, 20, 17, 19, (u8*)NULL, 0xdead000B, "PADRead D", 2, 0 },
};
FuncPattern CPatterns[] =
{
{ 0x14C, 28, 12, 7, 12, 4, CARDFreeBlocks, sizeof(CARDFreeBlocks), "CARDFreeBlocks A", 1, 0 },
{ 0x11C, 24, 10, 7, 10, 4, CARDFreeBlocks, sizeof(CARDFreeBlocks), "CARDFreeBlocks B", 1, 0 },
{ 0xC0, 22, 5, 2, 5, 10, CARDGetSerialNo, sizeof(CARDGetSerialNo),"CARDGetSerialNo", 0, 0 },
{ 0x84, 12, 5, 3, 4, 2, CARDGetEncoding, sizeof(CARDGetEncoding),"CARDGetEncoding", 0, 0 },
{ 0x80, 11, 5, 3, 4, 2, CARDGetMemSize, sizeof(CARDGetMemSize), "CARDGetMemSize", 0, 0 },
{ 0x94, 11, 6, 3, 5, 4, __CARDSync, sizeof(__CARDSync), "__CARDSync", 0, 0 },
{ 0x50, 6, 3, 2, 2, 2, CARDCheck, sizeof(CARDCheck), "CARDCheck", 0, 0 },
//{ 0x24, 4, 2, 1, 0, 2, CARDCheckAsync, sizeof(CARDCheckAsync), "CARDCheckAsync", 0, 0 },
{ 0x58C, 82, 11, 18, 41, 57, CARDCheckEX, sizeof(CARDCheckEX), "CARDCheckExAsync", 0, 0 },
{ 0x34, 4, 2, 1, 2, 2, CARDProbe, sizeof(CARDProbe), "CARDProbe", 2, 0 },
//{ 0x1C, 2, 2, 1, 0, 2, CARDProbe, sizeof(CARDProbe), "CARDProbe B", 2, 0 }, //This is causing more trouble than a hack...
{ 0x178, 20, 6, 6, 20, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx A", 3, 0 },
{ 0x198, 22, 6, 5, 19, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx B", 3, 0 },
{ 0x160, 17, 6, 5, 18, 4, CARDProbeEX, sizeof(CARDProbeEX), "CARDProbeEx C", 3, 0 },
{ 0x19C, 32, 14, 11, 12, 3, CARDMountAsync, sizeof(CARDMountAsync), "CARDMountAsync A", 4, 0 },
{ 0x184, 30, 14, 11, 10, 3, CARDMountAsync, sizeof(CARDMountAsync), "CARDMountAsync B", 4, 0 },
{ 0xA8, 15, 8, 6, 3, 2, CARDCheck, sizeof(CARDCheck), "CARDUnMount", 0, 0 },
{ 0x174, 23, 6, 7, 14, 5, CARDOpen, sizeof(CARDOpen), "CARDOpen A", 5, 0 },
{ 0x118, 14, 6, 6, 11, 4, CARDOpen, sizeof(CARDOpen), "CARDOpen B", 5, 0 },
{ 0x170, 23, 6, 7, 14, 5, CARDOpen, sizeof(CARDOpen), "CARDOpen C", 5, 0 },
{ 0x15C, 27, 6, 5, 15, 6, CARDFastOpen, sizeof(CARDFastOpen), "CARDFastOpen A", 11, 0 },
{ 0x100, 20, 10, 4, 10, 4, CARDFastOpen, sizeof(CARDFastOpen), "CARDFastOpen B", 11, 0 },
{ 0x50, 8, 4, 2, 2, 3, CARDClose, sizeof(CARDClose), "CARDClose", 0, 0 },
{ 0x21C, 44, 6, 13, 19, 12, CARDCreate, sizeof(CARDCreate), "CARDCreateAsync A", 6, 0 },
{ 0x214, 42, 6, 13, 19, 12, CARDCreate, sizeof(CARDCreate), "CARDCreateAsync B", 6, 0 },
{ 0x10C, 25, 6, 9, 9, 5, CARDDelete, sizeof(CARDDelete), "CARDDeleteAsync A", 12, 0 },
{ 0x10C, 25, 6, 9, 9, 5, CARDDelete, sizeof(CARDDelete), "CARDDeleteAsync C", 12, 0 },
{ 0x128, 24, 7, 9, 12, 5, CARDFastDelete, sizeof(CARDFastDelete), "CARDFastDelete", 0, 0 },
{ 0x144, 27, 3, 8, 10, 9, CARDRead, sizeof(CARDRead), "CARDReadAsync A", 7, 0 },
{ 0x140, 30, 7, 7, 10, 10, CARDRead, sizeof(CARDRead), "CARDReadAsync B", 7, 0 },
{ 0x140, 27, 3, 8, 10, 9, CARDRead, sizeof(CARDRead), "CARDReadAsync C", 7, 0 },
{ 0x110, 24, 4, 8, 9, 6, CARDWrite, sizeof(CARDWrite), "CARDWriteAsync A", 8, 0 },
{ 0x10C, 23, 4, 8, 9, 6, CARDWrite, sizeof(CARDWrite), "CARDWriteAsync B", 8, 0 },
{ 0x1F8, 37, 3, 17, 18, 9, CARDRename, sizeof(CARDRename), "CARDRenameAsync", 0, 0 },
{ 0x128, 25, 9, 9, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus A", 9, 0 },
{ 0x110, 25, 9, 8, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus B", 9, 0 },
{ 0x124, 25, 9, 9, 6, 5, CARDGetStats, sizeof(CARDGetStats), "CARDGetStatus C", 9, 0 },
{ 0x170, 29, 9, 9, 12, 5, CARDSetStats, sizeof(CARDSetStats), "CARDSetStatusAsync A", 10, 0 },
{ 0x16C, 29, 9, 9, 12, 5, CARDSetStats, sizeof(CARDSetStats), "CARDSetStatusAsync B", 10, 0 },
};
u32 CardLowestOff = 0;
void PatchB( u32 dst, u32 src )
{
u32 newval = (dst - src);
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( src, newval );
}
void PatchBL( u32 dst, u32 src )
{
u32 newval = (dst - src);
newval&= 0x03FFFFFC;
newval|= 0x48000001;
write32( src, newval );
}
void MPattern( u8 *Data, u32 Length, FuncPattern *FunctionPattern )
{
u32 i;
memset( FunctionPattern, 0, sizeof(FuncPattern) );
for( i = 0; i < Length; i+=4 )
{
u32 word = read32( (u32)Data + i );
if( (word & 0xFC000003) == 0x48000001 )
FunctionPattern->FCalls++;
if( (word & 0xFC000003) == 0x48000000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x40800000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x41800000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x40810000 )
FunctionPattern->Branch++;
if( (word & 0xFFFF0000) == 0x41820000 )
FunctionPattern->Branch++;
if( (word & 0xFC000000) == 0x80000000 )
FunctionPattern->Loads++;
if( (word & 0xFF000000) == 0x38000000 )
FunctionPattern->Loads++;
if( (word & 0xFF000000) == 0x3C000000 )
FunctionPattern->Loads++;
if( (word & 0xFC000000) == 0x90000000 )
FunctionPattern->Stores++;
if( (word & 0xFC000000) == 0x94000000 )
FunctionPattern->Stores++;
if( (word & 0xFF000000) == 0x7C000000 )
FunctionPattern->Moves++;
if( word == 0x4E800020 )
break;
}
FunctionPattern->Length = i;
}
bool CPattern( FuncPattern *FPatA, FuncPattern *FPatB )
{
if( memcmp( FPatA, FPatB, sizeof(u32) * 6 ) == 0 )
return true;
else
return false;
}
void DoCardPatches( char *ptr, u32 size, u32 SectionOffset )
{
u32 i,j,k,offset,fail,FoundCardFuncStart=0;
dbgprintf("DoCardPatches( 0x%p, %d, 0x%X)\n", ptr, size, SectionOffset );
for( i=0; i < size; i+=4 )
{
if( read32( (u32)ptr + i) == 0x7C630214 && read32( (u32)ptr + i + 4) == 0x806300B8 )
{
dbgprintf("Found [CARDGetXferredBytes] @ 0x%08X\n", (u32)ptr + i - 12 );
memcpy( ptr + i - 12, CARDGetXferredBytes, sizeof(CARDGetXferredBytes) );
}
if( read32( (u32)ptr + i ) != 0x7C0802A6 ) // MFLR
continue;
FuncPattern fp;
MPattern( (u8*)(ptr+i), size, &fp );
for( j=0; j < sizeof(CPatterns)/sizeof(FuncPattern); ++j )
{
if( CPatterns[j].PatchLength == 0 )
continue;
if( CPatterns[j].Found ) // Skip already found patches
continue;
if( CPattern( &fp, &(CPatterns[j]) ) )
{
if( CPatterns[j].Patch == CARDFreeBlocks )
{
if( CardLowestOff == 0 )
{
dbgprintf("CardLowestOff:0x%08X\n", i );
CardLowestOff = i;
}
//Check for CARDGetResultCode which is always (when used) above CARDFreeBlocks
if( read32( (u32)ptr + i - 0x30 ) == 0x2C030000 )
{
dbgprintf("Found [CARDGetResultCode] @ 0x%08X\n", (u32)ptr + i - 0x30 + SectionOffset );
memcpy( ptr + i - 0x30, CARDGetResultCode, sizeof(CARDGetResultCode) );
}
FoundCardFuncStart = 1;
}
if( FoundCardFuncStart == 0 )
continue;
dbgprintf("Found [%s] @ 0x%08X\n", CPatterns[j].Name, (u32)ptr + i + SectionOffset );
CPatterns[j].Found = (u32)ptr + i;
// If this is a patch group set all others of this group as found aswell
if( CPatterns[j].Group )
{
for( k=0; k < sizeof(CPatterns)/sizeof(FuncPattern); ++k )
{
if( CPatterns[k].Group == CPatterns[j].Group )
{
if( !CPatterns[k].Found ) //Don't overwrite the offset!
CPatterns[k].Found = -1; // Usually this holds the offset, to determinate it from a REALLY found pattern we set it -1 which still counts a logical TRUE
//dbgprintf("Setting [%s] to found!\n", CPatterns[k].Name );
}
}
}
//If by now no CARDProbe is found it won't be so set it to found to prevent CARDProbe B false hits
if( CPatterns[j].Patch == CARDRead )
{
for( k=0; k < sizeof(CPatterns)/sizeof(FuncPattern); ++k )
{
if( CPatterns[k].Patch == CARDProbe )
{
if( !CPatterns[k].Found ) //Don't overwrite the offset!
CPatterns[k].Found = -1;
}
}
}
if( strstr( CPatterns[j].Name, "Async" ) != NULL )
{
//dbgprintf("Async!\n");
//Most games only use the normal functions so we patch a branch over to async and clear the CB
//Find function call to our function
offset = (u32)ptr + i;
fail = 0;
while(fail < 3)
{
//dbgprintf("[%08X] %08X %08X(%08X)\n", offset, read32( offset ) & 0xFC000003,read32( offset ) & 0x03FFFFFC ,(read32( offset ) & 0x03FFFFFC ) + offset);
if( (read32( offset ) & 0xFC000003 ) == 0x48000001 )
{
if( (((read32( offset ) & 0x03FFFFFC ) + offset) & 0x03FFFFFC) == (u32)ptr+i )
break;
}
if( read32( offset ) == 0x4E800020 )
fail++;
offset+=4;
}
if( fail < 3 )
{
dbgprintf("Found function call to [%s] @ 0x%08X\n", CPatterns[j].Name, offset + SectionOffset );
//Now find function start
offset -= 4;
while(1)
{
if( read32( offset ) == 0x7C0802A6 )
break;
offset-=4;
}
dbgprintf("Found function start of [%s(Sync)] @ 0x%08X\n", CPatterns[j].Name, offset + SectionOffset );
//This patches a li rX, 0 before the Async function call for the Sync call
//Since this register of the cb is different per function we do this haxx
if( (read32( offset + 0x04 ) & 0x0000F000 ) == 0x00008000 ) // lis
{
write32( offset, read32( offset + 0x0C ) & 0xFBE00000 );
//Forge a branch to the async function
offset += 4;
u32 newval = ((u32)ptr + i) - offset;
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( offset, newval );
} else {
dbgprintf("Unhandled Async cb case!\n");
}
} else {
dbgprintf("No sync function found!\n");
}
memcpy( ptr + i, CPatterns[j].Patch, CPatterns[j].PatchLength );
} else {
memcpy( ptr + i, CPatterns[j].Patch, CPatterns[j].PatchLength );
}
}
}
}
for( j=0; j < sizeof(CPatterns)/sizeof(FuncPattern); ++j )
{
if( CPatterns[j].Found == 0 )
dbgprintf("Pattern %s not found!\n", CPatterns[j].Name );
}
return;
}
void DoPatches( char *ptr, u32 size, u32 SectionOffset )
{
u32 i=0,j=0,k=0,value;
u32 PatchCount = 0;
dbgprintf("DoPatches( 0x%p, %d, 0x%X)\n", ptr, size, SectionOffset );
// HACK: PokemonXD and Pokemon Colosseum low memory clear patch
if(( (read32(0)>>8) == 0x475858 ) || ( (read32(0)>>8) == 0x474336 ))
{
// patch out initial memset(0x1800, 0, 0x1800)
if( (read32(0) & 0xFF) == 0x4A ) // JAP
write32( 0x560C, 0x60000000 );
else // EUR/USA
write32( 0x5614, 0x60000000 );
// patch memset to jump to test function
write32(0x00005498, 0x4BFFABF0);
// patch in test < 0x3000 function
write32(0x00000088, 0x3D008000);
write32(0x0000008C, 0x61083000);
write32(0x00000090, 0x7C044000);
write32(0x00000094, 0x4180542C);
write32(0x00000098, 0x90E40004);
write32(0x0000009C, 0x48005400);
// skips __start init of debugger mem
write32(0x00003194, 0x48000028);
}
// Reset Found
for( k=0; k < sizeof(FPatterns)/sizeof(FuncPattern); ++k )
FPatterns[k].Found = 0;
if( ConfigGetConfig(DML_CFG_NMM) )
DoCardPatches( ptr, size, SectionOffset );
//Note: ORing the values prevents an early break out when a single patterns has multiple hits
PatchCount=0;
for( i=0; i < size; i+=4 )
{
if( (PatchCount & 1) == 0 )
{
if( read32( (u32)ptr + i ) == 0x3C00A800 ) // Loader
{
int j=0;
while( read32( (u32)ptr + i - j ) != 0x7C0802A6 ) // Seek to start of function
j+=4;
//Check if there is a lis %rX, 0xCC00 in this function
//At least Sunshine has one false hit on lis r3,0xA800
int k=0;
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xF81FFFFF) == 0x3800CC00 )
break;
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
k = 0;
while(1)
{
u32 val = read32( (u32)ptr + i + k );
if( (val & 0xFFFF ) == 0xCC00 )
{
write32( (u32)ptr + i + k, (val&0xFFFF0000) | 0xC000 );
//dbgprintf("Patch:lis 0x%08X\n", (u32)ptr + i + k + SectionOffset );
continue;
}
if( (val & 0xFC00FF00) == 0x90006000 )
{
write32( (u32)ptr + i + k, (val&0xFFFF00FF) | 0x2F00 );
//dbgprintf("Patch:stw 0x%08X\n", (u32)ptr + i + k + SectionOffset );
continue;
}
if( read32( (u32)ptr + i + k ) == 0x4E800020 )
break;
k+=4;
}
write32( (u32)ptr + i, 0x3C00A700 );
dbgprintf("Patch:Found [DVDLowRead]: 0x%08X\n", (u32)ptr + i + SectionOffset );
PatchCount |= 1;
} else if( read32( (u32)ptr + i ) == 0x3C60A800 ) // Games
{
int j=0;
while( read32( (u32)ptr + i - j ) != 0x7C0802A6 ) // Seek to start of function
j+=4;
//Check if there is a lis %rX, 0xCC00 in this function
//At least Sunshine has one false hit on lis r3,0xA800
int k=0;
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xF81FFFFF) == 0x3800CC00 )
{
write32( (u32)ptr + i + k - j, (read32((u32)ptr + i + k - j) & 0xFFFF0000) | 0xC000 );
break;
}
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
//Search addi 0x6000
while( 1 )
{
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
break;
if( (read32( (u32)ptr + i + k - j ) & 0xFFFF) == 0x6000 )
{
write32( (u32)ptr + i + k - j, (read32((u32)ptr + i + k - j) & 0xFFFF0000) | 0x2F00 );
break;
}
k += 4;
}
if( read32( (u32)ptr + i + k - j ) == 0x4E800020 )
{
//dbgprintf("Patch:No 0xCC00 found around:%08X\n", (u32)ptr+i);
continue;
}
write32( (u32)ptr + i, 0x3C60A700 );
dbgprintf("Patch:Found [DVDLowRead]: 0x%08X\n", (u32)ptr + i + SectionOffset );
PatchCount |= 1;
}
}
if( (PatchCount & 2) == 0 )
if( (read32( (u32)ptr + i )&0xFC00FFFF) == 0x5400077A &&
(read32( (u32)ptr + i + 4 )&0xFC00FFFF) == 0x28000000 &&
read32( (u32)ptr + i + 8 ) == 0x41820008 &&
(read32( (u32)ptr + i +12 )&0xFC00FFFF) == 0x64002000
)
{
dbgprintf("Patch:Found [__OSDispatchInterrupt]: 0x%08X 0x%08X\n", (u32)ptr + i + 0 + SectionOffset, (u32)ptr + i + 0x1A8 + SectionOffset );
write32( (u32)ptr + i + 0, (read32( (u32)ptr + i + 0 ) & 0xFFFF0000) | 0x0463 );
write32( (u32)ptr + i + 0x1A8, (read32( (u32)ptr + i + 0x1A8 ) & 0xFFFF0000) | 0x0463 );
PatchCount |= 2;
}
if( (PatchCount & 4) == 0 )
if( read32( (u32)ptr + i ) == 0x5480056A &&
read32( (u32)ptr + i + 4 ) == 0x28000000 &&
read32( (u32)ptr + i + 8 ) == 0x40820008 &&
(read32( (u32)ptr + i +12 )&0xFC00FFFF) == 0x60000004
)
{
dbgprintf("Patch:Found [SetInterruptMask]: 0x%08X\n", (u32)ptr + i + 12 + SectionOffset );
write32( (u32)ptr + i + 12, (read32( (u32)ptr + i + 12 ) & 0xFFFF0000) | 0x4000 );
PatchCount |= 4;
}
if( (PatchCount & 8) == 0 )
if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0x6000 &&
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x002A &&
(read32( (u32)ptr + i + 8 ) & 0xFFFF) == 0x0054
)
{
u32 Offset = (u32)ptr + i - 8;
dbgprintf("Patch:Found [__DVDIntrruptHandler]: 0x%08X\n", Offset + SectionOffset );
if( (read32(Offset+4) & 0xFFFF) == 0xCC00 ) // Loader
{
value = *(vu32*)(Offset+4);
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)(Offset+4) = value;
} else {
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)Offset = value;
}
Offset += 8;
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x00002F30;
*(vu32*)Offset = value;
Offset += 20;
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
*(vu32*)Offset = 0x3D00CD00; Offset += 4;
*(vu32*)Offset = 0x38000034; Offset += 4;
*(vu32*)Offset = 0x90080004; Offset +=16;
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
*(vu32*)Offset = 0x3D00CD00; Offset += 4;
*(vu32*)Offset = 0x3C004000; Offset += 4;
*(vu32*)Offset = 0x90080030; Offset +=32;
if( (read32(Offset-8) & 0xFFFF) == 0xCC00 ) // Loader
{
Offset -= 8;
}
dbgprintf("Patch:[__DVDInterruptHandler] 0x%08X\n", Offset + SectionOffset );
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x0000C000;
*(vu32*)Offset = value;
Offset += 4;
value = *(vu32*)Offset;
value&= 0xFFFF0000;
value|= 0x00002F08;
*(vu32*)Offset = value;
PatchCount |= 8;
}
if( (PatchCount & 32) == 0 )
{
if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0xCC00 && // Game
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x6000 &&
(read32( (u32)ptr + i +12 ) & 0xFFFF) == 0x001C
)
{
u32 Offset = (u32)ptr + i;
dbgprintf("Patch:[cbForStateBusy] 0x%08X\n", Offset + SectionOffset );
write32( Offset, 0x3C80C000 );
write32( Offset+4, 0x38842F30 );
PatchCount |= 32;
} else if( (read32( (u32)ptr + i + 0 ) & 0xFFFF) == 0xCC00 && // Loader
(read32( (u32)ptr + i + 4 ) & 0xFFFF) == 0x6018 &&
(read32( (u32)ptr + i +12 ) & 0xFFFF) == 0x001C
)
{
u32 Offset = (u32)ptr + i;
dbgprintf("Patch:[cbForStateBusy] 0x%08X\n", Offset + SectionOffset );
write32( Offset, 0x3C60C000 );
write32( Offset+4, 0x80832F48 );
PatchCount |= 32;
}
}
if( ConfigGetConfig(DML_CFG_CHEATS) || ConfigGetConfig( DML_CFG_DEBUGGER ) )
{
// OSSleepThread(Pattern 1)
if( (PatchCount & 16) == 0 )
if( read32((u32)ptr + i + 0 ) == 0x3C808000 &&
( read32((u32)ptr + i + 4 ) == 0x38000004 || read32((u32)ptr + i + 4 ) == 0x808400E4 ) &&
( read32((u32)ptr + i + 8 ) == 0x38000004 || read32((u32)ptr + i + 8 ) == 0x808400E4 )
)
{
int j = 12;
while( read32((u32)ptr + i + j ) != 0x4E800020 )
j+=4;
dbgprintf("Patch:[Hook:OSSleepThread] at 0x%08X\n", ((u32)ptr + i + j) | 0x80000000 );
u32 DBGSize;
//if( ConfigGetConfig( DML_CFG_DEBUGGER ) )
//{
memcpy( (void*)0x1800, kenobigcDBG, sizeof(kenobigcDBG) );
DBGSize = sizeof(kenobigcDBG);
//} else {
// memcpy( (void*)0x1800, kenobigc, sizeof(kenobigc) );
// DBGSize = sizeof(kenobigc);
//}
if( ConfigGetConfig(DML_CFG_DEBUGWAIT) )
write32( P2C(read32(0x1808)), 1 );
else
write32( P2C(read32(0x1808)), 0 );
u32 newval = 0x18A8 - ((u32)ptr + i + j);
newval&= 0x03FFFFFC;
newval|= 0x48000000;
write32( (u32)ptr + i + j, newval );
memcpy( (void*)0x1800, (void*)0, 6 );
char *path = (char*)malloc( 128 );
if( ConfigGetConfig(DML_CFG_CHEAT_PATH) )
{
sprintf( path, "%s", ConfigGetCheatPath() );
} else {
sprintf( path, "/games/%.6s/%.6s.gct", (char*)0x1800, (char*)0x1800 );
}
FIL CodeFD;
u32 read;
if( f_open( &CodeFD, path, FA_OPEN_EXISTING|FA_READ ) == FR_OK )
{
if( CodeFD.fsize >= 0x2E80 - (0x1800+DBGSize-8) )
{
dbgprintf("Patch:Cheatfile is too large, it must not be large than %d bytes!\n",
0x2E80 - (0x1800+DBGSize-8));
} else {
if( f_read( &CodeFD, (void*)(0x1800+DBGSize-8), CodeFD.fsize, &read ) == FR_OK )
{
dbgprintf("Patch:Copied cheat file to memory\n");
write32( 0x1804, 1 );
} else
dbgprintf("Patch:Failed to read cheat file:\"%s\"\n", path );
}
f_close( &CodeFD );
} else {
dbgprintf("Patch:Failed to open/find cheat file:\"%s\"\n", path );
}
free(path);
PatchCount |= 16;
}
}
if( ConfigGetConfig(DML_CFG_CHEATS) )
{
if( PatchCount == 63 )
break;
} else {
if( PatchCount == 47 )
break;
}
}
for( i=0; i < size; i+=4 )
{
if( read32( (u32)ptr + i ) != 0x4E800020 )
continue;
i+=4;
FuncPattern fp;
MPattern( (u8*)(ptr+i), size, &fp );
for( j=0; j < sizeof(FPatterns)/sizeof(FuncPattern); ++j )
{
if( FPatterns[j].Found ) //Skip already found patches
continue;
if( CPattern( &fp, &(FPatterns[j]) ) )
{
u32 FOffset = (u32)ptr + i;
dbgprintf("Patch:Found [%s]: 0x%08X\n", FPatterns[j].Name, FOffset + SectionOffset );
switch( FPatterns[j].PatchLength )
{
case 0xdead0004: // Audiostreaming hack
{
switch( read32(0) >> 8 )
{
case 0x474544: // Eternal Darkness
break;
default:
{
write32( FOffset + 0xB4, 0x60000000 );
write32( FOffset + 0xC0, 0x60000000 );
} break;
}
} break;
case 0xdead0001: // Patch for __GXSetVAT, fixes the dungeon map freeze in Wind Waker
{
switch( read32(0) >> 8 )
{
case 0x505A4C: // The Legend of Zelda: Collector's Edition
if( !(DOLSize == 3847012 || DOLSize == 3803812) ) // only patch the main.dol of the Zelda:ww game
break;
case 0x475A4C: // The Legend of Zelda: The Wind Waker
{
write32(FOffset, (read32(FOffset) & 0xff00ffff) | 0x220000);
memcpy((void *)(FOffset + 4), __GXSetVAT_patch, sizeof(__GXSetVAT_patch));
dbgprintf("Patch:Applied __GXSetVAT patch\n");
} break;
default:
break;
}
} break;
case 0xdead000B: // PADRead hook
{
//Find blr
j=0;
while(1)
{
if( read32( FOffset + j ) == 0x4E800020 )
break;
j+=4;
}
dbgprintf("Patch:[PADRead hook] %08X\n", FOffset + j );
memcpy( (void*)0x2EE0, padipc, sizeof(padipc) );
PatchB( 0x2EE0, FOffset + j );
write32( 0x12FC, 0 );
} break;
default:
{
if( ConfigGetConfig( DML_CFG_CHEATS ) )
{
if( FPatterns[j].Patch == patch_fwrite_GC )
break;
}
if( (FPatterns[j].Length >> 16) == 0xdead )
{
dbgprintf("DIP:Unhandled dead case:%08X\n", FPatterns[j].Length );
} else
{
memcpy( (void*)(FOffset), FPatterns[j].Patch, FPatterns[j].PatchLength );
if ((FPatterns[j].Patch == (u8 *)__dvdLowAudioStatusNULL) && ((read32(0) >> 8) == 0x47494B))
{
// Ikaruga resets to the main menu, if the returned status is 0(finished playing the stream), but it works if 1(still playing) is returned
write32(FOffset + 36, 0x38600001);
dbgprintf("Patch:LowAudioStatus patched for Ikaruga\n");
}
}
} break;
}
// If this is a patch group set all others of this group as found aswell
if( FPatterns[j].Group )
{
for( k=0; k < sizeof(FPatterns)/sizeof(FuncPattern); ++k )
{
if( FPatterns[k].Group == FPatterns[j].Group )
{
if( !FPatterns[k].Found ) // Don't overwrite the offset!
FPatterns[k].Found = -1; // Usually this holds the offset, to determinate it from a REALLY found pattern we set it -1 which still counts a logical TRUE
//dbgprintf("Setting [%s] to found!\n", FPatterns[k].Name );
}
}
}
}
}
}
}

52
Patches.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _PATCHES_
#define _PATCHES_
#include "string.h"
#include "global.h"
#include "ipc.h"
#include "alloc.h"
#include "ff.h"
#include "vsprintf.h"
#include "HW.h"
#include "dol.h"
typedef struct PatchInfo
{
u8 *Signature;
u8 *Mask;
u32 Length;
u32 FunctionLength;
u8 *Patch;
u32 PatchLength;
char *Name;
} PatchInfo;
typedef struct FuncPattern
{
u32 Length;
u32 Loads;
u32 Stores;
u32 FCalls;
u32 Branch;
u32 Moves;
u8 *Patch;
u32 PatchLength;
char *Name;
u32 Group;
u32 Found;
} FuncPattern;
typedef struct PatchCache
{
u32 Offset;
u32 PatchID;
} PatchCache;
void PatchGCIPL( void );
void DoPatches( char *ptr, u32 size, u32 SectionOffset );
void DoCardPatches( char *ptr, u32 size, u32 SectionOffset );
void DoPatchesLoader( char *ptr, u32 size );
#endif

205
alloc.c Normal file
View File

@ -0,0 +1,205 @@
#include "alloc.h"
#include "vsprintf.h"
u8 *RAM;//[_AHEAP_SIZE_TOTAL];
HeapInfoEntry *HeapInfoEntries=(HeapInfoEntry *)NULL;
extern u32 DRAMRead( u32 a );
extern void DRAMWrite( u32 a, u32 b );
void HeapInit( u8 *Offset )
{
//RAM = (u8*)0xFFFE4000;
//RAM = (u8*)0x13600000;
//RAM = (u8*)0x00600000;
RAM = Offset;
HeapInfoEntries = (HeapInfoEntry*)(RAM+_AHEAP_SIZE);
memset32( HeapInfoEntries, 0, _AHEAP_INFO_SIZE );
while( HeapInfoEntries[0].Offset != 0 )
{
EXIControl(1);
dbgprintf("Failed to clear memory!:%08X", HeapInfoEntries[0].Offset );
Shutdown();
}
// dbgprintf("Cleared 0x%04X bytes Space for %d allocs\n", _AHEAP_INFO_SIZE, _AHEAP_INFO_SIZE / 8 );
}
void *malloc( u32 _size )
{
if( _size == 0 )
return NULL;
if( _size > _AHEAP_SIZE )
return NULL;
//align size to 32, easy cheat toallow all allocs to be aligned easily
u32 size = (_size+0x1F) & (~0x1F);
//find a free entry to be used
u32 entry = 0xdeadbeef;
u32 i;
for( i=0; i < _AHEAP_INFO_SIZE / sizeof(HeapInfoEntry); ++i )
{
if( HeapInfoEntries[i].Offset == 0 )
{
entry = i;
break;
}
}
if( entry == 0xdeadbeef )
{
EXIControl(1);
dbgprintf("Alloc: run out of entries!\n");
while(1);
}
dbgprintf("Using entry:%d to alloc %u(%u) bytes...\n", entry, size, _size );
//Now we search a used entry
u32 used_entry = 0xdeadbeef;
for( i=0; i < _AHEAP_INFO_SIZE / sizeof(HeapInfoEntry); ++i )
{
if( HeapInfoEntries[i].Offset == 0 )
continue;
used_entry = i;
break;
}
if( used_entry == 0xdeadbeef )
{
//dbgprintf("There are no other entries used atm\n");
HeapInfoEntries[entry].Offset = RAM;
HeapInfoEntries[entry].Size = size;
//dbgprintf("alloc1: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[entry].Offset, HeapInfoEntries[entry].Size, entry );
return HeapInfoEntries[entry].Offset;
}
find_space:
;
//dbgprintf("[%02d]Offset:%08X Size:%08X\n", used_entry, HeapInfoEntries[used_entry].Offset, HeapInfoEntries[used_entry].Size );
//now we search for the next closest and the previous closest entry
u32 next = 0xdeadbeef;
u32 prev = 0xdeadbeef;
for( i=0; i < _AHEAP_INFO_SIZE / sizeof(HeapInfoEntry); ++i )
{
if( HeapInfoEntries[i].Offset == 0 )
continue;
if( used_entry == i )
continue;
if( next == 0xdeadbeef )
{
if( HeapInfoEntries[i].Offset > HeapInfoEntries[used_entry].Offset )
next = i;
} else {
if( HeapInfoEntries[i].Offset < HeapInfoEntries[next].Offset && HeapInfoEntries[i].Offset > HeapInfoEntries[used_entry].Offset )
next = i;
}
if( prev == 0xdeadbeef )
{
if( HeapInfoEntries[i].Offset < HeapInfoEntries[used_entry].Offset )
prev = i;
} else {
if( HeapInfoEntries[i].Offset > HeapInfoEntries[prev].Offset && HeapInfoEntries[i].Offset < HeapInfoEntries[used_entry].Offset )
prev = i;
}
}
if( next == 0xdeadbeef )
{
//dbgprintf("This is the last entry\n");
//check if there is engough space left for our alloc
if( (u32)(HeapInfoEntries[used_entry].Offset-RAM) + HeapInfoEntries[used_entry].Size + size <= _AHEAP_SIZE )
{
HeapInfoEntries[entry].Offset = HeapInfoEntries[used_entry].Offset + HeapInfoEntries[used_entry].Size;
HeapInfoEntries[entry].Size = size;
//dbgprintf("alloc2: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[entry].Offset, HeapInfoEntries[entry].Size, entry );
return HeapInfoEntries[entry].Offset;
}
;//dbgprintf("2Not enough space left only had:%d\n", HEAP_SIZE - ((u32)(HeapInfoEntries[used_entry].Offset-RAM) + HeapInfoEntries[used_entry].Size) );
} else if( (u32)(HeapInfoEntries[used_entry].Offset) + HeapInfoEntries[used_entry].Size + size < (u32)(HeapInfoEntries[next].Offset) )
{
HeapInfoEntries[entry].Offset = HeapInfoEntries[used_entry].Offset + HeapInfoEntries[used_entry].Size;
HeapInfoEntries[entry].Size = size;
//dbgprintf("alloc4: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[entry].Offset, HeapInfoEntries[entry].Size, entry );
return HeapInfoEntries[entry].Offset;
} else {
;//dbgprintf("4Not enough space left only had:%d %d:%d\n", (u32)( HeapInfoEntries[next].Offset - HeapInfoEntries[used_entry].Offset ) - HeapInfoEntries[used_entry].Size, next, used_entry );
}
if( prev == 0xdeadbeef )
{
//dbgprintf("This is the first entry\n");
if( (u32)(HeapInfoEntries[used_entry].Offset-RAM) >= size )
{
HeapInfoEntries[entry].Offset = HeapInfoEntries[used_entry].Offset - size;
HeapInfoEntries[entry].Size = size;
//dbgprintf("alloc3: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[entry].Offset, HeapInfoEntries[entry].Size, entry );
return HeapInfoEntries[entry].Offset;
}
;//dbgprintf("3Not enough space left only had:%d\n", (u32)(HeapInfoEntries[used_entry].Offset-RAM) );
} else if( (u32)(HeapInfoEntries[prev].Offset) + HeapInfoEntries[prev].Size + size < (u32)(HeapInfoEntries[used_entry].Offset) )
{
HeapInfoEntries[entry].Offset = HeapInfoEntries[prev].Offset + HeapInfoEntries[prev].Size;
HeapInfoEntries[entry].Size = size;
//dbgprintf("alloc5: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[entry].Offset, HeapInfoEntries[entry].Size, entry );
return HeapInfoEntries[entry].Offset;
} else {
;//dbgprintf("5Not enough space left only had:%d\n", (u32)(HeapInfoEntries[used_entry].Offset-HeapInfoEntries[prev].Offset) - HeapInfoEntries[prev].Size );
}
//if we land here we have to go to the next entry
u32 temp = used_entry + 1;
used_entry = 0xdeadbeef;
for( i=temp; i < _AHEAP_INFO_SIZE / sizeof(HeapInfoEntry); ++i )
{
if( HeapInfoEntries[i].Offset == 0 )
continue;
used_entry = i;
break;
}
if( used_entry != 0xdeadbeef )
goto find_space;
dbgprintf("failed to alloc %d bytes\n", size );
return NULL;
}
void *malloca( u32 size, u32 align )
{
return malloc( size );
}
void free( void *ptr )
{
if( ptr == NULL )
return;
u32 i;
for( i=0; i < _AHEAP_INFO_SIZE / sizeof(HeapInfoEntry); ++i )
{
if( HeapInfoEntries[i].Offset == ptr )
{
//dbgprintf("free: ptr:%p size:%08X Entry:%d\n", HeapInfoEntries[i].Offset, HeapInfoEntries[i].Size, i );
HeapInfoEntries[i].Offset = NULL;
HeapInfoEntries[i].Size = 0;
ptr = NULL;
return;
}
}
}

23
alloc.h Normal file
View File

@ -0,0 +1,23 @@
#include "utils.h"
#include "memory.h"
#include "HW.h"
#ifndef _ALLOC_
#define _ALLOC_
#define _AHEAP_SIZE_TOTAL 0x3000
#define _AHEAP_INFO_SIZE 0x0100
#define _AHEAP_SIZE _AHEAP_SIZE_TOTAL-_AHEAP_INFO_SIZE
typedef struct
{
u8 *Offset;
u32 Size;
} HeapInfoEntry;
void HeapInit( u8 *Offset );
void *malloc( u32 size );
void *malloca( u32 size, u32 align );
void free( void *ptr );
#endif

23
asm/CARDCheck.S Normal file
View File

@ -0,0 +1,23 @@
#include <asm.h>
#
# r3 Channel
CARDCheck:
mflr %r0
cmpwi %r3, 0
beq CARDPresent
li %r3, -3
b end
CARDPresent:
li %r3, 0
end:
lis %r4, 0xC000
stw %r3, 0x2F94(%r4)
mtlr %r0
blr

43
asm/CARDCheckAsync.S Normal file
View File

@ -0,0 +1,43 @@
#include <asm.h>
#
# r3 Channel
# r4 cb( chan, res )
CARDCheck:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
cmpwi %r3, 0
beq CARDPresent
cmpwi %r4, 0
beq NoCardNoCB
mtctr %r4
li %r4, -3
bctrl
NoCardNoCB:
li %r3, -3
b end
CARDPresent:
cmpwi %r4, 0
beq CardNoCB
mtctr %r4
li %r4, 0
bctrl
CardNoCB:
li %r3, 0
end:
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

60
asm/CARDCheckEX.S Normal file
View File

@ -0,0 +1,60 @@
#include <asm.h>
#
# r3 Channel
# r4 *xfer bytes used to repair the FS
# r5 cb
CARDCheckEx:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
cmpwi %r3, 0
beq CARDPresent
cmpwi %r4, 0
beq NoCardZeroPtr
li %r6, 0
stw %r6, 0(%r4)
NoCardZeroPtr:
cmpwi %r5, 0
beq NoCardNoCB
mtctr %r5
li %r4, -3
bctrl
NoCardNoCB:
li %r3, -3
b end
CARDPresent:
cmpwi %r4, 0
beq CardZeroPtr
li %r6, 0
stw %r6, 0(%r4)
CardZeroPtr:
cmpwi %r5, 0
beq CardNoCB
mtctr %r5
li %r4, 0
bctrl
CardNoCB:
li %r3, 0
end:
lis %r4, 0xC000
stw %r3, 0x2F94(%r4)
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

47
asm/CARDClose.S Normal file
View File

@ -0,0 +1,47 @@
#include <asm.h>
#
# r3 FileInfo
CARDClose:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xC100
stw %r0, 0x2F60(%r7)
lwz %r0, 0x04(%r3)
stw %r0, 0x2F64(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
lwz %r3, 0x2F94(%r7)
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

88
asm/CARDCreate.S Normal file
View File

@ -0,0 +1,88 @@
#include <asm.h>
#
# r3 chan
# r4 fileName
# r5 size
# r6 fileInfo
# r7 cb
CARDCreate:
cmpwi %r3, 0
beq DoCode
li %r3, -3
li %r4, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
mr %r12, %r7
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xC200
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
stw %r6, 0x2F6C(%r7)
#cache workaround for the filename
li %r5, 8
mtctr %r5
lis %r5, 0xC000
invalidloop:
lwz %r0, 0(%r4)
stw %r0, 0x17E0(%r5)
addi %r4, %r4, 4
addi %r5, %r5, 4
bdnz invalidloop
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
lwz %r0, 0x2F90(%r7)
stw %r0, 0x04(%r6)
cmpwi %r12, 0
beq skip_cb
mtlr %r12
li %r3, 0
li %r4, 0
blrl
skip_cb:
lis %r7, 0xC000
lwz %r3, 0x2F94(%r7)
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

80
asm/CARDDelete.S Normal file
View File

@ -0,0 +1,80 @@
#include <asm.h>
#
# r3 chan
# r4 fileName
# r5 cb
CARDDelete:
cmpwi %r3, 0
beq DoCode
li %r3, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
mr %r12, %r5
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xC600
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
#cache workaround for the filename
li %r5, 8
mtctr %r5
lis %r5, 0xC000
invalidloop:
lwz %r0, 0(%r4)
stw %r0, 0x17E0(%r5)
addi %r4, %r4, 4
addi %r5, %r5, 4
bdnz invalidloop
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtlr %r12
lwz %r3, 0x2F94(%r7)
li %r4, 0
blrl
skip_cb:
lis %r7, 0xC000
lwz %r3, 0x2F94(%r7)
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

69
asm/CARDFastDelete.S Normal file
View File

@ -0,0 +1,69 @@
#include <asm.h>
#
# r3 chan
# r4 FileNo
# r5 cb
CARDFastDelete:
cmpwi %r3, 0
beq DoCode
li %r3, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
mr %r12, %r5
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xCA00
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtlr %r12
lwz %r3, 0x2F94(%r7)
li %r4, 0
blrl
skip_cb:
lis %r7, 0xC000
lwz %r3, 0x2F94(%r7)
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

62
asm/CARDFastOpen.S Normal file
View File

@ -0,0 +1,62 @@
#include <asm.h>
#
# r3 chan
# r4 FileNo
# r5 FileInfo
CARDFastOpen:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
cmpwi %r3, 0
bne NoCard
#send cmd to DM
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xC500
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
lwz %r3, 0x2F90(%r7)
stw %r3, 0x10(%r5)
stw %r4, 0x04(%r5)
lwz %r3, 0x2F94(%r7)
b end
NoCard:
li %r3, -3
end:
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

32
asm/CARDFreeBlocks.S Normal file
View File

@ -0,0 +1,32 @@
#include <asm.h>
#
# r3 chan
# r4 byteNotUsed
# r5 filesNotUsed
CARDFreeBlocks:
mflr %r0
cmpwi %r3, 0
beq CARDPresent
li %r3, -3
b end
CARDPresent:
lis %r3, 0x7F
addi %r3, %r3, 0x6000
stw %r3, 0(%r4)
li %r3, 16
stw %r3, 0(%r5)
li %r3, 0
end:
mtlr %r0
blr

30
asm/CARDGetEncoding.S Normal file
View File

@ -0,0 +1,30 @@
#include <asm.h>
#
# r3 Channel
# r4 endcoding(u16)
CARDGetEncoding:
cmpwi %r3, 0
beq DoCode
li %r3, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#0 is USA/EUR, 1 is JAP
li %r0, 0
sth %r0, 0(%r4)
end:
li %r3, 0
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

30
asm/CARDGetMemSize.S Normal file
View File

@ -0,0 +1,30 @@
#include <asm.h>
#
# r3 Channel
# r4 size(u16)
CARDGetMemSize:
cmpwi %r3, 0
beq DoCode
li %r3, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#possible sizes 4,8,16,32,64,128
li %r0, 8
sth %r0, 0(%r4)
end:
li %r3, 0
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

19
asm/CARDGetResultCode.S Normal file
View File

@ -0,0 +1,19 @@
#include <asm.h>
#
# r3 Channel
CARDGetResultCode:
cmpwi %r3, 0
beq CARDPresent
li %r3, -3
b end
CARDPresent:
lis %r3, 0xC000
lwz %r3, 0x2F94(%r3)
end:
blr

29
asm/CARDGetSerialNo.S Normal file
View File

@ -0,0 +1,29 @@
#include <asm.h>
#
# r3 Channel
# r4 serialNo
CARDGetSerialNo:
cmpwi %r3, 0
beq DoCode
li %r3, -3
blr
DoCode:
mflr %r0
lis %r3, 0xc7bd
subi %r3, %r3, 0x26C
stw %r3, 0x00(%r4)
lis %r3, 0xf47f
subi %r3, %r3, 0x3924
stw %r3, 0x04(%r4)
li %r3, 0
mtlr %r0
blr

74
asm/CARDGetStats.S Normal file
View File

@ -0,0 +1,74 @@
#include <asm.h>
#
# r3 chan
# r4 FileNo
# r5 Stat
# r6 cb
CARDGetStats:
cmpwi %r3, 0
beq DoCode
li %r3, 0
li %r4, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
mr %r12, %r6
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
lis %r0, 0xC300
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
#cache workaround
li %r6, 27
mtctr %r6
lis %r6, 0xC000
addi %r6, %r6, 0x1780
invalidloop:
lwz %r0, 0(%r6)
stw %r0, 0(%r5)
addi %r5, %r5, 4
addi %r6, %r6, 4
bdnz invalidloop
lwz %r3, 0x2F94(%r7)
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

17
asm/CARDGetXferredBytes.S Normal file
View File

@ -0,0 +1,17 @@
#include <asm.h>
#
# r3 Channel
CARDGetEncoding:
cmpwi %r3, 0
beq DoCode
blr
DoCode:
lis %r3, 0xC000
lwz %r3, 0x2FA0(%r3)
blr

26
asm/CARDMount.S Normal file
View File

@ -0,0 +1,26 @@
#include <asm.h>
#
# r3 Channel
# r4 workarea
# r5 detachCallback
CARDMount:
mflr %r0
stw %r0, 4(%sp)
cmpwi %r3, 0
beq CARDPresent
li %r3, -3
b end
CARDPresent:
li %r3, 0
end:
lwz %r0, 4(%sp)
mtlr %r0
blr

42
asm/CARDMountAsync.S Normal file
View File

@ -0,0 +1,42 @@
#include <asm.h>
#
# r3 Channel
# r4 workarea
# r5 detachCallback
# r6 attachCallback
CARDMountAsync:
cmpwi %r3, 0
beq DoCode
li %r3, -3
lis %r7, 0xC000
stw %r3, 0x2F94(%r7)
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
li %r3, 0
li %r4, 0
cmpwi %r6, 0
beq end
mtctr %r6
bctrl
end:
li %r3, 0
li %r4, 0
lis %r7, 0xC000
stw %r3, 0x2F94(%r7)
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

71
asm/CARDOpen.S Normal file
View File

@ -0,0 +1,71 @@
#include <asm.h>
#
# r3 chan
# r4 FileName
# r5 FileInfo
CARDOpen:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
cmpwi %r3, 0
bne NoCard
#send cmd to DM
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
lis %r7, 0xC000
#cmd is the same as the offset, one opcode saved!
stw %r7, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
#cache workaround for the filename
li %r3, 8
mtctr %r3
lis %r3, 0xC000
invalidloop:
lwz %r0, 0(%r4)
stw %r0, 0x17E0(%r3)
addi %r4, %r4, 4
addi %r3, %r3, 4
bdnz invalidloop
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
lwz %r0, 0x2F90(%r7)
stw %r0, 0x04(%r5)
lwz %r3, 0x2F94(%r7)
b end
NoCard:
li %r3, -3
end:
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

21
asm/CARDProbe.S Normal file
View File

@ -0,0 +1,21 @@
#include <asm.h>
#
# r3 Channel
CARDProbe:
mflr %r0
cmpwi %r3, 0
beq CARDPresent
li %r3, 0
b end
CARDPresent:
li %r3, 1
end:
mtlr %r0
blr

41
asm/CARDProbeEX.S Normal file
View File

@ -0,0 +1,41 @@
#include <asm.h>
#
# r3 Channel
# r4 MemSize (can be zero ptr)
# r5 SecSize (can be zero ptr)
CARDProbeEX:
mflr %r0
cmpwi %r3, 0
beq CARDPresent
li %r3, -3
b end
CARDPresent:
cmpwi %r4, 0
beq ZeroMemPtr
li %r3, 8
stw %r3, 0(%r4)
ZeroMemPtr:
cmpwi %r5, 0
beq ZeroSecPtr
li %r3, 0x2000
stw %r3, 0(%r5)
ZeroSecPtr:
li %r3, 0
end:
mtlr %r0
blr

82
asm/CARDRead.S Normal file
View File

@ -0,0 +1,82 @@
#include <asm.h>
#
# r3 file *
# r4 buffer
# r5 length
# r6 offset
# r7 cb
CardWrite:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x20(%sp)
stw %r31, 0x1C(%sp)
#Update fileinfo
stw %r5, 0x0C(%r3)
stw %r6, 0x08(%r3)
#send cmd to DM
mr %r12, %r7
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
srwi %r7, %r5, 5
mtctr %r7
mr %r7, %r4
invalidloop:
dcbi %r0, %r7
addi %r7, %r7, 0x20
bdnz invalidloop
lis %r7, 0xC000
lis %r0, 0xC900
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
stw %r6, 0x2F6C(%r7)
lwz %r0, 0x04(%r3)
stw %r0, 0x2F70(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtctr %r12
li %r3, 0
li %r4, 0
bctrl
skip_cb:
li %r3, 0
mr %r4, %r3
lwz %r0, 0x24(%sp)
lwz %r31, 0x1C(%sp)
addi %sp, %sp, 0x20
mtlr %r0
blr

87
asm/CARDRename.S Normal file
View File

@ -0,0 +1,87 @@
#include <asm.h>
#
# r3 chan
# r4 old
# r5 new
# r6 cb
CARDRename:
mflr %r8
cmpwi %r3, 0
bne NoCard
#send cmd to DM
mr %r12, %r6
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
addi %r7, %r7, 0x20
dcbi %r0, %r7
#cache workaround for the filename
li %r3, 8
mtctr %r3
lis %r3, 0xC000
invalidloopA:
lwz %r0, 0(%r4)
stw %r0, 0x17C0(%r3)
addi %r4, %r4, 4
addi %r3, %r3, 4
bdnz invalidloopA
#cache workaround for the filename
li %r3, 8
mtctr %r3
lis %r3, 0xC000
invalidloopB:
lwz %r0, 0(%r5)
stw %r0, 0x17E0(%r3)
addi %r5, %r5, 4
addi %r3, %r3, 4
bdnz invalidloopB
lis %r7, 0xC000
lis %r0, 0xCB00
stw %r0, 0x2F60(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtlr %r12
li %r3, 0
lwz %r4, 0x2F94(%r7)
blrl
skip_cb:
lwz %r3, 0x2F94(%r7)
b end
NoCard:
li %r3, -3
end:
mr %r4, %r3
mtlr %r8
blr

83
asm/CARDSetStats.S Normal file
View File

@ -0,0 +1,83 @@
#include <asm.h>
#
# r3 chan
# r4 fileNo
# r5 stat
# r6 cb
CARDSetStat:
cmpwi %r3, 0
beq DoCode
li %r3, 0
li %r4, -3
blr
DoCode:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#send cmd to DM
mr %r12, %r6
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbst %r0, %r7
#stat
mr %r7, %r5
#0x00
dcbst %r0, %r7
addi %r7, %r7, 0x20
#0x20
dcbst %r0, %r7
addi %r7, %r7, 0x20
#0x40
dcbst %r0, %r7
addi %r7, %r7, 0x20
#0x60
dcbst %r0, %r7
sc
lis %r7, 0xC000
lis %r0, 0xC400
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtctr %r12
li %r3, 0
li %r4, 0
bctrl
skip_cb:
li %r3, 0
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

80
asm/CARDWrite.S Normal file
View File

@ -0,0 +1,80 @@
#include <asm.h>
#
# r3 file *
# r4 buffer
# r5 length
# r6 offset
# r7 cb
CardWrite:
mflr %r0
stw %r0, 4(%sp)
stwu %sp, -0x10(%sp)
#Update fileinfo
stw %r5, 0x0C(%r3)
stw %r6, 0x08(%r3)
#send cmd to DM
mr %r12, %r7
li %r0, 0
lis %r7, 0xC000
addi %r7, %r7, 0x2F60
#IPC area
dcbi %r0, %r7
srwi %r7, %r5, 5
mtctr %r7
mr %r7, %r4
invalidloop:
dcbst %r0, %r7
addi %r7, %r7, 0x20
bdnz invalidloop
sc
lis %r7, 0xC000
lis %r0, 0xC800
stw %r0, 0x2F60(%r7)
stw %r4, 0x2F64(%r7)
stw %r5, 0x2F68(%r7)
stw %r6, 0x2F6C(%r7)
lwz %r0, 0x04(%r3)
stw %r0, 0x2F70(%r7)
li %r0, 3
stw %r0, 0x2F78(%r7)
ready_loop:
lwz %r0, 0x2F78(%r7)
cmpwi %r0, 3
beq ready_loop
wait_loop:
lwz %r0, 0x2F9C(%r7)
andi. %r0, %r0, 0x14
cmpwi %r0, 0
beq wait_loop
cmpwi %r12, 0
beq skip_cb
mtctr %r12
li %r3, 0
li %r4, 0
bctrl
skip_cb:
li %r3, 0
mr %r4, %r3
lwz %r0, 0x14(%sp)
addi %sp, %sp, 0x10
mtlr %r0
blr

60
asm/DVDInquiryAsync.S Normal file
View File

@ -0,0 +1,60 @@
#include <asm.h>
# issue read command
#
# r3 dvdstruct
# r4 dst
# r5 cb
DVDInquiryAsync:
stwu %sp, -0x10(%sp)
mflr %r0
stw %r0, 8(%sp)
#update dvdstruct
li %r0, 0
stw %r0, 0x00(%r3)
stw %r0, 0x04(%r3)
stw %r0, 0x0C(%r3)
#offset
stw %r0, 0x10(%r3)
li %r0, 2
stw %r0, 0x08(%r3)
li %r0, 0x20
#TransferSize
stw %r0, 0x1C(%r3)
stw %r0, 0x20(%r3)
#size
stw %r0, 0x14(%r3)
#ptr
stw %r4, 0x18(%r3)
#cb
stw %r5, 0x28(%r3)
#Inquiry reply
li %r0, 0
dcbi %r0, %r4
li %r0, 0x0000
sth %r0, 0x02(%r4)
cmpwi %r5, 0
beq skip_cb
mtctr %r5
mr %r4, %r3
li %r3, 0x20
bctrl
skip_cb:
li %r3, 1
lwz %r0, 8(%sp)
mtlr %r0
addi %sp, %sp, 0x10
blr

47
asm/DVDSeekAbsAsyncPrio.S Normal file
View File

@ -0,0 +1,47 @@
#include <asm.h>
# issue read command
#
# r3 dvdstruct
# r4 off
# r5 cb
# r6 prio
DVDSeekAbsAsyncPrio:
stwu %sp, -0x10(%sp)
mflr %r0
stw %r0, 8(%sp)
#update dvdstruct
li %r0, 0
stw %r0, 0x00(%r3)
stw %r0, 0x04(%r3)
stw %r0, 0x1C(%r3)
li %r0, 2
stw %r0, 0x08(%r3)
li %r0, 0
stw %r0, 0x0C(%r3)
#off
stw %r4, 0x10(%r3)
#cb
stw %r5, 0x28(%r3)
cmpwi %r5, 0
beq skip_cb
mtctr %r5
mr %r4, %r3
li %r3, 0
bctrl
skip_cb:
li %r3, 1
lwz %r0, 8(%sp)
mtlr %r0
addi %sp, %sp, 0x10
blr

9
asm/__CARDSync.S Normal file
View File

@ -0,0 +1,9 @@
#include <asm.h>
#
# r3 *Async result
__CARDSync:
mr %r3, %r4
blr

4
asm/make.cmd Normal file
View File

@ -0,0 +1,4 @@
@echo off
for /R %%i IN (*.S) DO E:\devkitPro\devkitPPC\bin\powerpc-eabi-as.exe %%i -o %%~ni.elf
for /R %%i IN (*.S) DO E:\devkitPro\devkitPPC\bin\powerpc-eabi-strip.exe -s %%~ni.elf -O binary -o %%~ni.bin
for /R %%i in (*.bin) DO "C:\Users\crediar\Documents\Visual Studio 2010\Projects\bin2h\Release\bin2h.exe" %%~ni.bin

11
asm/padipc.S Normal file
View File

@ -0,0 +1,11 @@
#include <asm.h>
PADRead:
lis %r4, 0xCC00
lwz %r0, 0x6404(%r4)
lwz %r4, 0x6408(%r4)
lis %r4, 0xC000
stw %r0, 0x12FC(%r4)
blr

32
bsdtypes.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __BSDTYPES_H__
#define __BSDTYPES_H__
#include "global.h"
#include "errno.h"
typedef u32 u_int;
//typedef u32 u_int32_t;
typedef u16 u_int16_t;
typedef u8 u_int8_t;
typedef u8 u_char;
typedef u32 bus_space_tag_t;
typedef u32 bus_space_handle_t;
struct device {
char dv_xname[255];
void *dummy;
};
#define MIN(a, b) (((a)>(b))?(b):(a))
#define wakeup(...)
#define bzero(mem, size) memset8(mem, 0, size)
#define ISSET(var, mask) (((var) & (mask)) ? 1 : 0)
#define SET(var, mask) ((var) |= (mask))
#endif

2
common.c Normal file
View File

@ -0,0 +1,2 @@
#include "string.h"
#include "global.h"

292
dip.c Normal file
View File

@ -0,0 +1,292 @@
#include "dip.h"
u32 StreamBufferSize= 54*1024;
u32 Streaming = 0;
u32 StreamOffset = 0;
u32 StreamDiscOffset= 0;
s32 StreamSize = 0;
u32 StreamRAMOffset = 0;
u32 StreamTimer = 0;
u32 StreamStopEnd = 0;
u32 GameRun = 0;
u32 DOLMinOff = 0;
u32 DOLMaxOff = 0;
u32 DOLSize = 0;
u32 DOLOffset = 0;
s32 ELFNumberOfSections = 0;
u32 FSTMode = 0;
FIL GameFile;
u32 read;
u32 DiscRead=0;
char *getfilenamebyoffset(u32 offset)
{
u32 fst_offset = read32(0x38) & ~0x80000000;
u32 i;
for (i = fst_offset + 12; i < 0x01800000; i+=12)
{
if (read8(i) == 0 && offset >= read32(i + 4) && offset < read32(i + 4) + read32(i + 8))
{
return (char *)(fst_offset + read32(fst_offset+8)*12 + (read32(i) & 0x00ffffff));
}
}
return (char*)NULL;
}
void DIInit( void )
{
memset32( (void*)DI_BASE, 0xdeadbeef, 0x30 );
memset32( (void*)(DI_SHADOW), 0, 0x30 );
write32( DI_SCONFIG, 0xFF );
write32( DI_SCOVER, 0 );
}
u32 DIUpdateRegisters( void )
{
u32 read,i,j;
static u32 PatchState = 0;
static u32 DOLReadSize= 0;
if( read32(DI_CONTROL) != 0xdeadbeef )
{
write32( DI_SCONTROL, read32(DI_CONTROL) & 3 );
clear32( DI_SSTATUS, 0x14 );
write32( DI_CONTROL, 0xdeadbeef );
if( read32(DI_SCONTROL) & 1 )
{
if( ConfigGetConfig(DML_CFG_ACTIVITY_LED) )
set32( HW_GPIO_OUT, 1<<5 );
if( read32(DI_CMD_0) != 0xdeadbeef )
{
write32( DI_SCMD_0, read32(DI_CMD_0) );
write32( DI_CMD_0, 0xdeadbeef );
}
if( read32(DI_CMD_1) != 0xdeadbeef )
{
write32( DI_SCMD_1, read32(DI_CMD_1) );
write32( DI_CMD_1, 0xdeadbeef );
}
if( read32(DI_CMD_2) != 0xdeadbeef )
{
write32( DI_SCMD_2, read32(DI_CMD_2) );
write32( DI_CMD_2, 0xdeadbeef );
}
if( read32(DI_DMA_ADR) != 0xdeadbeef )
{
write32( DI_SDMA_ADR, read32(DI_DMA_ADR) );
write32( DI_DMA_ADR, 0xdeadbeef );
}
if( read32(DI_DMA_LEN) != 0xdeadbeef )
{
write32( DI_SDMA_LEN, read32(DI_DMA_LEN) );
write32( DI_DMA_LEN, 0xdeadbeef );
}
if( read32(DI_IMM) != 0xdeadbeef )
{
write32( DI_SIMM, read32(DI_IMM) );
write32( DI_IMM, 0xdeadbeef );
}
switch( read32(DI_SCMD_0) >> 24 )
{
case 0xA7:
case 0xA9:
//dbgprintf("DIP:Async!\n");
case 0xA8:
{
u32 Buffer = P2C(read32(DI_SDMA_ADR));
u32 Length = read32(DI_SCMD_2);
u32 Offset = read32(DI_SCMD_1) << 2;
// dbgprintf("DIP:DVDRead%02X( 0x%08x, 0x%08x, 0x%08x )\n", read32(DI_SCMD_0) >> 24, Offset, Length, Buffer|0x80000000 );
// udelay(250);
if( FSTMode )
{
FSTRead( (char*)Buffer, Length, Offset );
} else {
if( GameFile.fptr != Offset )
if( f_lseek( &GameFile, Offset ) != FR_OK )
{
EXIControl(1);
dbgprintf("DIP:Failed to seek to 0x%08x\n", Offset );
while(1);
}
if( f_read( &GameFile, (char*)Buffer, Length, &read ) != FR_OK )
{
EXIControl(1);
dbgprintf("DIP:Failed to read from 0x%08x to 0x%08X\n", Offset, Buffer );
while(1);
}
}
//if( ((read+31)&(~31)) != Length )
//{
// dbgprintf("DIP:DVDLowRead Offset:%08X Size:%08d Dst:%08X\n", Offset, Length, Buffer );
// dbgprintf("DIP:Failed to read %d bytes, only got %d\n", Length, read );
// break;
//}
if( (u32)Buffer == 0x01300000 )
{
DoPatches( (char*)(0x01300000), Length, 0x80000000 );
}
if( PatchState == 0 )
{
if( Length == 0x100 )
{
if( read32( (u32)Buffer ) == 0x100 )
{
//quickly calc the size
DOLSize = sizeof(dolhdr);
dolhdr *dol = (dolhdr*)Buffer;
for( i=0; i < 7; ++i )
DOLSize += dol->sizeText[i];
for( i=0; i < 11; ++i )
DOLSize += dol->sizeData[i];
DOLReadSize = sizeof(dolhdr);
DOLMinOff=0x81800000;
DOLMaxOff=0;
for( i=0; i < 7; ++i )
{
if( dol->addressText[i] == 0 )
continue;
if( DOLMinOff > dol->addressText[i])
DOLMinOff = dol->addressText[i];
if( DOLMaxOff < dol->addressText[i] + dol->sizeText[i] )
DOLMaxOff = dol->addressText[i] + dol->sizeText[i];
}
DOLMinOff -= 0x80000000;
DOLMaxOff -= 0x80000000;
dbgprintf("DIP:DOLSize:%d DOLMinOff:0x%08X DOLMaxOff:0x%08X\n", DOLSize, DOLMinOff, DOLMaxOff );
PatchState = 1;
}
} else if( read32(Buffer) == 0x7F454C46 )
{
if (getfilenamebyoffset(Offset) != NULL)
{
dbgprintf("DIP:The Game is loading %s\n", getfilenamebyoffset(Offset));
} else
{
dbgprintf("DIP:The Game is loading some .elf that is not in the fst...\n");
}
for (i = ((*(u32 *)0x00000038) & ~0x80000000) + 16; i < 0x01800000; i+=12) // Search the fst for the dvd offset of the .elf file
{
if (*(u32 *)i == Offset)
{
DOLSize = *(u32 *)(i+4);
DOLReadSize = Length;
if( DOLReadSize == DOLSize ) // The .elf is read completely already
{
dbgprintf("DIP:The .elf is read completely, file size: %u bytes\n", DOLSize);
DoPatches( (char*)(Buffer), Length, 0x80000000 );
} else // a part of the .elf is read
{
PatchState = 2;
DOLMinOff=Buffer;
DOLMaxOff=Buffer+Length;
if (Length <= 4096) // The .elf header is read
{
ELFNumberOfSections = read16(Buffer+0x2c) -2; // Assume that 2 sections are .bss and .sbss which are not read
dbgprintf("DIP:The .elf header is read(%u bytes), .elf file size: %u bytes, number of sections to load: %u\n", Length, DOLSize, ELFNumberOfSections);
} else // The .elf is read into a buffer
{
ELFNumberOfSections = -1; // Make sure that ELFNumberOfSections == 0 does not become true
dbgprintf("DIP:The .elf is read into a buffer, read progress: %u/%u bytes\n", Length, DOLSize);
}
}
break;
}
}
}
} else if ( PatchState != 0 )
{
DOLReadSize += Length;
if (PatchState == 2)
{
ELFNumberOfSections--;
// DOLMinOff and DOLMaxOff are optimised when loading .dol files
if (DOLMinOff > Buffer)
DOLMinOff = Buffer;
if (DOLMaxOff < Buffer+Length)
DOLMaxOff = Buffer+Length;
if (ELFNumberOfSections < 0)
{
dbgprintf("DIP:.elf read progress: %u/%u bytes\n", DOLReadSize, DOLSize);
} else
{
dbgprintf("DIP:.elf read progress: %u/%u bytes, sections left: %u\n", DOLReadSize, DOLSize, ELFNumberOfSections);
}
}
//dbgprintf("DIP:DOLSize:%d DOLReadSize:%d\n", DOLSize, DOLReadSize );
if( DOLReadSize >= DOLSize || (PatchState == 2 && ELFNumberOfSections == 0))
{
DoPatches( (char*)(DOLMinOff), DOLMaxOff-DOLMinOff, 0x80000000 );
PatchState = 0;
}
}
write32( DI_SDMA_LEN, 0 );
while( read32(DI_SCONTROL) & 1 )
clear32( DI_SCONTROL, 1 );
set32( DI_SSTATUS, 0x3A );
if( (read32(DI_SCMD_0) >> 24) == 0xA7 )
{
write32( 0x0d80000C, (1<<0) | (1<<4) );
write32( HW_PPCIRQFLAG, read32(HW_PPCIRQFLAG) );
write32( HW_ARMIRQFLAG, read32(HW_ARMIRQFLAG) );
set32( 0x0d80000C, (1<<2) );
}
} break;
default:
{
EXIControl(1);
dbgprintf("DIP:Unknown CMD:%08X %08X %08X %08X %08X %08X\n", read32(DI_SCMD_0), read32(DI_SCMD_1), read32(DI_SCMD_2), read32(DI_SIMM), read32(DI_SDMA_ADR), read32(DI_SDMA_LEN) );
while(1);
} break;
}
if( ConfigGetConfig(DML_CFG_ACTIVITY_LED) )
clear32( HW_GPIO_OUT, 1<<5 );
return 1;
} else {
;//dbgprintf("DIP:DI_CONTROL:%08X:%08X\n", read32(DI_CONTROL), read32(DI_CONTROL) );
}
}
return 0;
}

138
dip.h Normal file
View File

@ -0,0 +1,138 @@
#ifndef _DIP_
#define _DIP_
#include "global.h"
#include "string.h"
#include "alloc.h"
#include "ff.h"
#include "vsprintf.h"
#include "HW.h"
#include "dol.h"
#include "Patches.h"
#include "vsprintf.h"
#include "Config.h"
#include "DVD.h"
enum opcodes
{
DVD_IDENTIFY = 0x12,
DVD_READ_DISCID = 0x70,
DVD_LOW_READ = 0x71,
DVD_WAITFORCOVERCLOSE = 0x79,
DVD_READ_PHYSICAL = 0x80,
DVD_READ_COPYRIGHT = 0x81,
DVD_READ_DISCKEY = 0x82,
DVD_GETCOVER = 0x88,
DVD_RESET = 0x8A,
DVD_OPEN_PARTITION = 0x8B,
DVD_CLOSE_PARTITION = 0x8C,
DVD_READ_UNENCRYPTED = 0x8D,
DVD_REPORTKEY = 0xA4,
DVD_LOW_SEEK = 0xAB,
DVD_READ = 0xD0,
DVD_READ_CONFIG = 0xD1,
DVD_READ_BCA = 0xDA,
DVD_GET_ERROR = 0xE0,
DVD_SET_MOTOR = 0xE3,
DVD_SELECT_GAME = 0x23,
DVD_GET_GAMECOUNT = 0x24,
DVD_EJECT_DISC = 0x27,
DVD_INSERT_DISC = 0x28,
DVD_READ_GAMEINFO = 0x30,
};
enum GameRegion
{
JAP=0,
USA,
EUR,
KOR,
ASN,
LTN,
};
#define DI_BASE 0x00002F00
#define DI_STATUS (DI_BASE+0x00)
#define DI_COVER (DI_BASE+0x04)
#define DI_CMD_0 (DI_BASE+0x08)
#define DI_CMD_1 (DI_BASE+0x0C)
#define DI_CMD_2 (DI_BASE+0x10)
#define DI_DMA_ADR (DI_BASE+0x14)
#define DI_DMA_LEN (DI_BASE+0x18)
#define DI_CONTROL (DI_BASE+0x1C)
#define DI_IMM (DI_BASE+0x20)
#define DI_CONFIG (DI_BASE+0x24)
#define DI_SHADOW (DI_BASE + 0x30)
#define DI_SSTATUS (DI_SHADOW+0x00)
#define DI_SCOVER (DI_SHADOW+0x04)
#define DI_SCMD_0 (DI_SHADOW+0x08)
#define DI_SCMD_1 (DI_SHADOW+0x0C)
#define DI_SCMD_2 (DI_SHADOW+0x10)
#define DI_SDMA_ADR (DI_SHADOW+0x14)
#define DI_SDMA_LEN (DI_SHADOW+0x18)
#define DI_SCONTROL (DI_SHADOW+0x1C)
#define DI_SIMM (DI_SHADOW+0x20)
#define DI_SCONFIG (DI_SHADOW+0x24)
typedef struct
{
union
{
struct
{
u32 Type :8;
u32 NameOffset :24;
};
u32 TypeName;
};
union
{
struct // File Entry
{
u32 FileOffset;
u32 FileLength;
};
struct // Dir Entry
{
u32 ParentOffset;
u32 NextOffset;
};
u32 entry[2];
};
} FEntry;
typedef struct
{
u32 Offset;
u32 Size;
FIL File;
} FileCache;
#define FILECACHE_MAX 1
typedef struct
{
u8 *data;
u32 len;
} vector;
typedef struct
{
u32 TMDSize;
u32 TMDOffset;
u32 CertChainSize;
u32 CertChainOffset;
u32 H3TableOffset;
u32 DataOffset;
u32 DataSize;
} PartitionInfo;
void DIInit( void );
u32 DIUpdateRegisters( void );
#endif

93
diskio.c Normal file
View File

@ -0,0 +1,93 @@
#include "diskio.h"
#include "string.h"
#include "memory.h"
extern u32 IsInit;
DSTATUS disk_initialize( BYTE drv )
{
udelay( 50000 );
tiny_ehci_init();
int ret = -ENODEV;
do {
udelay( 4000 );
ret = ehci_discover();
} while( ret == -ENODEV );
dbgprintf("ehci_discover():%d\n", ret );
s32 r = USBStorage_Init();
u32 s_size;
u32 s_cnt = USBStorage_Get_Capacity(&s_size);
dbgprintf( "DIP: Drive size: %dMB SectorSize:%d\n", s_cnt / 1024 * s_size / 1024, s_size);
return r;
}
DSTATUS disk_status( BYTE drv )
{
(void)drv;
return 0;
}
DRESULT disk_read( BYTE drv, BYTE *buff, DWORD sector, BYTE count )
{
u8 *buffer = (u8*)buff;
//dbgprintf("disk_read( %d, %d, %p, %p)\n", sector, count, buff, buffer );
if( (u32)buff & 0xF0000000 )
{
buffer = (u8*)0x1000;
u32 i=0;
u32 Blocks = 3;
while(1)
{
if( (count-i) < Blocks )
Blocks = (count-i);
USBStorage_Read_Sectors( sector + i, Blocks, buffer );
memcpy( buff + i * 512, buffer, Blocks * 512 );
i+=Blocks;
if( i >= count )
break;
}
} else {
USBStorage_Read_Sectors( sector, count, buffer );
dc_flushrange( buffer, count*512 );
ahb_flush_from( AHB_SDHC );
}
return RES_OK;
}
// Write Sector(s)
DRESULT disk_write( BYTE drv, const BYTE *buff, DWORD sector, BYTE count )
{
u8 *buffer = (u8*)buff;
if( (u32)buff & 0xF0000000 )
{
buffer = (u8*)0x1000;
u32 i;
for( i=0; i < count; ++i )
{
memcpy( buffer, (void*)buff + i * 512, 512 );
USBStorage_Write_Sectors( sector + i, 1, buffer );
}
} else {
ahb_flush_to( AHB_SDHC );
USBStorage_Write_Sectors( sector, count, buffer );
}
return RES_OK;
}

70
diskio.h Normal file
View File

@ -0,0 +1,70 @@
/*-----------------------------------------------------------------------
/ Low level disk interface modlue include file R0.07 (C)ChaN, 2009
/-----------------------------------------------------------------------
/ FatFs module is an open source project to implement FAT file system to small
/ embedded systems. It is opened for education, research and development under
/ license policy of following trems.
/
/ Copyright (C) 2009, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/ commercial use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/
// original source: http://elm-chan.org/fsw/ff/00index_e.html
#ifndef _DISKIO
#define _READONLY 0 /* 1: Read-only mode */
#define _USE_IOCTL 1
#include "integer.h"
#include "string.h"
#include "ehci.h"
#include "alloc.h"
#include "tiny_ehci_glue.h"
#include "dip.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
#if _READONLY == 0
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
#if _USE_IOCTL == 1
DRESULT disk_ioctl (BYTE, BYTE, void*);
#endif
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
#if _USE_IOCTL == 1
/* Command code for disk_ioctl() */
#define CTRL_SYNC 0 /* Mandatory for write functions */
#endif
#define _DISKIO
#endif

16
dol.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _DOL_
#define _DOL_
typedef struct {
unsigned int offsetText[7];
unsigned int offsetData[11];
unsigned int addressText[7];
unsigned int addressData[11];
unsigned int sizeText[7];
unsigned int sizeData[11];
unsigned int addressBSS;
unsigned int sizeBSS;
unsigned int entrypoint;
} dolhdr;
#endif

85
ehci-mem.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Original Copyright (c) 2001 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* this file is part of ehci.c */
static inline void ehci_qtd_init(struct ehci_qtd *qtd
)
{
dma_addr_t dma = ehci_virt_to_dma(qtd);
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_token = (QTD_STS_HALT);
qtd->hw_next = EHCI_LIST_END();
qtd->hw_alt_next = EHCI_LIST_END();
}
static inline struct ehci_qtd * ehci_qtd_alloc(void)
{
struct ehci_qtd *qtd ;
//debug_printf("ehci_qtd used=%x\n",ehci->qtd_used);
BUG_ON(ehci->qtd_used>=EHCI_MAX_QTD);
qtd = ehci->qtds[ehci->qtd_used++];
ehci_qtd_init(qtd);
return qtd;
}
int ehci_mem_init (void)
{
int i;
u32 ptr = 0x17FF000;
// ehci->periodic = ehci_maligned(DEFAULT_I_TDPS * sizeof(__le32),32,4096);
ehci->periodic = (u32*)ptr;
ehci->periodic_dma = ehci_virt_to_dma(ehci->periodic);
for (i = 0; i < DEFAULT_I_TDPS; i++)
ehci->periodic[i] = EHCI_LIST_END();
ehci_writel(ehci->periodic_dma, &ehci->regs->frame_list);
for(i=0;i<EHCI_MAX_QTD;i++)
{
// ehci->qtds[i] = ehci_maligned(sizeof(struct ehci_qtd),32,4096);
ptr -= sizeof(struct ehci_qtd);
ehci->qtds[i] = (struct ehci_qtd*)(ptr);
}
ehci->qtd_used = 0;
// ehci->asyncqh = ehci_maligned(sizeof(struct ehci_qh),32,4096);
ptr -= sizeof(struct ehci_qh);
ehci->asyncqh = (struct ehci_qh*)ptr;
ehci->asyncqh->ehci = ehci;
ehci->asyncqh->qh_dma = ehci_virt_to_dma(ehci->asyncqh);
ehci->asyncqh->qtd_head = NULL;
// ehci->async = ehci_maligned(sizeof(struct ehci_qh),32,4096);
ptr -= sizeof(struct ehci_qh);
ehci->async = (struct ehci_qh*)ptr;
ehci->async->ehci = ehci;
ehci->async->qh_dma = ehci_virt_to_dma(ehci->async);
ehci->async->qtd_head = NULL;
return 0;
}

811
ehci.c Normal file
View File

@ -0,0 +1,811 @@
/* simplest usb-ehci driver which features:
control and bulk transfers only
only one transfer pending
driver is synchronous (waiting for the end of the transfer)
endianess independant
no uncached memory allocation needed
this driver is originally based on the GPL linux ehci-hcd driver
* Original Copyright (c) 2001 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* magic numbers that can affect system performance */
u32 IsInit = 0;
#undef DEBUG
#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
#define EHCI_TUNE_RL_TT 0
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
extern int verbose;
static void
dbg_qtd (const char *label, struct ehci_qtd *qtd)
{
ehci_dbg( "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
hc32_to_cpup( &qtd->hw_next),
hc32_to_cpup( &qtd->hw_alt_next),
hc32_to_cpup( &qtd->hw_token),
hc32_to_cpup( &qtd->hw_buf [0]));
if (qtd->hw_buf [1])
ehci_dbg( " p1=%08x p2=%08x p3=%08x p4=%08x\n",
hc32_to_cpup( &qtd->hw_buf[1]),
hc32_to_cpup( &qtd->hw_buf[2]),
hc32_to_cpup( &qtd->hw_buf[3]),
hc32_to_cpup( &qtd->hw_buf[4]));
}
static void
dbg_qh (const char *label, struct ehci_qh *qh)
{
ehci_dbg ( "%s qh %p n%08x info %x %x qtd %x\n", label,
qh,
hc32_to_cpu(qh->hw_next),
hc32_to_cpu(qh->hw_info1),
hc32_to_cpu(qh->hw_info2),
hc32_to_cpu(qh->hw_current));
dbg_qtd ("overlay", (struct ehci_qtd *) &qh->hw_qtd_next);
}
static void
dbg_command (void)
{
#ifdef DEBUG
u32 command=ehci_readl( &ehci->regs->command);
u32 async=ehci_readl( &ehci->regs->async_next);
ehci_dbg ("async_next: %08x\n",async);
ehci_dbg (
"command %06x %s=%d ithresh=%d%s%s%s%s %s %s\n",
command,
(command & CMD_PARK) ? "park" : "(park)",
CMD_PARK_CNT (command),
(command >> 16) & 0x3f,
(command & CMD_LRESET) ? " LReset" : "",
(command & CMD_IAAD) ? " IAAD" : "",
(command & CMD_ASE) ? " Async" : "",
(command & CMD_PSE) ? " Periodic" : "",
(command & CMD_RESET) ? " Reset" : "",
(command & CMD_RUN) ? "RUN" : "HALT"
);
#endif
}
static void
dbg_status (void)
{
#ifdef DEBUG
u32 status=ehci_readl( &ehci->regs->status);
ehci_dbg (
"status %04x%s%s%s%s%s%s%s%s%s%s\n",
status,
(status & STS_ASS) ? " Async" : "",
(status & STS_PSS) ? " Periodic" : "",
(status & STS_RECL) ? " Recl" : "",
(status & STS_HALT) ? " Halt" : "",
(status & STS_IAA) ? " IAA" : "",
(status & STS_FATAL) ? " FATAL" : "",
(status & STS_FLR) ? " FLR" : "",
(status & STS_PCD) ? " PCD" : "",
(status & STS_ERR) ? " ERR" : "",
(status & STS_INT) ? " INT" : ""
);
#endif
}
void debug_qtds(void)
{
struct ehci_qh *qh = ehci->async;
struct ehci_qtd *qtd;
dbg_qh ("qh",qh);
dbg_command ();
dbg_status ();
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
{
ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
dbg_qtd("qtd",qtd);
ehci_dma_map_bidir(qtd,sizeof(struct ehci_qtd));
}
}
void dump_qh(struct ehci_qh *qh)
{
struct ehci_qtd *qtd;
dbg_command ();
dbg_status ();
ehci_dma_unmap_bidir(qh->qh_dma,sizeof(struct ehci_qh));
dbg_qh("qh",qh);
print_hex_dump_bytes("qh:",DUMP_PREFIX_OFFSET,(void*)qh,12*4);
for(qtd = qh->qtd_head; qtd; qtd = qtd->next){
u32 *buf;
ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
dbg_qtd("qtd",qtd);
print_hex_dump_bytes("qtd:",DUMP_PREFIX_OFFSET,(void*)qtd,8*4);
buf = (u32*)hc32_to_cpu(qtd->hw_buf[0]);
if(buf)
print_hex_dump_bytes("qtd buf:",DUMP_PREFIX_OFFSET,(void*)(buf),8*4);
}
}
/*-------------------------------------------------------------------------*/
/*
* handshake - spin reading hc until handshake completes or fails
* @ptr: address of hc register to be read
* @mask: bits to look at in result of read
* @done: value of those bits when handshake succeeds
* @usec: timeout in microseconds
*
* Returns negative errno, or zero on success
*
* Success happens when the "mask" bits have the specified value (hardware
* handshake done). There are two failure modes: "usec" have passed (major
* hardware flakeout), or the register reads as all-ones (hardware removed).
*
* That last failure should_only happen in cases like physical cardbus eject
* before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it.
*/
static int handshake (void __iomem *ptr,
u32 mask, u32 done, int usec)
{
u32 result;
do {
result = ehci_readl( ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
result &= mask;
if (result == done)
return 0;
udelay (1);
usec--;
} while (usec > 0);
ehci_dbg("\nhandshake timeout!!\n\n");
dump_qh(ehci->async);
dump_qh(ehci->asyncqh);
//BUG();
return -ETIMEDOUT;
}
#include "ehci-mem.c"
/* one-time init, only for memory state */
static int ehci_init(void)
{
int retval;
if ((retval = ehci_mem_init()) < 0)
return retval;
/*
* dedicate a qh for the async ring head, since we couldn't unlink
* a 'real' qh without stopping the async schedule [4.8]. use it
* as the 'reclamation list head' too.
* its dummy is used in hw_alt_next of many tds, to prevent the qh
* from automatically advancing to the next td after short reads.
*/
ehci->async->hw_next = QH_NEXT( ehci->async->qh_dma);
ehci->async->hw_info1 = cpu_to_hc32( QH_HEAD);
ehci->async->hw_token = cpu_to_hc32( QTD_STS_HALT);
ehci->async->hw_qtd_next = EHCI_LIST_END();
ehci->async->hw_alt_next = EHCI_LIST_END();//QTD_NEXT( ehci->async->dummy->qtd_dma);
ehci->ctrl_buffer = USB_Alloc(sizeof(usbctrlrequest));
ehci->command = 0;
ehci_writel( 0x00800002, &ehci->regs->command);
ehci_writel( ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel( ehci->async->qh_dma, &ehci->regs->async_next);
ehci_writel( 0x00010009, &ehci->regs->command);
ehci_writel( 1, &ehci->regs->configured_flag);
ehci_writel( 0x00010029, &ehci->regs->command);
return 0;
}
/* fill a qtd, returning how much of the buffer we were able to queue up */
static int qtd_fill( struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token, int maxpacket)
{
int i, count;
u64 addr = buf;
//ehci_dbg("fill qtd with dma %X len %X\n",buf,len);
/* one buffer entry per 4K ... first might be short or unaligned */
qtd->hw_buf[0] = cpu_to_hc32( (u32)addr);
qtd->hw_buf_hi[0] = 0;
count = 0x1000 - (buf & 0x0fff); /* rest of that page */
if (likely (len < count)) /* ... iff needed */
count = len;
else {
buf += 0x1000;
buf &= ~0x0fff;
/* per-qtd limit: from 16K to 20K (best alignment) */
for (i = 1; count < len && i < 5; i++) {
addr = buf;
qtd->hw_buf[i] = cpu_to_hc32( (u32)addr);
qtd->hw_buf_hi[i] = cpu_to_hc32(
(u32)(addr >> 32));
buf += 0x1000;
if ((count + 0x1000) < len)
count += 0x1000;
else
count = len;
}
/* short packets may only terminate transfers */
if (count != len)
count -= (count % maxpacket);
}
qtd->hw_token = cpu_to_hc32( (count << 16) | token);
qtd->length = count;
return count;
}
// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
// ... and packet size, for any kind of endpoint descriptor
#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
/*
* reverse of qh_urb_transaction: free a list of TDs.
* also count the actual transfer length.
*
*/
static void qh_end_transfer (void)
{
struct ehci_qtd *qtd;
struct ehci_qh *qh = ehci->asyncqh;
u32 token;
int error = 0;
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
{
token = hc32_to_cpu( qtd->hw_token);
if (likely (QTD_PID (token) != 2))
qtd->urb->actual_length += qtd->length - QTD_LENGTH (token);
if (!(qtd->length ==0 && ((token & 0xff)==QTD_STS_HALT)) && (token & QTD_STS_HALT))
{
ehci_dbg("\nqtd error!:");
if (token & QTD_STS_BABBLE)
{
/* FIXME "must" disable babbling device's port too */
ehci_dbg(" BABBLE");
}
if (token & QTD_STS_MMF)
{
/* fs/ls interrupt xfer missed the complete-split */
ehci_dbg(" missed micro frame");
}
if (token & QTD_STS_DBE)
{
ehci_dbg(" databuffer error");
}
if (token & QTD_STS_XACT)
{
ehci_dbg(" wrong ack");
}
if (QTD_CERR (token)==0)
ehci_dbg(" toomany errors");
ehci_dbg("\n");
error = -1;
}
}
if(error)
{
dump_qh(ehci->asyncqh);
qtd->urb->actual_length = error;
}
ehci->qtd_used = 0;
}
/*
* create a list of filled qtds for this URB; won't link into qh.
*/
struct ehci_qtd *qh_urb_transaction (
struct ehci_urb *urb
) {
struct ehci_qtd *qtd, *qtd_prev;
struct ehci_qtd *head;
dma_addr_t buf;
int len, maxpacket;
int is_input;
u32 token;
/*
* URBs map to sequences of QTDs: one logical transaction
*/
head = qtd = ehci_qtd_alloc ();
qtd->urb = urb;
urb->actual_length = 0;
token = QTD_STS_ACTIVE;
token |= (EHCI_TUNE_CERR << 10);
/* for split transactions, SplitXState initialized to zero */
len = urb->transfer_buffer_length;
is_input = urb->input;
if (urb->ep==0) {/* is control */
/* SETUP pid */
qtd_fill( qtd, urb->setup_dma, sizeof (usbctrlrequest), token | (2 /* "setup" */ << 8), 8);
/* ... and always at least one more pid */
token ^= QTD_TOGGLE;
qtd_prev = qtd;
qtd = ehci_qtd_alloc ();
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
qtd_prev->next = qtd;
/* for zero length DATA stages, STATUS is always IN */
if (len == 0)
token |= (1 /* "in" */ << 8);
}
/*
* data transfer stage: buffer setup
*/
buf = urb->transfer_dma;
if (is_input)
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
maxpacket = max_packet(urb->maxpacket);
/*
* buffer gets wrapped in one or more qtds;
* last one may be "short" (including zero len)
* and may serve as a control status ack
*/
for (;;) {
int this_qtd_len;
this_qtd_len = qtd_fill( qtd, buf, len, token, maxpacket);
len -= this_qtd_len;
buf += this_qtd_len;
/*
* short reads advance to a "magic" dummy instead of the next
* qtd ... that forces the queue to stop, for manual cleanup.
* (this will usually be overridden later.)
*/
if (is_input)
qtd->hw_alt_next = ehci->asyncqh->hw_alt_next;
/* qh makes control packets use qtd toggle; maybe switch it */
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
token ^= QTD_TOGGLE;
if (likely (len <= 0))
break;
qtd_prev = qtd;
qtd = ehci_qtd_alloc ();
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
qtd_prev->next = qtd;
}
qtd->hw_alt_next = EHCI_LIST_END();
/*
* control requests may need a terminating data "status" ack;
* bulk ones may need a terminating short packet (zero length).
*/
if (likely (urb->transfer_buffer_length != 0)) {
int one_more = 0;
if (urb->ep==0) {
one_more = 1;
token ^= 0x0100; /* "in" <--> "out" */
token |= QTD_TOGGLE; /* force DATA1 */
} else if(!(urb->transfer_buffer_length % maxpacket)) {
//one_more = 1;
}
if (one_more) {
qtd_prev = qtd;
qtd = ehci_qtd_alloc ();
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT( qtd->qtd_dma);
qtd_prev->next = qtd;
/* never any data in such packets */
qtd_fill( qtd, 0, 0, token, 0);
}
}
/* by default, enable interrupt on urb completion */
qtd->hw_token |= cpu_to_hc32( QTD_IOC);
return head;
}
int ehci_do_urb ( struct ehci_device *dev, struct ehci_urb *urb)
{
struct ehci_qh *qh;
struct ehci_qtd *qtd;
u32 info1 = 0, info2 = 0;
int is_input;
int maxp = 0;
int retval;
//ehci_dbg ("do urb %X %X ep %X\n",urb->setup_buffer,urb->transfer_buffer,urb->ep);
if(urb->ep==0) //control message
urb->setup_dma = ehci_dma_map_to(urb->setup_buffer,sizeof (usbctrlrequest));
if( urb->transfer_buffer_length )
{
if(urb->input)
urb->transfer_dma = ehci_dma_map_to( urb->transfer_buffer, urb->transfer_buffer_length );
else
urb->transfer_dma = ehci_dma_map_from( urb->transfer_buffer, urb->transfer_buffer_length );
}
qh = ehci->asyncqh;
memset(qh,0,12*4);
qtd = qh_urb_transaction( urb );
qh->qtd_head = qtd;
info1 |= ((urb->ep)&0xf)<<8;
info1 |= dev->id;
is_input = urb->input;
maxp = urb->maxpacket;
info1 |= (2 << 12); /* EPS "high" */
if(urb->ep==0)// control
{
info1 |= (EHCI_TUNE_RL_HS << 28);
info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else {//bulk
info1 |= (EHCI_TUNE_RL_HS << 28);
/* The USB spec says that high speed bulk endpoints
* always use 512 byte maxpacket. But some device
* vendors decided to ignore that, and MSFT is happy
* to help them do so. So now people expect to use
* such nonconformant devices with Linux too; sigh.
*/
info1 |= max_packet(maxp) << 16;
info2 |= (EHCI_TUNE_MULT_HS << 30);
}
//ehci_dbg("HW info: %08X\n",info1);
qh->hw_info1 = cpu_to_hc32( info1);
qh->hw_info2 = cpu_to_hc32( info2);
qh->hw_next = QH_NEXT( qh->qh_dma );
qh->hw_qtd_next = QTD_NEXT( qtd->qtd_dma );
qh->hw_alt_next = EHCI_LIST_END();
if( urb->ep != 0 )
{
if( get_toggle( dev, urb->ep ) )
qh->hw_token |= cpu_to_hc32(QTD_TOGGLE);
else
qh->hw_token &= ~cpu_to_hc32(QTD_TOGGLE);
//ehci_dbg("toggle for ep %x: %d %x\n", urb->ep, get_toggle(dev,urb->ep), qh->hw_token );
}
qh->hw_token &= cpu_to_hc32( QTD_TOGGLE | QTD_STS_PING);
qh->hw_next = QH_NEXT(ehci->async->qh_dma);
ehci_dma_map_bidir(qh,sizeof(struct ehci_qh));
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
ehci_dma_map_bidir(qtd,sizeof(struct ehci_qtd));
// start (link qh)
ehci->async->hw_next = QH_NEXT(qh->qh_dma);
ehci_dma_map_bidir(ehci->async,sizeof(struct ehci_qh));
retval = handshake(&ehci->regs->status,STS_INT,STS_INT,1000*1000);
//print_hex_dump_bytes ("qh mem",0,(void*)qh,17*4);
//retval = poll_transfer_end(1000*1000);
ehci_dma_unmap_bidir(ehci->async->qh_dma,sizeof(struct ehci_qh));
ehci_dma_unmap_bidir(qh->qh_dma,sizeof(struct ehci_qh));
for(qtd = qh->qtd_head; qtd; qtd = qtd->next)
ehci_dma_unmap_bidir(qtd->qtd_dma,sizeof(struct ehci_qtd));
// stop (unlink qh)
ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma);
ehci_dma_map_bidir(ehci->async,sizeof(struct ehci_qh));
ehci_dma_unmap_bidir(ehci->async->qh_dma,sizeof(struct ehci_qh));
// ack
ehci_writel( STS_RECL|STS_IAA|STS_INT, &ehci->regs->status);
if(urb->ep!=0)
{
set_toggle(dev,urb->ep,(qh->hw_token & cpu_to_hc32(QTD_TOGGLE))?1:0);
//ehci_dbg("toggle for ep %x: %d %d %x %X\n",urb->ep,get_toggle(dev,urb->ep),(qh->hw_token & cpu_to_hc32(QTD_TOGGLE)),qh->hw_token,dev->toggles);
}
if( retval >= 0 )
// wait hc really stopped
retval = handshake(&ehci->regs->async_next,~0,ehci->async->qh_dma,1*1000);
//release memory, and actualise urb->actual_length
qh_end_transfer();
if(urb->transfer_buffer_length)
{
if(urb->input)
ehci_dma_unmap_to(urb->transfer_dma,urb->transfer_buffer_length);
else
ehci_dma_unmap_from(urb->transfer_dma,urb->transfer_buffer_length);
}
if( urb->ep == 0 ) //control message
ehci_dma_unmap_to(urb->setup_dma,sizeof (usbctrlrequest));
if(retval==0)
{
return urb->actual_length;
}
ehci_dbg ( "un successfull urb %d!!\n", retval);
return retval;
}
s32 ehci_control_message(struct ehci_device *dev,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *buf)
{
struct ehci_urb urb;
int ret;
usbctrlrequest *req = (void*)0x17C0;
if( verbose )
ehci_dbg("control msg: rt%02X r%02X v%04X i%04X s%04x %p\n", bmRequestType, bmRequest, wValue, wIndex, wLength, buf );
u32 *_req = (u32*)req;
_req[0] = (bmRequestType<<24) | (bmRequest<<16) | swab16(wValue);
_req[1] = (swab16(wIndex) << 16) | swab16(wLength);
urb.setup_buffer = req;
urb.ep = 0;
urb.input = (bmRequestType&USB_CTRLTYPE_DIR_DEVICE2HOST)!=0;
urb.maxpacket = 64;
urb.transfer_buffer_length = wLength;
if( urb.transfer_buffer_length )
{
if( ((u32)buf >> 28 ) == 0xF )
{
urb.transfer_buffer = USB_Alloc( wLength );
dbgprintf("memcpy(%p,%p,%u)\n", urb.transfer_buffer, buf, wLength );
memcpy( urb.transfer_buffer, buf, wLength );
ret = ehci_do_urb( dev, &urb );
memcpy( buf, urb.transfer_buffer, wLength );
USB_Free( urb.transfer_buffer );
} else {
urb.transfer_buffer = buf;
ret = ehci_do_urb( dev, &urb );
}
//hexdump( buf, wLength > 0x20 ? 0x20 : wLength );
} else {
urb.transfer_buffer = NULL;
ret = ehci_do_urb( dev, &urb );
}
return ret;
}
s32 ehci_bulk_message(struct ehci_device *dev,u8 bEndpoint,u16 wLength,void *rpData)
{
struct ehci_urb urb;
s32 ret;
urb.setup_buffer = NULL;
urb.ep = bEndpoint;
urb.input = (bEndpoint&0x80)!=0;
urb.maxpacket = 512;
urb.transfer_buffer_length = wLength;
urb.transfer_buffer = rpData;
if (verbose)
ehci_dbg ( "bulk msg: ep:%02X size:%02X addr:%04X\n", bEndpoint, wLength, urb.transfer_buffer );
// hexdump( urb.transfer_buffer, urb.transfer_buffer_length );
if( ((u32)rpData >> 28) == 0xF )
{
memcpy( (void*)0x1800, rpData, wLength );
urb.transfer_buffer = (u8*)0x1800;
ret = ehci_do_urb( dev, &urb );
memcpy( rpData, (void*)0x1800, wLength );
} else {
ret = ehci_do_urb( dev, &urb );
}
// hexdump( urb.transfer_buffer, urb.transfer_buffer_length );
if (verbose)
ehci_dbg ( "==>%d\n", ret);
return ret;
}
int ehci_reset_port(int port)
{
u32 __iomem *status_reg = &ehci->regs->port_status[port];
struct ehci_device *dev = &ehci->devices[port];
u32 status = ehci_readl(status_reg);
int retval = 0;
dev->id = 0;
if ((PORT_OWNER&status) || !(PORT_CONNECT&status))
{
ehci_writel( PORT_OWNER, status_reg);
//ehci_dbg ( "port %d had no usb2 device connected at startup %X \n", port,ehci_readl(status_reg));
return -ENODEV;// no USB2 device connected
}
ehci_dbg ( "port %d has usb2 device connected! reset it...\n", port);
ehci_writel( 0x1803,status_reg);
while ((ehci_readl(status_reg) & 0x1801) != 0x1801)
{
ehci_dbg ( "Waiting for port %d to settle...(%04x)\n", port, ehci_readl(status_reg));
ehci_writel( 0x1803,status_reg);
msleep(500);
}
ehci_writel( 0x1903,status_reg);
//ehci_writel( PORT_OWNER|PORT_POWER|PORT_RESET,status_reg);
msleep(50);// wait 50ms for the reset sequence
ehci_writel( 0x1001,status_reg);
retval = handshake( status_reg, PORT_RESET, 0, 2000);
if (retval != 0)
{
ehci_dbg ( "port %d reset error %d\n", port, retval);
return retval;
}
ehci_dbg ( "port %d reseted status:%04x...\n", port,ehci_readl(status_reg));
msleep(50);
// now the device has the default device id
retval = ehci_control_message( dev, USB_CTRLTYPE_DIR_DEVICE2HOST, USB_REQ_GETDESCRIPTOR, USB_DT_DEVICE<<8, 0, sizeof(dev->desc), &dev->desc );
if (retval < 0)
{
ehci_dbg("unable to get device desc...\n");
return retval;
}
retval = ehci_control_message( dev, USB_CTRLTYPE_DIR_HOST2DEVICE, USB_REQ_SETADDRESS,port+1,0,0,0);
if (retval < 0)
{
ehci_dbg("unable to set device addr...\n");
return retval;
}
dev->toggles = 0;
dev->id = port+1;
ehci_dbg ( "device %d: %X %X...\n", dev->id,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
return retval;
}
int ehci_reset_device(struct ehci_device *dev)
{
return ehci_reset_port(dev->port);
}
#include "usbstorage.h"
int ehci_discover(void)
{
int i;
int ret = 0 ;
// precondition: the ehci should be halted
for(i = 0;i<ehci->num_port; i++)
{
struct ehci_device *dev = &ehci->devices[i];
dev->port = i;
ret = ehci_reset_port(i);
if( ret != -ENODEV )
break;
}
return ret;
}
/* wii: quickly release non ehci or not connected ports,
as we can't kick OHCI drivers laters if we discover a device for them.
*/
int ehci_release_ports(void)
{
int i;
u32 __iomem *status_reg = &ehci->regs->port_status[2];
while(ehci_readl(&ehci->regs->port_status[2]) == 0x1000);// wait port 2 to init
msleep(1);// wait another msec..
for(i = 0;i<ehci->num_port; i++){
status_reg = &ehci->regs->port_status[i];
u32 status = ehci_readl(status_reg);
if (i==2 || !(PORT_CONNECT&status) || PORT_USB11(status))
ehci_writel( PORT_OWNER,status_reg); // release port.
}
return 0;
}
int ehci_open_device(int vid,int pid,int fd)
{
int i;
for(i=0;i<ehci->num_port;i++)
{
ehci_dbg("try device: %d\n",i);
if(ehci->devices[i].fd == 0 &&
le16_to_cpu(ehci->devices[i].desc.idVendor) == vid &&
le16_to_cpu(ehci->devices[i].desc.idProduct) == pid)
{
ehci_dbg("found device: %x %x\n",vid,pid);
ehci->devices[i].fd = fd;
return fd;
}
}
return -6;
}
int ehci_close_device(struct ehci_device *dev)
{
if (dev)
dev->fd = 0;
return 0;
}
void * ehci_fd_to_dev(int fd)
{
int i;
for(i=0;i<ehci->num_port;i++)
{
struct ehci_device *dev = &ehci->devices[i];
ehci_dbg ( "device %d:fd:%d %X %X...\n", dev->id,dev->fd,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
if(dev->fd == fd){
return dev;
}
}
ehci_dbg("unkown fd! %d\n",fd);
return 0;
}
#define g_ehci #error
int ehci_get_device_list(u8 maxdev,u8 b0,u8*num,u16*buf)
{
int i,j = 0;
for(i=0;i<ehci->num_port && j<maxdev ;i++)
{
struct ehci_device *dev = &ehci->devices[i];
if(dev->id != 0){
ehci_dbg ( "device %d: %X %X...\n", dev->id,le16_to_cpu(dev->desc.idVendor),le16_to_cpu(dev->desc.idProduct));
buf[j*4] = 0;
buf[j*4+1] = 0;
buf[j*4+2] = le16_to_cpu(dev->desc.idVendor);
buf[j*4+3] = le16_to_cpu(dev->desc.idProduct);
j++;
}
}
ehci_dbg("found %d devices\n",j);
*num = j;
return 0;
}
#include "usb.c"
#include "usbstorage.c"

282
ehci.h Normal file
View File

@ -0,0 +1,282 @@
/*
* Copyright (c) 2009 Kwiirk
* Original Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ehci_types.h"
#ifndef __LINUX_EHCI_HCD_H
#define __LINUX_EHCI_HCD_H
/* definitions used for the EHCI driver */
/*
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
* the host controller implementation.
*
* To facilitate the strongest possible byte-order checking from "sparse"
* and so on, we use __leXX unless that's not practical.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
typedef __u32 __bitwise __hc32;
typedef __u16 __bitwise __hc16;
#else
#define __hc32 __le32
#define __hc16 __le16
#endif
#define EHCI_MAX_ROOT_PORTS 4 /* see HCS_N_PORTS */
#define EHCI_MAX_QTD 8
#include "usb.h"
struct ehci_device{
usb_devdesc desc;
int id;
int port;
int fd;
u32 toggles;
};
#define ep_bit(ep) (((ep)&0xf)+(((ep)>>7)?16:0))
#define get_toggle(dev,ep) (((dev)->toggles>>ep_bit(ep))&1)
#define set_toggle(dev,ep,v) (dev)->toggles = ((dev)->toggles &(~(1<<ep_bit(ep)))) | ((v)<<ep_bit(ep))
struct ehci_urb{
void* setup_buffer;
dma_addr_t setup_dma;
void* transfer_buffer;
dma_addr_t transfer_dma;
u32 transfer_buffer_length;
u32 actual_length;
u8 ep;
u8 input;
u32 maxpacket;
};
struct ehci_hcd { /* one per controller */
/* glue to PCI and HCD framework */
void __iomem *_regs;
struct ehci_caps __iomem *caps;
struct ehci_regs __iomem *regs;
struct ehci_dbg_port __iomem *debug;
void *device;
__u32 hcs_params; /* cached register copy */
/* async schedule support */
struct ehci_qh *async; // the head never gets a qtd inside.
struct ehci_qh *asyncqh;
struct ehci_qtd *qtds[EHCI_MAX_QTD];
int qtd_used;
unsigned long next_statechange;
u32 command;
/* HW need periodic table initialised even if we dont use it @todo:is it really true? */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
__hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
u8 num_port;
struct ehci_device devices[EHCI_MAX_ROOT_PORTS]; /* the attached device list per port */
void *ctrl_buffer; /* pre allocated buffer for control messages */
};
/*-------------------------------------------------------------------------*/
#include "ehci_defs.h"
/*-------------------------------------------------------------------------*/
#define QTD_NEXT( dma) cpu_to_hc32( (u32)dma)
/*
* EHCI Specification 0.95 Section 3.5
* QTD: describe data transfer components (buffer, direction, ...)
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
*
* These are associated only with "QH" (Queue Head) structures,
* used with control, bulk, and interrupt transfers.
*/
struct ehci_qtd {
/* first part defined by EHCI spec */
__hc32 hw_next; /* see EHCI 3.5.1 */
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
__hc32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
#define QTD_PID(tok) (((tok)>>8) & 0x3)
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
#define QTD_STS_HALT (1 << 6) /* halted on error */
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
#define QTD_STS_STS (1 << 1) /* split transaction state */
#define QTD_STS_PING (1 << 0) /* issue PING? */
#define ACTIVE_BIT(ehci) cpu_to_hc32( QTD_STS_ACTIVE)
#define HALT_BIT(ehci) cpu_to_hc32( QTD_STS_HALT)
#define STATUS_BIT(ehci) cpu_to_hc32( QTD_STS_STS)
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
__hc32 hw_buf_hi [5]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
struct ehci_qtd *next; /* sw qtd list */
struct ehci_urb *urb; /* qtd's urb */
size_t length; /* length of buffer */
} __attribute__ ((aligned (32)));
/* mask NakCnt+T in qh->hw_alt_next */
#define QTD_MASK(ehci) cpu_to_hc32 ( ~0x1f)
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
/*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */
#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_hc32( 3 << 1))
/*
* Now the following defines are not converted using the
* __constant_cpu_to_le32() macro anymore, since we have to support
* "dynamic" switching between be and le support, so that the driver
* can be used on one system with SoC EHCI controller using big-endian
* descriptors as well as a normal little-endian PCI EHCI controller.
*/
/* values for that type tag */
#define Q_TYPE_ITD (0 << 1)
#define Q_TYPE_QH (1 << 1)
#define Q_TYPE_SITD (2 << 1)
#define Q_TYPE_FSTN (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma) (cpu_to_hc32( (((u32)dma)&~0x01f)|Q_TYPE_QH))
/* for periodic/async schedules and qtd lists, mark end of list */
#define EHCI_LIST_END() cpu_to_hc32( 1) /* "null pointer" to hw */
/*
* Entries in periodic shadow table are pointers to one of four kinds
* of data structure. That's dictated by the hardware; a type tag is
* encoded in the low bits of the hardware's periodic schedule. Use
* Q_NEXT_TYPE to get the tag.
*
* For entries in the async schedule, the type tag always says "qh".
*/
union ehci_shadow {
struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
__hc32 *hw_next; /* (all types) */
void *ptr;
};
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.95 Section 3.6
* QH: describes control/bulk/interrupt endpoints
* See Fig 3-7 "Queue Head Structure Layout".
*
* These appear in both the async and (for interrupt) periodic schedules.
*/
struct ehci_qh {
/* first part defined by EHCI spec */
__hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000
__hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
#define QH_HUBADDR 0x007f0000
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__hc32 hw_qtd_next;
__hc32 hw_alt_next;
__hc32 hw_token;
__hc32 hw_buf [5];
__hc32 hw_buf_hi [5];
/* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */
struct ehci_qtd *qtd_head; /* sw qtd list */
struct ehci_hcd *ehci;
#define NO_FRAME ((unsigned short)~0) /* pick new start */
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
/* cpu to ehci */
#define cpu_to_hc32(b) cpu_to_le32(b)
#define hc32_to_cpu(b) le32_to_cpu(b)
#define hc32_to_cpup(b) le32_to_cpu(*(b))
/*-------------------------------------------------------------------------*/
/* os specific functions */
void*ehci_maligned(int size,int alignement,int crossing);
dma_addr_t ehci_virt_to_dma(void *);
dma_addr_t ehci_dma_map_to(void *buf,size_t len);
dma_addr_t ehci_dma_map_from(void *buf,size_t len);
dma_addr_t ehci_dma_map_bidir(void *buf,size_t len);
void ehci_dma_unmap_to(dma_addr_t buf,size_t len);
void ehci_dma_unmap_from(dma_addr_t buf,size_t len);
void ehci_dma_unmap_bidir(dma_addr_t buf,size_t len);
/* extern API */
s32 ehci_control_message(struct ehci_device *dev,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *buf);
s32 ehci_bulk_message(struct ehci_device *dev,u8 bEndpoint,u16 wLength,void *rpData);
int ehci_discover(void);
int ehci_get_device_list(u8 maxdev,u8 b0,u8*num,u16*buf);
extern struct ehci_hcd *ehci; /* @todo put ehci as a static global and remove ehci from APIs.. */
extern int ehci_open_device(int vid,int pid,int fd);
extern int ehci_close_device(struct ehci_device *dev);
extern void * ehci_fd_to_dev(int fd);
extern int ehci_release_ports(void);
/* UMS API */
s32 USBStorage_Init(void);
s32 USBStorage_Get_Capacity(u32*sector_size);
s32 USBStorage_Read_Sectors(u32 sector, u32 numSectors, void *buffer);
s32 USBStorage_Read_Stress(u32 sector, u32 numSectors, void *buffer);
s32 USBStorage_Write_Sectors(u32 sector, u32 numSectors, const void *buffer);
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
/*-------------------------------------------------------------------------*/
#endif /* __LINUX_EHCI_HCD_H */

160
ehci_defs.h Normal file
View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LINUX_USB_EHCI_DEF_H
#define __LINUX_USB_EHCI_DEF_H
/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
/* Section 2.2 Host Controller Capability Registers */
struct ehci_caps {
/* these fields are specified as 8 and 16 bit registers,
* but some hosts can't perform 8 or 16 bit PCI accesses.
*/
u32 hc_capbase;
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
u32 hcs_params; /* HCSPARAMS - offset 0x4 */
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
u8 portroute [8]; /* nibbles for routing - offset 0xC */
} __attribute__ ((packed));
/* Section 2.3 Host Controller Operational Registers */
struct ehci_regs {
/* USBCMD: offset 0x00 */
u32 command;
/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
#define CMD_PARK (1<<11) /* enable "park" on async qh */
#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
#define CMD_ASE (1<<5) /* async schedule enable */
#define CMD_PSE (1<<4) /* periodic schedule enable */
/* 3:2 is periodic frame list size */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
/* USBSTS: offset 0x04 */
u32 status;
#define STS_ASS (1<<15) /* Async Schedule Status */
#define STS_PSS (1<<14) /* Periodic Schedule Status */
#define STS_RECL (1<<13) /* Reclamation */
#define STS_HALT (1<<12) /* Not running (any reason) */
/* some bits reserved */
/* these STS_* flags are also intr_enable bits (USBINTR) */
#define STS_IAA (1<<5) /* Interrupted on async advance */
#define STS_FATAL (1<<4) /* such as some PCI access errors */
#define STS_FLR (1<<3) /* frame list rolled over */
#define STS_PCD (1<<2) /* port change detect */
#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
#define STS_INT (1<<0) /* "normal" completion (short, ...) */
/* USBINTR: offset 0x08 */
u32 intr_enable;
/* FRINDEX: offset 0x0C */
u32 frame_index; /* current microframe number */
/* CTRLDSSEGMENT: offset 0x10 */
u32 segment; /* address bits 63:32 if needed */
/* PERIODICLISTBASE: offset 0x14 */
u32 frame_list; /* points to periodic list */
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
u32 reserved [9];
/* CONFIGFLAG: offset 0x40 */
u32 configured_flag;
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
/* PORTSC: offset 0x44 */
u32 port_status [0]; /* up to N_PORTS */
/* 31:23 reserved */
#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
/* 19:16 for port testing */
#define PORT_LED_OFF (0<<14)
#define PORT_LED_AMBER (1<<14)
#define PORT_LED_GREEN (2<<14)
#define PORT_LED_MASK (3<<14)
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
/* 9 reserved */
#define PORT_RESET (1<<8) /* reset port */
#define PORT_SUSPEND (1<<7) /* suspend port */
#define PORT_RESUME (1<<6) /* resume it */
#define PORT_OCC (1<<5) /* over current change */
#define PORT_OC (1<<4) /* over current active */
#define PORT_PEC (1<<3) /* port enable change */
#define PORT_PE (1<<2) /* port enable */
#define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
} __attribute__ ((packed));
#define USBMODE 0x68 /* USB Device mode */
#define USBMODE_SDIS (1<<3) /* Stream disable */
#define USBMODE_BE (1<<2) /* BE/LE endianness select */
#define USBMODE_CM_HC (3<<0) /* host controller mode */
#define USBMODE_CM_IDLE (0<<0) /* idle state */
/* Appendix C, Debug port ... intended for use with special "debug devices"
* that can help if there's no serial console. (nonstandard enumeration.)
*/
struct ehci_dbg_port {
u32 control;
#define DBGP_OWNER (1<<30)
#define DBGP_ENABLED (1<<28)
#define DBGP_DONE (1<<16)
#define DBGP_INUSE (1<<10)
#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
# define DBGP_ERR_BAD 1
# define DBGP_ERR_SIGNAL 2
#define DBGP_ERROR (1<<6)
#define DBGP_GO (1<<5)
#define DBGP_OUT (1<<4)
#define DBGP_LEN(x) (((x)>>0)&0x0f)
u32 pids;
#define DBGP_PID_GET(x) (((x)>>16)&0xff)
#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
u32 data03;
u32 data47;
u32 address;
#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
} __attribute__ ((packed));
#endif /* __LINUX_USB_EHCI_DEF_H */

55
ehci_types.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef __EHCI_TYPES_H__
#define __EHCI_TYPES_H__
#include "global.h"
/* linux kernel types needed by our code */
#define __iomem
typedef unsigned long uint32_t;
#if 0
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef char s8;
typedef unsigned long long u64;
#endif
#define __u32 u32
#define __le32 u32
#define dma_addr_t u32
#define __GNUG__
typedef u32 spinlock_t;
typedef enum
{
GFP_KERNEL=1
}gfp_t;
struct timer_list
{
int time;
};
enum{
ENODEV =1,
ETIMEDOUT,
EINVAL,
ENOMEM,
};
#define jiffies 0
#define likely(x) (x)
#define unlikely(x) (x)
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#endif

4048
ff.c Normal file

File diff suppressed because it is too large Load Diff

335
ff.h Normal file
View File

@ -0,0 +1,335 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.08b (C)ChaN, 2011
/----------------------------------------------------------------------------/
/ FatFs module is a generic FAT file system module for small embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following trems.
/
/ Copyright (C) 2011, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 8237 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive# */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition# */
typedef struct {
BYTE pd; /* Physical drive# */
BYTE pt; /* Partition # (0-3) */
} PARTITION;
extern const PARTITION VolToPart[]; /* Volume - Physical location resolution table */
#else /* Single partition configuration */
#define LD2PD(vol) (vol) /* Logical drive# is bound to the same physical drive# */
#define LD2PT(vol) 0 /* Always mounts the 1st partition */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 in non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1,2) */
BYTE wflag; /* win[] dirty flag (1:must be written back) */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != 512
WORD ssize; /* Bytes per sector (512,1024,2048,4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
DWORD fsi_sector; /* fsinfo sector (FAT32) */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
DWORD fsize; /* Sectors per FAT */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE pad1;
DWORD fptr; /* File read/write pointer (0 on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0 when fsize==0) */
DWORD clust; /* Current cluster */
DWORD dsect; /* Current data sector */
#if !_FS_READONLY
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
#endif
#if _FS_SHARE
UINT lockid; /* File lock ID (index of file semaphore table) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File data read/write buffer */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
} DIR;
/* File status structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occured in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Acces denied due to prohibited access or directory full */
FR_EXIST, /* (8) Acces denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume on the physical drive */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file shareing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES /* (18) Number of open files > _FS_SHARE */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */
FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
FRESULT f_chdrive (BYTE); /* Change current drive */
FRESULT f_chdir (const TCHAR*); /* Change current directory */
FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
int f_putc (TCHAR, FIL*); /* Put a character to the file */
int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
#ifndef EOF
#define EOF (-1)
#endif
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT); /* Allocate memory block */
void ff_memfree (void*); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
int ff_req_grant (_SYNC_t); /* Lock sync object */
void ff_rel_grant (_SYNC_t); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#define FA__ERROR 0x80
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek function */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

189
ffconf.h Normal file
View File

@ -0,0 +1,189 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.08b (C)ChaN, 2011
/----------------------------------------------------------------------------/
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FFCONF
#define _FFCONF 8237 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function and Buffer Configurations
/----------------------------------------------------------------------------*/
#define _FS_TINY 0 /* 0:Normal or 1:Tiny */
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/ object instead of the sector buffer in the individual file object for file
/ data transfer. This reduces memory consumption 512 bytes each file object. */
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 0 /* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
/ are removed.
/ 2: f_opendir and f_readdir are removed in addition to 1.
/ 3: f_lseek is removed in addition to 2. */
#define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0 /* 0:Disable or 1:Enable */
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
#define _USE_FASTSEEK 1 /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/
#define _CODE_PAGE 437
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
/ 949 - Korean (DBCS, OEM, Windows)
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
/ 1250 - Central Europe (Windows)
/ 1251 - Cyrillic (Windows)
/ 1252 - Latin 1 (Windows)
/ 1253 - Greek (Windows)
/ 1254 - Turkish (Windows)
/ 1255 - Hebrew (Windows)
/ 1256 - Arabic (Windows)
/ 1257 - Baltic (Windows)
/ 1258 - Vietnam (OEM, Windows)
/ 437 - U.S. (OEM)
/ 720 - Arabic (OEM)
/ 737 - Greek (OEM)
/ 775 - Baltic (OEM)
/ 850 - Multilingual Latin 1 (OEM)
/ 858 - Multilingual Latin 1 + Euro (OEM)
/ 852 - Latin 2 (OEM)
/ 855 - Cyrillic (OEM)
/ 866 - Russian (OEM)
/ 857 - Turkish (OEM)
/ 862 - Hebrew (OEM)
/ 874 - Thai (OEM, Windows)
/ 1 - ASCII only (Valid for non LFN cfg.)
*/
#define _USE_LFN 1 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. When enable to use heap, memory control functions
/ ff_memalloc() and ff_memfree() must be added to the project. */
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/ enable LFN feature and set _LFN_UNICODE to 1. */
#define _FS_RPATH 1 /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path. f_chdrive() and f_chdir() are available.
/ 2: f_getcwd() is available in addition to 1.
/
/ Note that output of the f_readdir fnction is affected by this option. */
/*---------------------------------------------------------------------------/
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
/* Maximum sector size to be handled.
/ Always set 512 for memory card and hard disk but a larger value may be
/ required for on-board flash memory, floppy disk and optical disk.
/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
#define _MULTI_PARTITION 0 /* 0:Single partition or 1:Multiple partition */
/* When set to 0, each volume is bound to the same physical drive number and
/ it can mount only first primaly partition. When it is set to 1, each volume
/ is tied to the partitions listed in VolToPart[]. */
#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
/ should be added to the disk_ioctl functio. */
/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/
#define _WORD_ACCESS 0 /* 0 or 1 */
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
/ option defines which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access.
/ 1: Word access. Do not choose this unless following condition is met.
/
/ When the byte order on the memory is big-endian or address miss-aligned word
/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/ If it is not the case, the value can also be set to 1 to improve the
/ performance and code size. */
/* A header file that defines sync object types on the O/S, such as
/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
/
/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
/ 1: Enable reentrancy. Also user provided synchronization handlers,
/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
/ function must be added to the project. */
#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */
/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
defines how many files can be opened simultaneously. */
#endif /* _FFCONFIG */

62
global.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef __GLOBAL_H__
#define __GLOBAL_H__
#define UINT_MAX ((unsigned int)0xffffffff)
#define CARD_DEBUG 1
#define CHEATHOOK 1
//#define DEBUGGER 1
//#define DEBUGGERWAIT 1
//#define ACTIVITYLED 1
//#define CARDMODE 1
//#define CARDDEBUG 1
#define REALNAND 1
#define PADHOOK 1
#define CONFIG_VERSION 0x00000001
#define DM_VERSION 0x00020000
#define DI_SUCCESS 1
#define DI_ERROR 2
#define DI_FATAL 64
//#define DEBUG 0
#define false 0
#define true 1
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef int bool;
typedef unsigned int sec_t;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef volatile unsigned char vu8;
typedef volatile unsigned short vu16;
typedef volatile unsigned int vu32;
typedef volatile unsigned long long vu64;
typedef volatile signed char vs8;
typedef volatile signed short vs16;
typedef volatile signed int vs32;
typedef volatile signed long long vs64;
typedef s32 size_t;
typedef u32 u_int32_t;
typedef s32(*ipccallback)(s32 result,void *usrdata);
#define NULL ((void *)0)
#define ALIGNED(x) __attribute__((aligned(x)))
#endif

180
hollywood.h Normal file
View File

@ -0,0 +1,180 @@
#ifndef __HOLLYWOOD_H__
#define __HOLLYWOOD_H__
/* Hollywood Registers */
#define HW_PPC_REG_BASE 0xd000000
#define HW_REG_BASE 0xd800000
#define IPC_CTRL_Y1 0x01
#define IPC_CTRL_X2 0x02
#define IPC_CTRL_X1 0x04
#define IPC_CTRL_Y2 0x08
#define IPC_CTRL_IX1 0x10
#define IPC_CTRL_IX2 0x20
// Our definitions for this IPC interface
#define IPC_CTRL_OUT IPC_CTRL_Y1
#define IPC_CTRL_IN IPC_CTRL_X1
#define IPC_CTRL_IRQ_IN IPC_CTRL_IX1
// reset both flags (X* for ARM and Y* for PPC)
#define IPC_CTRL_RESET 0x06
// The PPC can only see the first three IPC registers
#define HW_IPC_PPCMSG (HW_REG_BASE + 0x000)
#define HW_IPC_PPCCTRL (HW_REG_BASE + 0x004)
#define HW_IPC_ARMMSG (HW_REG_BASE + 0x008)
#define HW_IPC_ARMCTRL (HW_REG_BASE + 0x00c)
#define HW_TIMER (HW_REG_BASE + 0x010)
#define HW_ALARM (HW_REG_BASE + 0x014)
#define HW_PPCIRQFLAG (HW_REG_BASE + 0x030)
#define HW_PPCIRQMASK (HW_REG_BASE + 0x034)
#define HW_ARMIRQFLAG (HW_REG_BASE + 0x038)
#define HW_ARMIRQMASK (HW_REG_BASE + 0x03c)
#define HW_MEMMIRR (HW_REG_BASE + 0x060)
// something to do with PPCBOOT
// and legacy DI it seems ?!?
#define HW_EXICTRL (HW_REG_BASE + 0x070)
#define EXICTRL_ENABLE_EXI 1
// PPC side of GPIO1 (Starlet can access this too)
// Output state
#define HW_GPIO1BOUT (HW_REG_BASE + 0x0c0)
// Direction (1=output)
#define HW_GPIO1BDIR (HW_REG_BASE + 0x0c4)
// Input state
#define HW_GPIO1BIN (HW_REG_BASE + 0x0c8)
// Interrupt level
#define HW_GPIO1BINTLVL (HW_REG_BASE + 0x0cc)
// Interrupt flags (write 1 to clear)
#define HW_GPIO1BINTFLAG (HW_REG_BASE + 0x0d0)
// Interrupt propagation enable
// Do these interrupts go anywhere???
#define HW_GPIO1BINTENABLE (HW_REG_BASE + 0x0d4)
//??? seems to be a mirror of inputs at some point... power-up state?
#define HW_GPIO1BINMIR (HW_REG_BASE + 0x0d8)
// 0xFFFFFF by default, if cleared disables respective outputs. Top bits non-settable.
#define HW_GPIO1ENABLE (HW_REG_BASE + 0x0dc)
#define HW_GPIO1_SLOT 0x000020
#define HW_GPIO1_DEBUG 0xFF0000
#define HW_GPIO1_DEBUG_SH 16
// Starlet side of GPIO1
// Output state
#define HW_GPIO1OUT (HW_REG_BASE + 0x0e0)
// Direction (1=output)
#define HW_GPIO1DIR (HW_REG_BASE + 0x0e4)
// Input state
#define HW_GPIO1IN (HW_REG_BASE + 0x0e8)
// Interrupt level
#define HW_GPIO1INTLVL (HW_REG_BASE + 0x0ec)
// Interrupt flags (write 1 to clear)
#define HW_GPIO1INTFLAG (HW_REG_BASE + 0x0f0)
// Interrupt propagation enable (interrupts go to main interrupt 0x800)
#define HW_GPIO1INTENABLE (HW_REG_BASE + 0x0f4)
//??? seems to be a mirror of inputs at some point... power-up state?
#define HW_GPIO1INMIR (HW_REG_BASE + 0x0f8)
// Owner of each GPIO bit. If 1, GPIO1B registers assume control. If 0, GPIO1 registers assume control.
#define HW_GPIO1OWNER (HW_REG_BASE + 0x0fc)
// ????
#define HW_DIFLAGS (HW_REG_BASE + 0x180)
#define DIFLAGS_BOOT_CODE 0x100000
// maybe a GPIO???
#define HW_CLOCKS (HW_REG_BASE + 0x190)
#define HW_RESETS (HW_REG_BASE + 0x194)
#define HW_GPIO2OUT (HW_REG_BASE + 0x1c8)
#define HW_GPIO2DIR (HW_REG_BASE + 0x1cc)
#define HW_GPIO2IN (HW_REG_BASE + 0x1d0)
#define HW_OTPCMD (HW_REG_BASE + 0x1ec)
#define HW_OTPDATA (HW_REG_BASE + 0x1f0)
#define HW_VERSION (HW_REG_BASE + 0x214)
/* NAND Registers */
#define NAND_REG_BASE 0xd010000
#define NAND_CMD (NAND_REG_BASE + 0x000)
#define NAND_STATUS NAND_CMD
#define NAND_CONF (NAND_REG_BASE + 0x004)
#define NAND_ADDR0 (NAND_REG_BASE + 0x008)
#define NAND_ADDR1 (NAND_REG_BASE + 0x00c)
#define NAND_DATA (NAND_REG_BASE + 0x010)
#define NAND_ECC (NAND_REG_BASE + 0x014)
#define NAND_UNK1 (NAND_REG_BASE + 0x018)
#define NAND_UNK2 (NAND_REG_BASE + 0x01c)
/* AES Registers */
#define AES_REG_BASE 0xd020000
#define AES_CMD (AES_REG_BASE + 0x000)
#define AES_SRC (AES_REG_BASE + 0x004)
#define AES_DEST (AES_REG_BASE + 0x008)
#define AES_KEY (AES_REG_BASE + 0x00c)
#define AES_IV (AES_REG_BASE + 0x010)
/* SHA-1 Registers */
#define SHA_REG_BASE 0xd030000
#define SHA_CMD (SHA_REG_BASE + 0x000)
#define SHA_SRC (SHA_REG_BASE + 0x004)
#define SHA_H0 (SHA_REG_BASE + 0x008)
#define SHA_H1 (SHA_REG_BASE + 0x00c)
#define SHA_H2 (SHA_REG_BASE + 0x010)
#define SHA_H3 (SHA_REG_BASE + 0x014)
#define SHA_H4 (SHA_REG_BASE + 0x018)
/* SD Host Controller Registers */
#define SDHC_REG_BASE 0xd070000
/* EXI Registers */
#define EXI_REG_BASE 0xd806800
#define EXI0_REG_BASE (EXI_REG_BASE+0x000)
#define EXI1_REG_BASE (EXI_REG_BASE+0x014)
#define EXI2_REG_BASE (EXI_REG_BASE+0x028)
#define EXI0_CSR (EXI0_REG_BASE+0x000)
#define EXI0_MAR (EXI0_REG_BASE+0x004)
#define EXI0_LENGTH (EXI0_REG_BASE+0x008)
#define EXI0_CR (EXI0_REG_BASE+0x00c)
#define EXI0_DATA (EXI0_REG_BASE+0x010)
#define EXI1_CSR (EXI1_REG_BASE+0x000)
#define EXI1_MAR (EXI1_REG_BASE+0x004)
#define EXI1_LENGTH (EXI1_REG_BASE+0x008)
#define EXI1_CR (EXI1_REG_BASE+0x00c)
#define EXI1_DATA (EXI1_REG_BASE+0x010)
#define EXI2_CSR (EXI2_REG_BASE+0x000)
#define EXI2_MAR (EXI2_REG_BASE+0x004)
#define EXI2_LENGTH (EXI2_REG_BASE+0x008)
#define EXI2_CR (EXI2_REG_BASE+0x00c)
#define EXI2_DATA (EXI2_REG_BASE+0x010)
#define EXI_BOOT_BASE (EXI_REG_BASE+0x040)
/* MEMORY CONTROLLER Registers */
#define MEM_REG_BASE 0xd8b4000
#define MEM_PROT (MEM_REG_BASE+0x20a)
#define MEM_PROT_START (MEM_REG_BASE+0x20c)
#define MEM_PROT_END (MEM_REG_BASE+0x20e)
#define MEM_FLUSHREQ (MEM_REG_BASE+0x228)
#define MEM_FLUSHACK (MEM_REG_BASE+0x22a)
#endif

37
integer.h Normal file
View File

@ -0,0 +1,37 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
#define _INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
#endif
#endif

81
iosmodule.ld Normal file
View File

@ -0,0 +1,81 @@
OUTPUT_FORMAT("elf32-bigarm")
OUTPUT_ARCH(arm)
ENTRY(_start)
__stack_size = 0x4000;
MEMORY
{
sram : ORIGIN = 0xFFFF0000, LENGTH = 0x10000
stack : ORIGIN = 0xFFFE0000, LENGTH = 0x4000
}
PHDRS
{
sram PT_LOAD AT ( 0xFFFF0000 ) ;
stack PT_LOAD AT ( 0xFFFE0000 ) ;
}
SECTIONS
{
.init :
{
*(.init)
. = ALIGN(4);
} >sram :sram
.text :
{
*(.text*)
*(.text.*)
*(.gnu.warning)
*(.gnu.linkonce.t*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
} >sram :sram
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
. = ALIGN(4);
} >sram :sram
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
. = ALIGN(4);
} >sram :sram
.bss :
{
__bss_start = . ;
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end = . ;
} >sram :sram
.stack :
{
__stack_end = .;
. = . +__stack_size;
. = ALIGN(4);
__stack_addr = .;
} >stack :stack
/DISCARD/ :
{
*(.ARM.exidx*)
*(.ARM.extab*)
}
}

67
ipc.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef __IPC_H__
#define __IPC_H__ 1
struct ioctl_vector {
void *data;
unsigned int len;
} __attribute__((packed));
struct ipcmessage
{
unsigned int command; // 0
unsigned int result; // 4
union
{
unsigned int fd; // 8
};
union
{
struct
{
char *device; // 12
unsigned int mode; // 16
unsigned int resultfd; // 20
} open;
struct
{
void *data;
unsigned int length;
} read, write;
struct
{
int offset;
int origin;
} seek;
struct
{
unsigned int command;
unsigned int *buffer_in;
unsigned int length_in;
unsigned int *buffer_io;
unsigned int length_io;
} ioctl;
struct
{
unsigned int command; // C
unsigned int argc_in; // 10
unsigned int argc_io; // 14
struct ioctl_vector *argv; // 18
} ioctlv;
};
} __attribute__((packed)) ipcmessage;
#define IOS_OPEN 0x01
#define IOS_CLOSE 0x02
#define IOS_READ 0x03
#define IOS_WRITE 0x04
#define IOS_SEEK 0x05
#define IOS_IOCTL 0x06
#define IOS_IOCTLV 0x07
#endif

299
main.c Normal file
View File

@ -0,0 +1,299 @@
/*
DIOS MIOS - Gamecube USB loader for Nintendo Wii
Copyright (C) 2010-2012 crediar
*/
#include "string.h"
#include "global.h"
#include "ipc.h"
#include "alloc.h"
#include "ff.h"
#include "diskio.h"
#include "dol.h"
#include "GCPad.h"
#include "HW.h"
#include "Patches.h"
#include "Config.h"
#include "Card.h"
#include "DVD.h"
#include "Drive.h"
#include "dip.h"
char __aeabi_unwind_cpp_pr0[0];
void Syscall( u32 a, u32 b, u32 c, u32 d )
{
dbgprintf("Syscall,%d,%d,%d,%d\n", a, b, c, d);
return;
}
void SWI( u32 a, u32 b )
{
dbgprintf("SWI:%X,%X\n", a, b );
return;
}
void PrefetchAbort( void )
{
u32 val;
__asm("mov %0,lr": "=r" (val) );
*(vu32*)0xD800070 |= 1;
dbgprintf("PrefetchAbort LR:%08x\n", val-8 );
while(1);
return;
}
void DataAbort( u32 a, u32 b, u32 c, u32 d, u32 e, u32 f, u32 g, u32 h )
{
u32 val;
__asm("mov %0,lr": "=r" (val) );
*(vu32*)0xD800070 |= 1;
dbgprintf("DataAbort: LR:%08x, %x, %x, %x, %x, %x, %x, %x\n",val-8,b,c,d,e,f,g,h);
Shutdown();
}
void IRQHandler( void )
{
u32 IRQs = read32(HW_ARMIRQFLAG) /*& read32(HW_ARMIRQMASK)*/;
if( IRQs & IRQ_GPIO1 ) // Starlet GPIO IRQ
{
if( read32(HW_GPIO_INTFLAG) & (1) )
{
set32( HW_EXICTRL, 1 );
int i;
for( i = 0; i < 0x20; i+=4 )
dbgprintf("0x%08X:0x%08X\t0x%08X\n", i, read32( CARD_BASE + i ), read32( CARD_SHADOW + i ) );
dbgprintf("\n");
for( i = 0; i < 0x30; i+=4 )
dbgprintf("0x%08X:0x%08X\t0x%08X\n", i, read32( 0x00002F00 + i ), read32( 0x00002F30 + i ) );
dbgprintf("\n");
for( i = 0; i < 0x30; i+=4 )
dbgprintf("0x%08X:0x%08X\t0x%08X\n", 0x0D806000 + i, read32( 0x0D806000 + i ), read32( 0x0D006000 + i ) );
dbgprintf("DVD:Error:%08X\n", DVDLowGetError() );
udelay(10000);
set32( HW_GPIO_ENABLE, GPIO_POWER );
set32( HW_GPIO_OUT, GPIO_POWER );
while(1);
}
} else if( IRQs & IRQ_RESET )
{
;
} else {
set32( HW_EXICTRL, 1 );
udelay(1000);
dbgprintf("IRQ:%08X %08X\n", read32(HW_ARMIRQFLAG), read32(HW_GPIO_INTFLAG) );
set32( HW_EXICTRL, 0 );
}
return;
}
void FIQHandler( void )
{
//dbgprintf("FIQHandler\n");
return;
}
void DebugPoke( u8 Value )
{
clear32( 0xD8000E0, 0xFF0000 );
set32( 0xD8000E0, Value<<16 );
}
void SysReset( void )
{
write32( HW_RESETS, (read32( HW_RESETS ) | 0x20 ) & (~1) );
}
void SysShutdown( void )
{
set32( HW_GPIO_ENABLE, GPIO_POWER );
set32( HW_GPIO_OUT, GPIO_POWER );
while(1);
}
u32 fail;
FIL Log;
int main( int argc, char *argv[] )
{
udelay(800);
#ifndef REALNAND
PPCReset();
clear32( HW_RESETS, 0x48000 );
clear32( 0xD800184, 0x438E );
ChangeClock();
DRAMInit(1,0);
set32( HW_RESETS, 0x48000 );
set32( 0xD800184, 0x438E );
UNKInit( 1, 1 );
#endif
set32( 0xD800038, IRQ_RESET|IRQ_GPIO1 );
set32( 0xD80003C, IRQ_RESET|IRQ_GPIO1 );
udelay(200);
u32 SP[2];
GetRevision( SP+1, SP );
if( SP[1] == 0 )
{
write32( HW_MEMIRR, 0x67 );
} else {
write32( HW_MEMIRR, 0x27 );
}
MIOSInit();
#ifdef DEBUG
dbgprintf("DIOS-MIOS [DEBUG] v%d.%d\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
#else
#ifdef REALNAND
dbgprintf("DIOS-MIOS v%d.%db\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
#else
dbgprintf("DIOS-MIOS v%d.%da\n", DM_VERSION>>16, DM_VERSION & 0xFFFF );
#endif
#endif
dbgprintf("Built: " __DATE__ " " __TIME__ "\n");
dbgprintf("This software is licensed under GPLv3, for more details visit:\nhttp://code.google.com/p/diosmioslite\n");
//dbgprintf("CPU Ver:%d.%d\n", SP[1], SP[0] );
//dbgprintf("MEMInitLow()...\n");
MEMInitLow();
// EHCI
*(vu32*)0x0D0400A4 = 0x00004026;
*(vu32*)0x0D0400B0 = 0x0002422E;
*(vu32*)0x0D0400B4 = 0x03802E14;
// DDR control
*(vu16*)0x0D8B4034 = 0x0000;
*(vu16*)0x0D8B403C = 0x0000;
*(vu16*)0x0D8B4034 = 0x0000;
*(vu16*)0x0D8B403C = 0x0000;
*(vu16*)0x0D8B4040 = 0x0000;
*(vu16*)0x0D8B4044 = 0x0000;
*(vu16*)0x0D8B4048 = 0x0000;
*(vu16*)0x0D8B404C = 0x0000;
*(vu16*)0x0D8B4050 = 0x0000;
*(vu16*)0x0D8B4054 = 0x13EB;
*(vu16*)0x0D8B4058 = 0x09B5;
*(vu16*)0x0D8B4060 = 0x0000;
*(vu16*)0x0D8B4064 = 0x0000;
*(vu16*)0x0D8B420C = 0x3620;
*(vu16*)0x0D8B4220 = 0xF000;
udelay(8000);
HeapInit( (u8*)0x13600000 );
set32( HW_EXICTRL, 1 );
DVDInit();
ConfigInit( (DML_CFG*)0x01200000 );
if( !ConfigGetConfig(DML_CFG_BOOT_DISC) )
{
if( DVDSelectGame() == DI_SUCCESS )
{
if( ConfigGetConfig(DML_CFG_NMM) )
CardInit();
} else {
dbgprintf("Loading disc\n");
((DML_CFG*)0x01200000)->Version = CONFIG_VERSION;
((DML_CFG*)0x01200000)->Magicbytes = 0xD1050CF6;
((DML_CFG*)0x01200000)->VideoMode = DML_VID_DML_AUTO;
((DML_CFG*)0x01200000)->Config = DML_CFG_BOOT_DISC;
}
}
DIInit();
//Switch mem2 to ARAM
DRAMCTRLWrite( 0x49, 0x0E );
udelay(2);
DRAMCTRLWrite( 0x49, 0x0F );
udelay(2);
HeapInit( (u8*)0xFFFE5000 );
write32( HW_PPCIRQFLAG, read32(HW_PPCIRQFLAG) );
write32( HW_ARMIRQFLAG, read32(HW_ARMIRQFLAG) );
set32( HW_PPCIRQMASK, (1<<31) );
set32( HW_IPC_PPCCTRL, 0x30 );
write32( 0x0D806008, 0 );
EXIControl(0);
write32( 0x1860, 0xdeadbeef ); // Clear OSReport area
write32( 0x30F8, 0 ); // Tell PPC side to start
ahb_flush_to( AHB_PPC );
while (1)
{
ahb_flush_from( AHB_STARLET ); //flush to arm
if( (((read32(0x12FC) >> 16) & 0x1030) == 0x1030 ) )
{
SysReset();
}
if( (((read32(0x12FC) >> 16) & 0x234) == 0x234 ) )
{
SysShutdown();
}
//Baten Kaitos save hax
if( read32(0) == 0x474B4245 )
{
if( read32( 0x0073E640 ) == 0xFFFFFFFF )
{
write32( 0x0073E640, 0 );
}
}
//if( read32(0x1860) != 0xdeadbeef )
//{
// if( read32(0x1860) != 0 )
// {
// dbgprintf( (char*)(P2C(read32(0x1860))),
// (char*)(P2C(read32(0x1864))),
// (char*)(P2C(read32(0x1868))),
// (char*)(P2C(read32(0x186C))),
// (char*)(P2C(read32(0x1870))),
// (char*)(P2C(read32(0x1864)))
// );
// }
// write32(0x1860, 0xdeadbeef);
//}
DIUpdateRegisters();
if( ConfigGetConfig(DML_CFG_NMM) )
CARDUpdateRegisters();
ahb_flush_to( AHB_PPC ); //flush to ppc
}
}

251
memory.c Normal file
View File

@ -0,0 +1,251 @@
#include "memory.h"
void _dc_inval_entries(void *start, int count);
void _dc_flush_entries(const void *start, int count);
void _dc_flush(void);
void _ic_inval(void);
void _drain_write_buffer(void);
u32 irq_kill(void);
void irq_restore(u32 cookie);
#define LINESIZE 0x20
#define CACHESIZE 0x4000
#define CR_MMU (1 << 0)
#define CR_DCACHE (1 << 2)
#define CR_ICACHE (1 << 12)
// TODO: move to hollywood.h once we figure out WTF
#define HW_100 (HW_REG_BASE + 0x100)
#define HW_104 (HW_REG_BASE + 0x104)
#define HW_108 (HW_REG_BASE + 0x108)
#define HW_10c (HW_REG_BASE + 0x10c)
#define HW_110 (HW_REG_BASE + 0x110)
#define HW_114 (HW_REG_BASE + 0x114)
#define HW_118 (HW_REG_BASE + 0x118)
#define HW_11c (HW_REG_BASE + 0x11c)
#define HW_120 (HW_REG_BASE + 0x120)
#define HW_124 (HW_REG_BASE + 0x124)
#define HW_130 (HW_REG_BASE + 0x130)
#define HW_134 (HW_REG_BASE + 0x134)
#define HW_138 (HW_REG_BASE + 0x138)
#define HW_188 (HW_REG_BASE + 0x188)
#define HW_18C (HW_REG_BASE + 0x18c)
// what is this thing doing anyway?
// and why only on reads?
u32 _mc_read32(u32 addr)
{
u32 data;
u32 tmp130 = 0;
// this seems to be a bug workaround
if(!(read32(HW_VERSION) & 0xF0))
{
tmp130 = read32(HW_130);
write32(HW_130, tmp130 | 0x400);
// Dummy reads?
read32(HW_138);
read32(HW_138);
read32(HW_138);
read32(HW_138);
}
data = read32(addr);
read32(HW_VERSION); //???
if(!(read32(HW_VERSION) & 0xF0))
write32(HW_130, tmp130);
return data;
}
// this is ripped from IOS, because no one can figure out just WTF this thing is doing
void _ahb_flush_to(enum AHBDEV dev) {
u32 mask = 10;
switch(dev) {
case AHB_STARLET: mask = 0x8000; break;
case AHB_PPC: mask = 0x4000; break;
//case 2: mask = 0x0001; break;
case AHB_NAND: mask = 0x0002; break;
case AHB_AES: mask = 0x0004; break;
case AHB_SHA1: mask = 0x0008; break;
case AHB_EHCI: mask = 0x0010; break;
//case 7: mask = 0x0020; break;
//case 8: mask = 0x0040; break;
case AHB_SDHC: mask = 0x0080; break;
//case 10: mask = 0x0100; break;
//case 11: mask = 0x1000; break;
//case 12: mask = 0x0000; break;
default:
dbgprintf("ahb_invalidate(%d): Invalid device\n", dev);
return;
}
//NOTE: 0xd8b000x, not 0xd8b400x!
u32 val = _mc_read32(0xd8b0008);
if(!(val & mask)) {
switch(dev) {
// 2 to 10 in IOS, add more
case AHB_NAND:
case AHB_AES:
case AHB_SHA1:
case AHB_EHCI:
case AHB_SDHC:
while((read32(HW_18C) & 0xF) == 9)
set32(HW_188, 0x10000);
clear32(HW_188, 0x10000);
set32(HW_188, 0x2000000);
mask32(HW_124, 0x7c0, 0x280);
set32(HW_134, 0x400);
while((read32(HW_18C) & 0xF) != 9);
set32(HW_100, 0x400);
set32(HW_104, 0x400);
set32(HW_108, 0x400);
set32(HW_10c, 0x400);
set32(HW_110, 0x400);
set32(HW_114, 0x400);
set32(HW_118, 0x400);
set32(HW_11c, 0x400);
set32(HW_120, 0x400);
write32(0xd8b0008, _mc_read32(0xd8b0008) & (~mask));
write32(0xd8b0008, _mc_read32(0xd8b0008) | mask);
clear32(HW_134, 0x400);
clear32(HW_100, 0x400);
clear32(HW_104, 0x400);
clear32(HW_108, 0x400);
clear32(HW_10c, 0x400);
clear32(HW_110, 0x400);
clear32(HW_114, 0x400);
clear32(HW_118, 0x400);
clear32(HW_11c, 0x400);
clear32(HW_120, 0x400);
clear32(HW_188, 0x2000000);
mask32(HW_124, 0x7c0, 0xc0);
//0, 1, 11 in IOS, add more
case AHB_STARLET:
case AHB_PPC:
write32(0xd8b0008, val & (~mask));
// wtfux
write32(0xd8b0008, val | mask);
write32(0xd8b0008, val | mask);
write32(0xd8b0008, val | mask);
}
}
}
// invalidate device and then starlet
void ahb_flush_to(enum AHBDEV type)
{
u32 cookie = irq_kill();
_ahb_flush_to(type);
if(type != AHB_STARLET)
_ahb_flush_to(AHB_STARLET);
irq_restore(cookie);
}
// flush device and also invalidate memory
void ahb_flush_from(enum AHBDEV dev)
{
u32 cookie = irq_kill();
u16 req = 0;
u16 ack;
int i;
switch(dev)
{
case AHB_STARLET:
case AHB_PPC:
req = 1;
break;
case AHB_AES:
case AHB_SHA1:
req = 2;
break;
case AHB_NAND:
case AHB_SDHC:
req = 8;
break;
case AHB_EHCI:
req = 4;
break;
default:
dbgprintf("ahb_flush(%d): Invalid device\n", dev);
goto done;
}
write16(MEM_FLUSHREQ, req);
for(i=0;i<1000000;i++) {
ack = read16(MEM_FLUSHACK);
_ahb_flush_to(AHB_STARLET);
if(ack == req)
break;
}
write16(MEM_FLUSHREQ, 0);
if(i>=1000000) {
dbgprintf("ahb_flush(%d): Flush (0x%x) did not ack!\n", dev, req);
}
done:
irq_restore(cookie);
}
void dc_flushrange(const void *start, u32 size)
{
u32 cookie = irq_kill();
if(size > 0x4000) {
_dc_flush();
} else {
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_flush_entries(start, (end - start) / LINESIZE);
}
_drain_write_buffer();
ahb_flush_from(AHB_PPC);
irq_restore(cookie);
}
void dc_invalidaterange(void *start, u32 size)
{
u32 cookie = irq_kill();
void *end = ALIGN_FORWARD(((u8*)start) + size, LINESIZE);
start = ALIGN_BACKWARD(start, LINESIZE);
_dc_inval_entries(start, (end - start) / LINESIZE);
ahb_flush_to(AHB_STARLET);
irq_restore(cookie);
}
void dc_flushall(void)
{
u32 cookie = irq_kill();
_dc_flush();
_drain_write_buffer();
ahb_flush_from(AHB_PPC);
irq_restore(cookie);
}
void ic_invalidateall(void)
{
u32 cookie = irq_kill();
_ic_inval();
ahb_flush_to(AHB_STARLET);
irq_restore(cookie);
}
u32 dma_addr(void *p)
{
u32 addr = (u32)p;
switch(addr>>20) {
case 0xfff:
case 0x0d4:
case 0x0dc:
if(read32(HW_MEMMIRR) & 0x20) {
addr ^= 0x10000;
}
addr &= 0x0001FFFF;
addr |= 0x0d400000;
break;
}
dbgprintf("DMA to %p: address %08x\n", p, addr);
return addr;
}

108
memory.h Normal file
View File

@ -0,0 +1,108 @@
#ifndef __MEMORY_H__
#define __MEMORY_H__
#include "string.h"
#include "global.h"
#include "ipc.h"
#include "utils.h"
#include "hollywood.h"
#include "vsprintf.h"
#define ALIGN_FORWARD(x,align) \
((typeof(x))((((u32)(x)) + (align) - 1) & (~(align-1))))
#define ALIGN_BACKWARD(x,align) \
((typeof(x))(((u32)(x)) & (~(align-1))))
enum AHBDEV {
AHB_STARLET = 0, //or MEM2 or some controller or bus or ??
AHB_PPC = 1, //ppc or something else???
AHB_NAND = 3,
AHB_AES = 4,
AHB_SHA1 = 5,
AHB_EHCI = 6,
AHB_SDHC = 9,
};
void dc_flushrange(const void *start, u32 size);
void dc_invalidaterange(void *start, u32 size);
void dc_flushall(void);
void ic_invalidateall(void);
void ahb_flush_from(enum AHBDEV dev);
void ahb_flush_to(enum AHBDEV dev);
u32 dma_addr(void *p);
static inline u32 get_cr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c1, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ttbr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c2, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_dacr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c3, c0, 0" : "=r" (data) );
return data;
}
static inline void set_cr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c1, c0, 0" :: "r" (data) );
}
static inline void set_ttbr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c2, c0, 0" :: "r" (data) );
}
static inline void set_dacr(u32 data)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c3, c0, 0" :: "r" (data) );
}
static inline u32 get_dfsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 0" : "=r" (data) );
return data;
}
static inline u32 get_ifsr(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c5, c0, 1" : "=r" (data) );
return data;
}
static inline u32 get_far(void)
{
u32 data;
__asm__ volatile ( "mrc\tp15, 0, %0, c6, c0, 0" : "=r" (data) );
return data;
}
void _ahb_flush_to(enum AHBDEV dev);
static inline void dc_inval_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c6, 1" :: "r" (block) );
_ahb_flush_to(AHB_STARLET); //TODO: check if really needed and if not, remove
}
static inline void dc_flush_block_fast(void *block)
{
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 1" :: "r" (block) );
__asm__ volatile ( "mcr\tp15, 0, %0, c7, c10, 4" :: "r" (0) );
ahb_flush_from(AHB_PPC); //TODO: check if really needed and if not, remove
}
#endif

70
memory_asm.S Normal file
View File

@ -0,0 +1,70 @@
#define CPSR_IRQDIS 0x80
#define CPSR_FIQDIS 0x40
.arm
.globl _dc_inval_entries
.globl _dc_flush_entries
.globl _dc_flush
.globl _dc_inval
.globl _ic_inval
.globl _drain_write_buffer
.globl _tlb_inval
.globl irq_kill
.globl irq_restore
.text
irq_kill:
mrs r1, cpsr
and r0, r1, #(CPSR_IRQDIS|CPSR_FIQDIS)
orr r1, r1, #(CPSR_IRQDIS|CPSR_FIQDIS)
msr cpsr_c, r1
bx lr
irq_restore:
mrs r1, cpsr
bic r1, r1, #(CPSR_IRQDIS|CPSR_FIQDIS)
orr r1, r1, r0
msr cpsr_c, r1
bx lr
_dc_inval_entries:
mcr p15, 0, r0, c7, c6, 1
add r0, #0x20
subs r1, #1
bne _dc_inval_entries
bx lr
_dc_flush_entries:
mcr p15, 0, r0, c7, c10, 1
add r0, #0x20
subs r1, #1
bne _dc_flush_entries
bx lr
_dc_flush:
mrc p15, 0, pc, c7, c10, 3
bne _dc_flush
bx lr
_dc_inval:
mov r0, #0
mcr p15, 0, r0, c7, c6, 0
bx lr
_ic_inval:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0
bx lr
_drain_write_buffer:
mov r0, #0
mcr p15, 0, r0, c7, c10, 4
bx lr
_tlb_inval:
mov r0, #0
mcr p15, 0, r0, c8, c7
bx lr

213
start.s Normal file
View File

@ -0,0 +1,213 @@
.global _start
.global start
.global udelay
.global RegWrite
.global RegRead
.global DRAMWrite
.global DRAMRead
.global DRAMCTRLRead
.global DRAMCTRLWrite
.extern main
.extern Syscall
.extern SWI
.extern PrefetchAbort
.extern DataAbort
.extern IRQHandler
.extern FIQHandler
.arm
.section ".init"
_start:
ldr pc, =start
ldr pc, =Syscall
ldr pc, =SWI
ldr pc, =PrefetchAbort
ldr pc, =DataAbort
ldr pc, =0
ldr pc, =IRQHandler
movs pc, lr
start:
mov r0, #0
ldr r1, =0xd80003c
str r0, [r1]
mov r0, #0
mcr p15, 0, r0,c7,c5
mcr p15, 0, r0,c7,c6
mrc p15, 0, r0,c1,c0
bic r0, r0, #4
bic r0, r0, #0x1000
mcr p15, 0, r0,c1,c0
ldr r0,=__bss_start
ldr r1,=__bss_end
mov r2,#0
mov r3,#4
clearbss:
cmp r0, r1
bcs clearbss_end
str r2, [r0], r3
b clearbss
clearbss_end:
msr CPSR_c, #211
ldr sp, =0xFFFF7E60
msr CPSR_c, #210
ldr sp, =0xFFFF7E60
msr CPSR_c, #209
ldr sp, =0xFFFF7E60
msr CPSR_c, #215
ldr sp, =0xFFFF7E60
msr CPSR_c, #219
ldr sp, =0xFFFF7E60
msr CPSR_c, #31
ldr sp, =0xFFFE4000
#enable IRQs
mrs r1, cpsr
bic r1, r1, #0xC0
msr cpsr_c, r1
mov lr, pc
ldr pc, =main
RegWrite:
ldr r3,=0xd8b4000
lsl r0, r0, #1
add r0, r0, r3
strh r1, [r0]
bx lr
RegRead:
ldr r3,=0xd8b4000
lsl r0, r0, #1
add r0, r0, r3
ldrh r0, [r0]
lsl r0, r0, #0x10
lsr r0, r0, #0x10
bx lr
DRAMWrite:
push {r4,lr}
add r3, r0, #0
add r4, r1, #0
mov r0, #0x3a
add r1, r3, #0
bl RegWrite
mov r0, #0x3a
bl RegRead
mov r0, #0x3b
add r1, r4, #0
bl RegWrite
pop {r4}
pop {r0}
bx r0
DRAMRead:
push {lr}
add r1, r0, #0
mov r0, #0x3a
bl RegWrite
mov r0, #0x3a
bl RegRead
mov r0, #0x3b
bl RegRead
pop {r1}
bx r1
DRAMCTRLWrite:
push {r4,r5,lr}
ldr r4, =0x163
add r3, r0, #0
add r5, r1, #0
add r0, r4, #0
add r1, r3, #0
bl DRAMWrite
add r0, r4, #0
bl DRAMRead
mov r0, #0xb1
add r1, r5, #0
lsl r0, r0, #1
bl DRAMWrite
pop {r4,r5}
pop {r0}
bx r0
DRAMCTRLRead:
push {r4,lr}
ldr r4, =0x163
add r1, r0, #0
add r0, r4, #0
bl DRAMWrite
add r0, r4, #0
bl DRAMRead
ldr r0, =0x162
bl DRAMRead
pop {r4}
pop {r1}
bx r1
udelay:
push {lr}
lsr r3, r0, #2
add r3, r3, r0
lsr r2, r0, #6
add r0, r3, r2
cmp r0, #1
bhi loc_ffff20e8
mov r0, #2
loc_ffff20e8:
ldr r1, =0xd800010
ldr r3, [r1]
add r2, r3, r0
cmp r2, r3
bls loc_ffff211c
loc_ffff20f2:
ldr r3, [r1]
cmp r3, r2
bcc loc_ffff20f2
loc_ffff20f8:
pop {r0}
bx r0
loc_ffff211c:
add r3, r1, #0
loc_ffff211e:
ldr r0, [r3]
cmp r0, #0
blt loc_ffff211e
cmp r0, r2
bcc loc_ffff211e
b loc_ffff20f8
.end

125
string.c Normal file
View File

@ -0,0 +1,125 @@
/*
* linux/lib/string.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include "string.h"
size_t strnlen(const char *s, size_t count)
{
const char *sc;
for (sc = s; count-- && *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
size_t strlen(const char *s)
{
const char *sc;
for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc - s;
}
char *strncpy(char *dst, const char *src, size_t n)
{
char *ret = dst;
while (n && (*dst++ = *src++))
n--;
while (n--)
*dst++ = 0;
return ret;
}
char *strcpy(char *dst, const char *src)
{
char *ret = dst;
while ((*dst++ = *src++))
;
return ret;
}
int strcmp(const char *p, const char *q)
{
for (;;) {
unsigned char a, b;
a = *p++;
b = *q++;
if (a == 0 || a != b)
return a - b;
}
}
int strncmp(const char *p, const char *q, size_t n)
{
while (n-- != 0) {
unsigned char a, b;
a = *p++;
b = *q++;
if (a == 0 || a != b)
return a - b;
}
return 0;
}
void *memset(void *dst, int x, size_t n)
{
unsigned char *p;
for (p = dst; n; n--)
*p++ = x;
return dst;
}
//
//void udelay(u32 d)
//{
// // should be good to max .2% error
// u32 ticks = d * 19 / 10;
//
// if(ticks < 2)
// ticks = 2;
//
// u32 now = *(vu32*)0x0D800010;
//
// u32 then = now + ticks;
//
// if(then < now) {
// while(*(vu32*)0x0D800010 >= now);
// now = *(vu32*)0x0D800010;
// }
//
// while(now < then) {
// now = *(vu32*)0x0D800010;
// }
//}
int memcmp(const void *s1, const void *s2, size_t n)
{
unsigned char *us1 = (unsigned char *) s1;
unsigned char *us2 = (unsigned char *) s2;
while (n-- != 0) {
if (*us1 != *us2)
return (*us1 < *us2) ? -1 : +1;
us1++;
us2++;
}
return 0;
}
char *strchr(const char *s, int c)
{
do {
if(*s == c)
return (char *)s;
} while(*s++ != 0);
return NULL;
}

23
string.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _STRING_H_
#define _STRING_H_
#include "global.h"
char *strcpy(char *, const char *);
char *strncpy(char *, const char *, size_t);
int strcmp(const char *, const char *);
int strncmp(const char *p, const char *q, size_t n);
size_t strlen(const char *);
size_t strnlen(const char *, size_t);
char *strchr(const char *s, int c);
extern void *memset(void *, int, size_t);
void udelay(u32 d);
//void *memcpy(void *, const void *, size_t);
//void *memcpy(void *, const void *, size_t);
//void *memcpy(void *, const void *, size_t);
int memcmp(const void *s1, const void *s2, size_t n);
int sprintf( char *astr, const char *fmt, ...);
#endif

92
tiny_ehci_glue.c Normal file
View File

@ -0,0 +1,92 @@
/*
EHCI glue. A bit hacky for the moment. needs cleaning..
Copyright (C) 2008 kwiirk.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tiny_ehci_glue.h"
#define static
#define inline extern
int verbose=0;
void BUG(void)
{
dbgprintf("bug\n");
while(1);
}
#define BUG_ON(a) if(a)BUG()
void msleep(int msec)
{
udelay(2048*msec);
}
extern u32 __exe_start_virt__;
extern u32 __ram_start_virt__;
extern u32 ios_thread_stack;
void print_hex_dump_bytes(char *header,int prefix,u8 *buf,int len)
{
int i;
if (len>0x100)len=0x100;
dbgprintf("%s %08X\n",header,(u32)buf);
for (i=0;i<len;i++){
dbgprintf("%02x ",buf[i]);
if((i&0xf) == 0xf)
dbgprintf("\n");
}
dbgprintf("\n");
}
#define DUMP_PREFIX_OFFSET 1
#include "ehci.h"
#define ehci_readl(a) ((*((volatile u32*)(a))))
//#define ehci_writel(e,v,a) do{msleep(40);dbgprintf("writel %08X %08X\n",a,v);*((volatile u32*)(a))=(v);}while(0)
#define ehci_writel(v,a) do{*((volatile u32*)(a))=(v);}while(0)
struct ehci_hcd _ehci;
struct ehci_hcd *ehci;
#include "ehci.c"
int usb_os_init(void);
int tiny_ehci_init(void)
{
int retval;
ehci = &_ehci;
//memset(ehci,0,sizeof(*ehci));
if(usb_os_init()<0)
return 0;
ehci->caps = (void*)0x0D040000;
ehci->regs = (void*)(0x0D040000 + HC_LENGTH(ehci_readl(&ehci->caps->hc_capbase)));
ehci->num_port = 4;
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl( &ehci->caps->hcs_params );
/* data structure init */
retval = ehci_init();
if (retval)
return retval;
ehci_release_ports(); //quickly release none usb2 port
return 0;
}

25
tiny_ehci_glue.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _TEGLUE_
#define _TEGLUE_
#include "string.h"
#include "ehci_types.h"
#include "utils.h"
#include "vsprintf.h"
int tiny_ehci_init(void);
#define readl(a) (*((volatile u32*)(a)))
#define writel(v,a) do{*((volatile u32*)(a))=(v);}while(0)
#define ehci_dbg(a...) dbgprintf(a)
#define printk(a...) dbgprintf(a)
#define get_timer() (*(((volatile u32*)0x0D800010)))
#define cpu_to_le32(a) swab32(a)
#define le32_to_cpu(a) swab32(a)
#define cpu_to_le16(a) swab16(a)
#define le16_to_cpu(a) swab16(a)
#define cpu_to_be32(a) (a)
#define be32_to_cpu(a) (a)
#endif

233
usb.c Normal file
View File

@ -0,0 +1,233 @@
/*
This file implements libogc usb API, but with ehci direct call
most of the file credit goes to libogc devs
*/
#define __usb_control_message(fd, b, c,d, e, f, g, h, i) ehci_control_message(fd,b,c,d,e,f,g)
static s32 __usb_getdesc(struct ehci_device * fd, u8 *buffer, u8 type, u8 index, u8 size)
{
//printk("usb_get desc %X %X %p\n",type,index,buffer);
return __usb_control_message(fd, USB_ENDPOINT_IN ,USB_REQ_GETDESCRIPTOR, (type << 8) | index, 0, size, buffer, NULL, NULL);
}
s32 USB_GetDescriptors(struct ehci_device * fd, usb_devdesc *udd)
{
u8 *buffer = NULL;
u8 *ptr = NULL;
usb_configurationdesc *ucd = NULL;
usb_interfacedesc *uid = NULL;
usb_endpointdesc *ued = NULL;
s32 retval = 0;
u32 iConf, iInterface, iEndpoint;
buffer = USB_Alloc(sizeof(*udd));
if(buffer == NULL)
{
retval = -ENOMEM;
goto free_and_error;
}
retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE);
if(retval < 0)
{
dbgprintf("__usb_getdesc():%d failed\n", retval );
goto free_and_error;
}
memcpy( udd, buffer, USB_DT_DEVICE_SIZE );
USB_Free(buffer);
u32 *_udd = (u32*)udd;
_udd[1] = ( udd->bLength << 24 ) | ( udd->bDescriptorType << 16 ) | cpu_to_le16(udd->bcdUSB);
_udd[2] = ( cpu_to_le16(udd->idVendor) << 16 ) | cpu_to_le16(udd->idProduct);
_udd[3] = ( cpu_to_le16(udd->bcdDevice) << 16 ) | (udd->iManufacturer<<8) | udd->iProduct;
u32 _ptr = (u32)USB_Alloc( udd->bNumConfigurations * sizeof(*udd->configurations) );
//udd->configurations = USB_Alloc(udd->bNumConfigurations* sizeof(*udd->configurations));
if( _ptr == 0)
{
dbgprintf("USB_Alloc():failed:%u\n", __LINE__ );
retval = -ENOMEM;
goto free_and_error;
}
_udd[4] = ( udd->iSerialNumber << 24 ) | ( udd->bNumConfigurations << 16 ) | (_ptr>>16);
_udd[5] = ((_ptr & 0xFFFF) << 16) | (_udd[5]&0xFFFF);
memset( udd->configurations, 0, udd->bNumConfigurations * sizeof(*udd->configurations) );
for( iConf = 0; iConf < udd->bNumConfigurations; iConf++)
{
buffer = USB_Alloc( USB_DT_CONFIG_SIZE );
if(buffer == NULL)
{
retval = -ENOMEM;
goto free_and_error;
}
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, USB_DT_CONFIG_SIZE);
ucd = &udd->configurations[iConf];
memcpy( ucd, buffer, USB_DT_CONFIG_SIZE );
USB_Free( buffer );
u32 *_ucd = (u32*)ucd;
_ucd[0] = ( ucd->bLength << 24 ) | ( ucd->bDescriptorType << 16 ) | cpu_to_le16(ucd->wTotalLength);
//ucd->wTotalLength = cpu_to_le16(ucd->wTotalLength);
buffer = USB_Alloc( ucd->wTotalLength);
if(buffer == NULL)
{
retval = -ENOMEM;
goto free_and_error;
}
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, ucd->wTotalLength);
if(retval < 0)
goto free_and_error;
ptr = buffer;
ptr += ucd->bLength;
retval = -ENOMEM;
//ucd->interfaces = USB_Alloc(ucd->bNumInterfaces* sizeof(*ucd->interfaces));
//if(ucd->interfaces == NULL)
// goto free_and_error;
_ptr = (u32)USB_Alloc(ucd->bNumInterfaces* sizeof(*ucd->interfaces));
if( _ptr == 0 )
goto free_and_error;
_ucd[2] = ( ucd->bMaxPower << 24 ) | (_ptr>>8);
_ucd[3] = ((_ptr & 0xFF) << 24) | (_ucd[3]&0xFFFFFF);
//dbgprintf("ucd->interfaces:%p\n", ucd->interfaces );
memset( ucd->interfaces, 0, ucd->bNumInterfaces * sizeof(*ucd->interfaces) );
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
{
uid = &ucd->interfaces[iInterface];
memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
ptr += uid->bLength;
//uid->endpoints = USB_Alloc(uid->bNumEndpoints* sizeof(*uid->endpoints));
//if(uid->endpoints == NULL)
// goto free_and_error;
u32 *_uid = (u32*)uid;
_ptr = (u32)USB_Alloc(uid->bNumEndpoints* sizeof(*uid->endpoints));
_uid[2] = (uid->iInterface<<24) | (_ptr >> 8);
_uid[3] = (_ptr<<24) | (_uid[3]&0xFFFFFF);
memset( uid->endpoints, 0, uid->bNumEndpoints * sizeof(*uid->endpoints) );
for( iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
{
ued = &uid->endpoints[iEndpoint];
memcpy( ued, ptr, USB_DT_ENDPOINT_SIZE );
ptr += ued->bLength;
//ued->wMaxPacketSize = cpu_to_le16(ued->wMaxPacketSize);
u32 *_ued = (u32*)ued;
_ued[1] = (cpu_to_le16(ued->wMaxPacketSize) << 16 ) | (_ued[1] & 0xFFFF);
}
}
USB_Free( buffer);
buffer = (u8*)NULL;
}
retval = 0;
free_and_error:
if(buffer != NULL)
USB_Free(buffer);
if(retval < 0)
USB_FreeDescriptors(udd);
return retval;
}
void USB_FreeDescriptors(usb_devdesc *udd)
{
int iConf, iInterface;
usb_configurationdesc *ucd;
usb_interfacedesc *uid;
if(udd->configurations != NULL)
{
for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
{
ucd = &udd->configurations[iConf];
if(ucd->interfaces != NULL)
{
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
{
uid = &ucd->interfaces[iInterface];
if(uid->endpoints != NULL)
USB_Free(uid->endpoints);
}
USB_Free(ucd->interfaces);
}
}
USB_Free(udd->configurations);
}
}
void USB_SuspendDevice(struct ehci_device *fd)
{
return ;
}
void USB_ResumeDevice(struct ehci_device *fd)
{
return ;
}
s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData)
{
return ehci_bulk_message(fd,bEndpoint,wLength,rpData);
}
s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
{
return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
}
s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration)
{
u8 *_configuration;
s32 retval;
_configuration = USB_Alloc(1);
if(_configuration == NULL)
return -ENOMEM;
retval = __usb_control_message(fd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_GETCONFIG, 0, 0, 1, _configuration, NULL, NULL);
if(retval >= 0)
*configuration = *_configuration;
USB_Free( _configuration);
return retval;
}
s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration)
{
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_SETCONFIG, configuration, 0, 0, NULL, NULL, NULL);
}
s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting)
{
if(alternateSetting == 0)
return -EINVAL;
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE),
USB_REQ_SETINTERFACE, alternateSetting, interface, 0, NULL, NULL, NULL);
}
s32 USB_ClearHalt(struct ehci_device *fd, u8 endpoint)
{
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT),
USB_REQ_CLEARFEATURE, USB_FEATURE_ENDPOINT_HALT, endpoint, 0, NULL, NULL, NULL);
}

176
usb.h Normal file
View File

@ -0,0 +1,176 @@
#ifndef __USB_H__
#define __USB_H__
#define USB_MAXPATH IPC_MAXPATH_LEN
#define USB_OK 0
#define USB_FAILED 1
/* Descriptor types */
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
/* Standard requests */
#define USB_REQ_GETSTATUS 0x00
#define USB_REQ_CLEARFEATURE 0x01
#define USB_REQ_SETFEATURE 0x03
#define USB_REQ_SETADDRESS 0x05
#define USB_REQ_GETDESCRIPTOR 0x06
#define USB_REQ_SETDESCRIPTOR 0x07
#define USB_REQ_GETCONFIG 0x08
#define USB_REQ_SETCONFIG 0x09
#define USB_REQ_GETINTERFACE 0x0a
#define USB_REQ_SETINTERFACE 0x0b
#define USB_REQ_SYNCFRAME 0x0c
/* Descriptor sizes per descriptor type */
#define USB_DT_DEVICE_SIZE 18
#define USB_DT_CONFIG_SIZE 9
#define USB_DT_INTERFACE_SIZE 9
#define USB_DT_ENDPOINT_SIZE 7
#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
#define USB_DT_HUB_NONVAR_SIZE 7
/* control message request type bitmask */
#define USB_CTRLTYPE_DIR_HOST2DEVICE (0<<7)
#define USB_CTRLTYPE_DIR_DEVICE2HOST (1<<7)
#define USB_CTRLTYPE_TYPE_STANDARD (0<<5)
#define USB_CTRLTYPE_TYPE_CLASS (1<<5)
#define USB_CTRLTYPE_TYPE_VENDOR (2<<5)
#define USB_CTRLTYPE_TYPE_RESERVED (3<<5)
#define USB_CTRLTYPE_REC_DEVICE 0
#define USB_CTRLTYPE_REC_INTERFACE 1
#define USB_CTRLTYPE_REC_ENDPOINT 2
#define USB_CTRLTYPE_REC_OTHER 3
#define USB_FEATURE_ENDPOINT_HALT 0
#define USB_ENDPOINT_IN 0x80
#define USB_ENDPOINT_OUT 0x00
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
# define ATTRIBUTE_PACKED __attribute__((packed))
typedef struct _usbctrlrequest {
u8 bRequestType;
u8 bRequest;
u16 wValue;
u16 wIndex;
u16 wLength;
} ATTRIBUTE_PACKED usbctrlrequest;
typedef struct _usbendpointdesc
{
u8 bLength;
u8 bDescriptorType;
u8 bEndpointAddress;
u8 bmAttributes;
u16 wMaxPacketSize;
u8 bInterval;
u8 pad;
} ATTRIBUTE_PACKED usb_endpointdesc;
typedef struct _usbinterfacedesc
{
u8 bLength;
u8 bDescriptorType;
u8 bInterfaceNumber;
u8 bAlternateSetting;
u8 bNumEndpoints;
u8 bInterfaceClass;
u8 bInterfaceSubClass;
u8 bInterfaceProtocol;
u8 iInterface;
struct _usbendpointdesc *endpoints;
} ATTRIBUTE_PACKED usb_interfacedesc;
typedef struct _usbconfdesc
{
u8 bLength;
u8 bDescriptorType;
u16 wTotalLength;
u8 bNumInterfaces;
u8 bConfigurationValue;
u8 iConfiguration;
u8 bmAttributes;
u8 bMaxPower;
struct _usbinterfacedesc *interfaces;
} ATTRIBUTE_PACKED usb_configurationdesc;
typedef struct _usbdevdesc
{
u8 bLength;
u8 bDescriptorType;
u16 bcdUSB;
u8 bDeviceClass;
u8 bDeviceSubClass;
u8 bDeviceProtocol;
u8 bMaxPacketSize0;
u16 idVendor;
u16 idProduct;
u16 bcdDevice;
u8 iManufacturer;
u8 iProduct;
u8 iSerialNumber;
u8 bNumConfigurations;
struct _usbconfdesc *configurations;
} ATTRIBUTE_PACKED usb_devdesc;
struct ehci_device;
s32 USB_OpenDevice(const char *device,u16 vid,u16 pid,struct ehci_device **fd);
s32 USB_CloseDevice(struct ehci_device **fd);
s32 USB_GetDescriptors(struct ehci_device *fd, usb_devdesc *udd);
void USB_FreeDescriptors(usb_devdesc *udd);
s32 USB_GetDeviceDescription(struct ehci_device *fd,usb_devdesc *devdesc);
void USB_SuspendDevice(struct ehci_device *fd);
void USB_ResumeDevice(struct ehci_device *fd);
s32 USB_ReadIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
s32 USB_ReadBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
s32 USB_ReadCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData);
s32 USB_WriteIntrMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u16 wLength,void *rpData);
s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData);
s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration);
s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration);
s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting);
s32 USB_ClearHalt(struct ehci_device *fd, u8 endpointAddress);
s32 USB_GetDeviceList(const char *devpath,void *descr_buffer,u8 num_descr,u8 b0,u8 *cnt_descr);
/* alloc memory from the USB subsystem */
void * USB_Alloc(int size);
void USB_Free(void *ptr);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

78
usb_os.c Normal file
View File

@ -0,0 +1,78 @@
#include <string.h>
#include "ehci_types.h"
#include "usb.h"
#include "ehci.h"
#include "alloc.h"
void *VirtualToPhysical( void *address )
{
if( ((u32)address & 0xFFFF0000) == 0xFFFF0000 )
return (void*)address;
return (void*)((u32)address & 0x7FFFFFFF);
}
void sync_after_write( void *a, u32 v )
{
dc_flushrange( a, v );
}
void sync_before_read( void *a, u32 v )
{
dc_invalidaterange( a, v );
}
int usb_os_init(void)
{
return 0;
}
void *ehci_maligned(int size,int alignement,int crossing)
{
return (void*)malloca( size, alignement );
}
dma_addr_t ehci_virt_to_dma(void *a)
{
return (dma_addr_t)VirtualToPhysical(a);
}
dma_addr_t ehci_dma_map_to(void *buf,size_t len)
{
sync_after_write(buf, len);
return (dma_addr_t)VirtualToPhysical(buf);
}
dma_addr_t ehci_dma_map_from(void *buf,size_t len)
{
sync_after_write(buf, len);
return (dma_addr_t)VirtualToPhysical(buf);
}
dma_addr_t ehci_dma_map_bidir(void *buf,size_t len)
{
sync_after_write(buf, len);
return (dma_addr_t)VirtualToPhysical(buf);
}
void ehci_dma_unmap_to(dma_addr_t buf,size_t len)
{
sync_before_read((void*)buf, len);
}
void ehci_dma_unmap_from(dma_addr_t buf,size_t len)
{
sync_before_read((void*)buf, len);
}
void ehci_dma_unmap_bidir(dma_addr_t buf,size_t len)
{
sync_before_read((void*)buf, len);
}
void *USB_Alloc(int size)
{
//u32 val;
//__asm("mov %0,lr": "=r" (val) );
//dbgprintf("USB_Alloc(%u) LR:%08x\n", size, val );
//void *ptr = malloc(size);
//memset( ptr, 0, size );
//return ptr;
return malloc(size);
}
void USB_Free(void *ptr)
{
return free(ptr);
}

745
usbstorage.c Normal file
View File

@ -0,0 +1,745 @@
/*-------------------------------------------------------------
usbstorage.c -- Bulk-only USB mass storage support
Copyright (C) 2008
Sven Peter (svpe) <svpe@gmx.net>
quick port to ehci/ios: Kwiirk
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
-------------------------------------------------------------*/
#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
#define HEAP_SIZE (32*1024)
#define TAG_START 0x1//BADC0DE
#define CBW_SIZE 31
#define CBW_SIGNATURE 0x43425355
#define CBW_IN (1 << 7)
#define CBW_OUT 0
#define CSW_SIZE 13
#define CSW_SIGNATURE 0x53425355
#define SCSI_TEST_UNIT_READY 0x00
#define SCSI_INQUIRY 0x12
#define SCSI_REQUEST_SENSE 0x03
#define SCSI_READ_CAPACITY 0x25
#define SCSI_READ_10 0x28
#define SCSI_WRITE_10 0x2A
#define SCSI_SENSE_REPLY_SIZE 18
#define SCSI_SENSE_NOT_READY 0x02
#define SCSI_SENSE_MEDIUM_ERROR 0x03
#define SCSI_SENSE_HARDWARE_ERROR 0x04
#define USB_CLASS_MASS_STORAGE 0x08
#define MASS_STORAGE_SCSI_COMMANDS 0x06
#define MASS_STORAGE_BULK_ONLY 0x50
#define USBSTORAGE_GET_MAX_LUN 0xFE
#define USBSTORAGE_RESET 0xFF
#define USB_ENDPOINT_BULK 0x02
#define USBSTORAGE_CYCLE_RETRIES 3
#define MAX_TRANSFER_SIZE 4096
#define DEVLIST_MAXSIZE 8
static s32 __usbstorage_reset(usbstorage_handle *dev);
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
// ehci driver has its own timeout.
static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData)
{
return USB_WriteBlkMsg(dev->usb_fd, bEndpoint, wLength, rpData);
}
static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
{
return USB_WriteCtrlMsg(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData);
}
static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
{
s32 retval = USBSTORAGE_OK;
if(cbLen == 0 || cbLen > 16)
return -EINVAL;
memset(dev->buffer, 0, CBW_SIZE);
((u32*)dev->buffer)[0]=cpu_to_le32(CBW_SIGNATURE);
((u32*)dev->buffer)[1]=cpu_to_le32(dev->tag);
((u32*)dev->buffer)[2]=cpu_to_le32(len);
dev->buffer[12] = flags;
dev->buffer[13] = lun;
dev->buffer[14] = (cbLen > 6 ? 0x10 : 6);
memcpy(dev->buffer + 15, (void*)cb, cbLen);
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
if(retval == CBW_SIZE) return USBSTORAGE_OK;
else if(retval >= 0) return USBSTORAGE_ESHORTWRITE;
return retval;
}
static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
{
s32 retval = USBSTORAGE_OK;
u32 signature, tag, _dataResidue, _status;
memset(dev->buffer, 0xff, CSW_SIZE);
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer);
//print_hex_dump_bytes("csv resp:",DUMP_PREFIX_OFFSET,dev->buffer,CSW_SIZE);
if(retval >= 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD;
else if(retval < 0) return retval;
signature = le32_to_cpu(((u32*)dev->buffer)[0]);
tag = le32_to_cpu(((u32*)dev->buffer)[1]);
_dataResidue = le32_to_cpu(((u32*)dev->buffer)[2]);
_status = dev->buffer[12];
if(signature != CSW_SIGNATURE) {
BUG();
return USBSTORAGE_ESIGNATURE;
}
if(dataResidue != NULL)
*dataResidue = _dataResidue;
if(status != NULL)
*status = _status;
if(tag != dev->tag) return USBSTORAGE_ETAG;
dev->tag++;
return USBSTORAGE_OK;
}
static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue)
{
s32 retval = USBSTORAGE_OK;
u8 status = 0;
u32 dataResidue = 0;
u32 thisLen;
s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
do
{
retries--;
if(retval == USBSTORAGE_ETIMEDOUT)
break;
if(write)
{
retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
if(retval == USBSTORAGE_ETIMEDOUT)
break;
if(retval < 0)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
continue;
}
while(len > 0)
{
thisLen=len;
retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, buffer);
if(retval == USBSTORAGE_ETIMEDOUT)
break;
if(retval < 0)
{
retval = USBSTORAGE_EDATARESIDUE;
break;
}
if(retval != thisLen && len > 0)
{
retval = USBSTORAGE_EDATARESIDUE;
break;
}
len -= retval;
buffer += retval;
}
if(retval < 0)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
continue;
}
}
else
{
retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
if(retval == USBSTORAGE_ETIMEDOUT)
break;
if(retval < 0)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
continue;
}
while(len > 0)
{
thisLen=len;
retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, buffer);
//print_hex_dump_bytes("usbs in:",DUMP_PREFIX_OFFSET,dev->buffer,36);
if(retval < 0)
break;
len -= retval;
buffer += retval;
if(retval != thisLen)
break;
}
if(retval < 0)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
continue;
}
}
retval = __read_csw(dev, &status, &dataResidue);
if(retval == USBSTORAGE_ETIMEDOUT)
break;
if(retval < 0)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
continue;
}
retval = USBSTORAGE_OK;
} while(retval < 0 && retries > 0);
if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT)
{
if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
retval = USBSTORAGE_ETIMEDOUT;
}
if(_status != NULL)
*_status = status;
if(_dataResidue != NULL)
*_dataResidue = dataResidue;
return retval;
}
static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
{
s32 retval;
u8 cmd[16];
u8 *sense= USB_Alloc(SCSI_SENSE_REPLY_SIZE);
u8 status = 0;
memset(cmd, 0, sizeof(cmd));
cmd[0] = SCSI_TEST_UNIT_READY;
retval = __cycle(dev, lun, NULL, 0, cmd, 1, 1, &status, NULL);
if(retval < 0) return retval;
if(status != 0)
{
cmd[0] = SCSI_REQUEST_SENSE;
cmd[1] = lun << 5;
cmd[4] = SCSI_SENSE_REPLY_SIZE;
cmd[5] = 0;
memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL);
if(retval < 0) goto error;
status = sense[2] & 0x0F;
if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR)
retval = USBSTORAGE_ESENSE;
}
error:
USB_Free(sense);
return retval;
}
static s32 __usbstorage_reset(usbstorage_handle *dev)
{
s32 retval;
if(dev->suspended == 1)
{
USB_ResumeDevice(dev->usb_fd);
dev->suspended = 0;
}
/*
retval = ehci_reset_device(dev->usb_fd);
if(retval < 0 && retval != -7004)
goto end;
*/
//debug_printf("usbstorage reset..\n");
retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
/* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
if(retval < 0 && retval != -7004)
goto end;
/* gives device enough time to process the reset */
msleep(10);
//debug_printf("cleat halt on bulk ep..\n");
retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
if(retval < 0)
goto end;
retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
end:
return retval;
}
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd)
{
s32 retval = -1;
u8 conf,*max_lun = NULL;
u32 iConf, iInterface, iEp;
usb_devdesc udd;
usb_configurationdesc *ucd;
usb_interfacedesc *uid;
usb_endpointdesc *ued;
max_lun = USB_Alloc(1);
if(max_lun==NULL) return -ENOMEM;
memset(dev, 0, sizeof(*dev));
dev->tag = TAG_START;
dev->usb_fd = fd;
retval = USB_GetDescriptors(dev->usb_fd, &udd);
if(retval < 0)
{
dbgprintf("USB_GetDescriptors():%d\n", retval );
goto free_and_return;
}
dbgprintf("udd.bNumConfigurations:%u\n", udd.bNumConfigurations );
for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
{
ucd = &udd.configurations[iConf];
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
{
uid = &ucd->interfaces[iInterface];
if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS &&
uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
{
if(uid->bNumEndpoints < 2)
continue;
dev->ep_in = dev->ep_out = 0;
for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
{
ued = &uid->endpoints[iEp];
if(ued->bmAttributes != USB_ENDPOINT_BULK)
continue;
if(ued->bEndpointAddress & USB_ENDPOINT_IN)
{
dev->ep_in = ued->bEndpointAddress;
dbgprintf("%08X:%08X\n", dev->ep_in, ued->bEndpointAddress );
} else {
dev->ep_out = ued->bEndpointAddress;
dbgprintf("%08X:%08X\n", dev->ep_out, ued->bEndpointAddress );
}
}
if(dev->ep_in != 0 && dev->ep_out != 0)
{
dev->configuration = ucd->bConfigurationValue;
dev->interface = uid->bInterfaceNumber;
dev->altInterface = uid->bAlternateSetting;
dbgprintf("%08X:%08X\n", dev->configuration , ucd->bConfigurationValue );
dbgprintf("%08X:%08X\n", dev->interface , uid->bInterfaceNumber );
dbgprintf("%08X:%08X\n", dev->altInterface , uid->bAlternateSetting );
goto found;
}
}
}
}
USB_FreeDescriptors(&udd);
retval = USBSTORAGE_ENOINTERFACE;
goto free_and_return;
found:
USB_FreeDescriptors(&udd);
retval = USBSTORAGE_EINIT;
if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
goto free_and_return;
if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
goto free_and_return;
if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
goto free_and_return;
dev->suspended = 0;
retval = USBStorage_Reset(dev);
if(retval < 0)
goto free_and_return;
retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun);
if(retval < 0)
dev->max_lun = 1;
else
dev->max_lun = *max_lun;
if(retval == USBSTORAGE_ETIMEDOUT)
goto free_and_return;
retval = USBSTORAGE_OK;
if(dev->max_lun == 0)
dev->max_lun++;
/* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
/*
* Some devices (i.e. Iomega Zip100) need this -- apparently
* the bulk pipes get STALLed when the GetMaxLUN request is
* processed. This is, in theory, harmless to all other devices
* (regardless of if they stall or not).
*/
USB_ClearHalt(dev->usb_fd, dev->ep_in);
USB_ClearHalt(dev->usb_fd, dev->ep_out);
dev->buffer = /*USB_Alloc(MAX_TRANSFER_SIZE)*/(u8*)0xFFFE4000;
if(dev->buffer == NULL) retval = -ENOMEM;
else retval = USBSTORAGE_OK;
free_and_return:
if(max_lun!=NULL) USB_Free(max_lun);
if(retval < 0)
{
if(dev->buffer != NULL)
USB_Free(dev->buffer);
memset(dev, 0, sizeof(*dev));
return retval;
}
return 0;
}
s32 USBStorage_Close(usbstorage_handle *dev)
{
if(dev->buffer != NULL)
USB_Free(dev->buffer);
memset(dev, 0, sizeof(*dev));
return 0;
}
s32 USBStorage_Reset(usbstorage_handle *dev)
{
s32 retval;
retval = __usbstorage_reset(dev);
return retval;
}
s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
{
return dev->max_lun;
}
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
{
s32 retval;
if(lun >= dev->max_lun)
return -EINVAL;
retval = __usbstorage_clearerrors(dev, lun);
if(retval < 0)
return retval;
retval = USBStorage_Inquiry(dev, lun);
retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], &dev->n_sector[lun]);
return retval;
}
s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun)
{
s32 retval;
u8 cmd[] = {SCSI_INQUIRY, lun << 5,0,0,36,0};
u8 *response = USB_Alloc(36);
retval = __cycle(dev, lun, response, 36, cmd, 6, 0, NULL, NULL);
//print_hex_dump_bytes("inquiry result:",DUMP_PREFIX_OFFSET,response,36);
USB_Free(response);
return retval;
}
s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
{
s32 retval;
u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
u8 *response = USB_Alloc(8);
u32 val;
retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL);
if(retval >= 0)
{
memcpy(&val, response, 4);
if(n_sectors != NULL)
*n_sectors = be32_to_cpu(val);
memcpy(&val, response + 4, 4);
if(sector_size != NULL)
*sector_size = be32_to_cpu(val);
retval = USBSTORAGE_OK;
}
USB_Free(response);
return retval;
}
s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
{
u8 status = 0;
s32 retval;
u8 cmd[] = {
SCSI_READ_10,
lun << 5,
sector >> 24,
sector >> 16,
sector >> 8,
sector,
0,
n_sectors >> 8,
n_sectors,
0
};
if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
return -EINVAL;
retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL);
if(retval > 0 && status != 0)
retval = USBSTORAGE_ESTATUS;
return retval;
}
s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
{
u8 status = 0;
s32 retval;
u8 cmd[] = {
SCSI_WRITE_10,
lun << 5,
sector >> 24,
sector >> 16,
sector >> 8,
sector,
0,
n_sectors >> 8,
n_sectors,
0
};
if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
return -EINVAL;
retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL);
if(retval > 0 && status != 0)
retval = USBSTORAGE_ESTATUS;
return retval;
}
s32 USBStorage_Suspend(usbstorage_handle *dev)
{
if(dev->suspended == 1)
return USBSTORAGE_OK;
USB_SuspendDevice(dev->usb_fd);
dev->suspended = 1;
return USBSTORAGE_OK;
}
/*
The following is for implementing the ioctl interface inpired by the disc_io.h
as used by libfat
This opens the first lun of the first usbstorage device found.
*/
static usbstorage_handle __usbfd;
static u8 __lun = 0;
static u8 __mounted = 0;
static u16 __vid = 0;
static u16 __pid = 0;
void switchbuf(void)
{
memcpy( (void*)0x080A0000, __usbfd.buffer, CBW_SIZE );
__usbfd.buffer = (u8*)0x080A0000;
}
/* perform 512 time the same read */
s32 USBStorage_Read_Stress(u32 sector, u32 numSectors, void *buffer)
{
s32 retval;
int i;
if(__mounted != 1)
return false;
for(i=0;i<512;i++){
retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
sector+=numSectors;
if(retval == USBSTORAGE_ETIMEDOUT)
{
__mounted = 0;
USBStorage_Close(&__usbfd);
}
if(retval < 0)
return false;
}
return true;
}
// temp function before libfat is available */
s32 USBStorage_Try_Device(struct ehci_device *fd)
{
int maxLun,j,retval;
int ret = USBStorage_Open(&__usbfd, fd);
if( ret < 0)
{
dbgprintf("Could not open USB device:%d\n",ret);
return -EINVAL;
}
maxLun = USBStorage_GetMaxLUN(&__usbfd);
if(maxLun == USBSTORAGE_ETIMEDOUT)
{
dbgprintf("USB device timed out\n");
return -EINVAL;
}
for(j = 0; j < maxLun; j++)
{
retval = USBStorage_MountLUN(&__usbfd, j);
if(retval == USBSTORAGE_ETIMEDOUT)
{
USBStorage_Reset(&__usbfd);
USBStorage_Close(&__usbfd);
break;
}
if(retval < 0)
continue;
__vid=fd->desc.idVendor;
__pid=fd->desc.idProduct;
__mounted = 1;
__lun = j;
return 0;
}
dbgprintf("USB device failed to mount\n");
return -EINVAL;
}
static int ums_init_done = 0;
s32 USBStorage_Init(void)
{
int i;
//debug_printf("usbstorage init %d\n", ums_init_done);
if(ums_init_done)
return 0;
ums_init_done = 1;
for(i = 0;i<ehci->num_port; i++){
struct ehci_device *dev = &ehci->devices[i];
if(dev->id != 0){
USBStorage_Try_Device(dev);
}
}
return 0;
}
s32 USBStorage_Get_Capacity(u32*sector_size)
{
if(__mounted == 1)
{
if(sector_size){
*sector_size = __usbfd.sector_size[__lun];
}
return __usbfd.n_sector[__lun];
}
return 0;
}
s32 USBStorage_Read_Sectors(u32 sector, u32 numSectors, void *buffer)
{
s32 retval;
if(__mounted != 1)
return false;
retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
if(retval == USBSTORAGE_ETIMEDOUT)
{
__mounted = 0;
USBStorage_Close(&__usbfd);
}
if(retval < 0)
return false;
return true;
}
s32 USBStorage_Write_Sectors(u32 sector, u32 numSectors, const void *buffer)
{
s32 retval;
if(__mounted != 1)
return false;
retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
if(retval == USBSTORAGE_ETIMEDOUT)
{
__mounted = 0;
USBStorage_Close(&__usbfd);
}
if(retval < 0)
return false;
return true;
}

74
usbstorage.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef __USBSTORAGE_H__
#define __USBSTORAGE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "ehci.h"
#define USBSTORAGE_OK 0
#define USBSTORAGE_ENOINTERFACE -10000
#define USBSTORAGE_ESENSE -10001
#define USBSTORAGE_ESHORTWRITE -10002
#define USBSTORAGE_ESHORTREAD -10003
#define USBSTORAGE_ESIGNATURE -10004
#define USBSTORAGE_ETAG -10005
#define USBSTORAGE_ESTATUS -10006
#define USBSTORAGE_EDATARESIDUE -10007
#define USBSTORAGE_ETIMEDOUT -ETIMEDOUT
#define USBSTORAGE_EINIT -10009
typedef struct
{
u8 configuration;
u32 interface;
u32 altInterface;
u8 ep_in;
u8 ep_out;
u8 max_lun;
u32 sector_size[16];
u32 n_sector[16];
struct ehci_device * usb_fd;
//mutex_t lock;
//cond_t cond;
s32 retval;
u32 tag;
u8 suspended;
u8 *buffer;
} usbstorage_handle;
s32 USBStorage_Initialize(void);
void switchbuf(void);
s32 USBStorage_Open(usbstorage_handle *dev, struct ehci_device *fd);
s32 USBStorage_Close(usbstorage_handle *dev);
s32 USBStorage_Reset(usbstorage_handle *dev);
s32 USBStorage_GetMaxLUN(usbstorage_handle *dev);
s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun);
s32 USBStorage_Suspend(usbstorage_handle *dev);
s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors);
s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer);
s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer);
s32 USBStorage_Inquiry(usbstorage_handle *dev, u8 lun);
#define DEVICE_TYPE_WII_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B')
s32 USBStorage_Try_Device(struct ehci_device *fd);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __USBSTORAGE_H__ */

204
utils.h Normal file
View File

@ -0,0 +1,204 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include "global.h"
static inline u32 read32(u32 addr)
{
u32 data;
__asm__ volatile ("ldr\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline void write32(u32 addr, u32 data)
{
__asm__ volatile ("str\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline u32 set32(u32 addr, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline u32 clear32(u32 addr, u32 clear)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline u32 mask32(u32 addr, u32 clear, u32 set)
{
u32 data;
__asm__ volatile (
"ldr\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstr\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline u16 read16(u32 addr)
{
u32 data;
__asm__ volatile ("ldrh\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline void write16(u32 addr, u16 data)
{
__asm__ volatile ("strh\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline u16 set16(u32 addr, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline u16 clear16(u32 addr, u16 clear)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline u16 mask16(u32 addr, u16 clear, u16 set)
{
u16 data;
__asm__ volatile (
"ldrh\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrh\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
static inline u8 read8(u32 addr)
{
u32 data;
__asm__ volatile ("ldrb\t%0, [%1]" : "=l" (data) : "l" (addr));
return data;
}
static inline void write8(u32 addr, u8 data)
{
__asm__ volatile ("strb\t%0, [%1]" : : "l" (data), "l" (addr));
}
static inline u8 set8(u32 addr, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set)
);
return data;
}
static inline u8 clear8(u32 addr, u8 clear)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (clear)
);
return data;
}
static inline u8 mask8(u32 addr, u8 clear, u8 set)
{
u8 data;
__asm__ volatile (
"ldrb\t%0, [%1]\n"
"\tbic\t%0, %3\n"
"\torr\t%0, %2\n"
"\tstrb\t%0, [%1]"
: "=&l" (data)
: "l" (addr), "l" (set), "l" (clear)
);
return data;
}
/*
* These functions are guaranteed to copy by reading from src and writing to dst in <n>-bit units
* If size is not aligned, the remaining bytes are not copied
*/
extern void memset32(void *dst, u32 value, u32 size);
extern void memset16(void *dst, u16 value, u32 size);
extern void memset8(void *dst, u8 value, u32 size);
extern void memcpy(void *dst, void *src, u32 size);
//void udelay(u32 d);
void panic(u8 v);
static inline u32 get_cpsr(void)
{
u32 data;
__asm__ volatile ( "mrs\t%0, cpsr" : "=r" (data) );
return data;
}
#define STACK_ALIGN(type, name, cnt, alignment) \
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
(u32)(_al__##name))&((alignment)-1))))
#define swab32(x) ((u32)( \
(((u32)(x) & (u32)0x000000ffUL) << 24) | \
(((u32)(x) & (u32)0x0000ff00UL) << 8) | \
(((u32)(x) & (u32)0x00ff0000UL) >> 8) | \
(((u32)(x) & (u32)0xff000000UL) >> 24)))
#define swab16(x) ((u16)( \
(((u16)(x) & (u16)0x00ffU) << 8) | \
(((u16)(x) & (u16)0xff00U) >> 8)))
#endif

116
utils_asm.S Normal file
View File

@ -0,0 +1,116 @@
/*
mini - a Free Software replacement for the Nintendo/BroadOn IOS.
random utilities
Copyright (C) 2008, 2009 Hector Martin "marcan" <marcan@marcansoft.com>
# This code is licensed to you under the terms of the GNU GPL, version 2;
# see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
.arm
.globl memcpy
.globl memset32
.globl memset16
.globl memset8
.text
memcpy:
cmp r2, #0
bxeq lr
stmfd sp!, {r4-r6}
orr r3, r0, r1
tst r3, #3
bne _unaligned
cmp r2, #0x0F
bls _dwordcopyfast
cmp r2, #0x1F
bls _fastcopy16
stmfd sp!, {r7-r9}
_fastcopy32:
ldmia r1!, {r3-r9,r12}
stmia r0!, {r3-r9,r12}
sub r2, r2, #0x20
cmp r2, #0x1F
bls _done
b _fastcopy32
_done:
ldmfd sp!, {r7-r9}
_fastcopy16:
cmp r2, #0xf
bls _dwordcopyfast
ldmia r1!, {r3-r6}
stmia r0!, {r3-r6}
sub r2, r2, #0x10
b _fastcopy16
_dwordcopyfast:
cmp r2, #3
bls _unaligned
ldr r3, [r1], #4
str r3, [r0], #4
sub r2, r2, #4
b _dwordcopyfast
_unaligned:
cmp r0, #0x1800000
bcs _bytecopy
mov r12, #0xff
_dwordcopy:
cmp r2, #0
beq _done2
mov r6, r0
and r3, r6, #3
ldr r4, [r6,-r3]!
mov r3, r3, lsl #3
rsb r3, r3, #0x18
bic r5, r4, r12, lsl r3
ldrb r4, [r1],#1
orr r4, r5, r4, lsl r3
str r4, [r6]
add r0, r0, #1
sub r2, r2, #1
b _dwordcopy
_bytecopy:
cmp r2, #0
beq _done2
ldrb r3, [r1], #1
strb r3, [r0], #1
sub r2, r2, #1
b _bytecopy
_done2:
ldmfd sp!, {r4-r6}
bx lr
memset32:
bics r2, #3
bxeq lr
1: str r1, [r0] ,#4
subs r2, #4
bne 1b
bx lr
memset16:
bics r2, #1
bxeq lr
1: strh r1, [r0], #2
subs r2, #2
bne 1b
bx lr
memset8:
cmp r2, #0
bxeq lr
1: strb r1, [r0], #1
subs r2, #1
bne 1b
bx lr

442
vsprintf.c Normal file
View File

@ -0,0 +1,442 @@
/*
* linux/lib/vsprintf.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
#include <stdarg.h>
#include "global.h"
#include "string.h"
#include "ff.h"
#include "memory.h"
char * strstr ( const char *str1, const char *str2)
{
char *cp = (char *) str1;
char *s1, *s2;
if ( !*str2 )
return((char *)str1);
while (*cp)
{
s1 = cp;
s2 = (char *) str2;
while ( *s1 && *s2 && !(*s1-*s2) )
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return(NULL);
}
static inline int isdigit(int c)
{
return c >= '0' && c <= '9';
}
static inline int isxdigit(int c)
{
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
static inline int islower(int c)
{
return c >= 'a' && c <= 'z';
}
static inline int toupper(int c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
static int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define do_div(n,base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static char * number(char * str, long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[66];
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type & SPECIAL) {
if (base==8)
*str++ = '0';
else if (base==16) {
*str++ = '0';
*str++ = digits[33];
}
}
if (!(type & LEFT))
while (size-- > 0)
*str++ = c;
while (i < precision--)
*str++ = '0';
while (i-- > 0)
*str++ = tmp[i];
while (size-- > 0)
*str++ = ' ';
return str;
}
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
unsigned long num;
int i, base;
char * str;
const char *s;
int flags; /* flags to number() */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
for(str=buf ; *fmt ; ++fmt)
{
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if (isdigit(*fmt))
field_width = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
field_width = va_arg(args, int);
if (field_width < 0) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if (*fmt == '.') {
++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
/* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
while (--field_width > 0)
*str++ = ' ';
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
continue;
case 's':
s = va_arg(args, char *);
//if (!s)
// s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT))
while (len < field_width--)
*str++ = ' ';
for (i = 0; i < len; ++i)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
continue;
case 'p':
if (field_width == -1) {
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
*str++ = '%';
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
*str++ = '%';
if (*fmt)
*str++ = *fmt;
else
--fmt;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h') {
num = (unsigned short) va_arg(args, int);
if (flags & SIGN)
num = (short) num;
} else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';
return str-buf;
}
int sprintf( char *astr, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = vsprintf(astr, fmt, args);
va_end(args);
return i;
}
#define EXI 0xD806814
void EXISendByte( char byte )
{
loop:
*(vu32*)EXI = 0xD0;
*(vu32*)(EXI+0x10) = 0xB0000000 | (byte<<20);
*(vu32*)(EXI+0x0C) = 0x19;
while( *(vu32*)(EXI+0x0C)&1 );
u32 loop = *(vu32*)(EXI+0x10)&0x4000000;
*(vu32*)EXI = 0;
if( !loop )
goto loop;
return;
}
void GeckoSendBuffer( char *buffer )
{
int i = 0;
while( buffer[i] != '\0' )
{
EXISendByte( buffer[i] );
++i;
}
return;
}
extern FIL Log;
static char buffer[128] ALIGNED(32);
int dbgprintf( const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsprintf(buffer, fmt, args);
va_end(args);
//u32 cokie = read32( 0x0D800070 );
//set32(0x0D800070,1);
if( read32( 0x0D800070 ) & 1 )
{
GeckoSendBuffer( buffer );
}/* else {
u32 read;
u32 fres = f_open( &Log, "/dm.log", FA_READ|FA_WRITE|FA_OPEN_ALWAYS );
if( fres != FR_OK )
{
write32( 0x0D800070, 1 );
dbgprintf("f_open():%d\n", fres );
}
f_lseek( &Log, Log.fsize );
f_write( &Log, buffer, strlen(buffer), &read );
f_close( &Log );
}*/
//write32( 0x0D800070, cokie );
return 1;
}
static char ascii(char s)
{
if(s < 0x20) return '.';
if(s > 0x7E) return '.';
return s;
}
void hexdump(void *d, int len)
{
u8 *data;
int i, off;
data = (u8*)d;
for (off=0; off<len; off += 16) {
dbgprintf("%08x ",off);
for(i=0; i<16; i++)
if((i+off)>=len) dbgprintf(" ");
else dbgprintf("%02x ",data[off+i]);
dbgprintf(" ");
for(i=0; i<16; i++)
if((i+off)>=len) dbgprintf(" ");
else dbgprintf("%c",ascii(data[off+i]));
dbgprintf("\n");
}
}
//void fatal(const char *fmt, ...)
//{
// va_list args;
// char buffer[1024];
// int i;
//
// va_start(args, fmt);
// i = vsprintf(buffer, fmt, args);
// va_end(args);
// OSReport(buffer);
// for (;;);
//}
//

8
vsprintf.h Normal file
View File

@ -0,0 +1,8 @@
#include <stdarg.h>
#include "string.h"
char * strstr ( const char *str1, const char *str2);
int vsprintf(char *buf, const char *fmt, va_list args);
int _sprintf( char *buf, const char *fmt, ... );
int dbgprintf( const char *fmt, ...);
void hexdump(void *d, int len);