- split slot 1 detection from swap_cart (current version is slightly buggy)

- introduce a new hardware detection routine
- introduce a new "argv" test, hoping to weed out more bad implementations
- convert more strings to upcoming translation interface
- some bugfixes
This commit is contained in:
msiewert76@gmail.com 2011-05-06 17:20:21 +00:00
parent 19ccec7d3f
commit 9002997030
14 changed files with 592 additions and 363 deletions

View File

@ -248,10 +248,10 @@ bool auxspi_has_infrared()
void auxspi_erase(bool ir)
{
uint8 type = auxspi_save_type();
uint8 type = auxspi_save_type(ir);
if (type == 3) {
uint8 size;
size = 1 << (auxspi_save_size_log_2() - 16);
size = 1 << (auxspi_save_size_log_2(ir) - 16);
for (int i = 0; i < size; i++) {
if (ir)
auxspi_disable_infrared();
@ -280,10 +280,10 @@ void auxspi_erase(bool ir)
auxspi_close();
}
} else {
int8 size = 1 << max(0, (auxspi_save_size_log_2() - 15));
int8 size = 1 << max(0, (auxspi_save_size_log_2(ir) - 15));
memset(data, 0, 0x8000);
for (int i = 0; i < size; i++) {
auxspi_write_data(i << 15, data, 0x8000, type);
auxspi_write_data(i << 15, data, 0x8000, type, ir);
}
}
}

View File

@ -37,16 +37,11 @@
#include "globals.h"
#include "strings.h"
#include "auxspi_core.inc"
PrintConsole upperScreen;
PrintConsole lowerScreen;
extern uint32 mode;
extern u8 gbatype;
//===========================================================
void displayInit()
@ -68,10 +63,15 @@ void displayInit()
void displayPrintUpper()
{
extern uint32 ezflash;
/*
//extern uint32 ezflash;
extern bool gba;
extern uint32 dstype;
extern bool slot2;
*/
bool gba = (mode == 1);
u32 dstype = (mode == 3) ? 1 : 0;
bool ir = (slot_1_type == 1) ? true : false;
// print upper screen (background)
consoleSelect(&upperScreen);
@ -100,29 +100,9 @@ void displayPrintUpper()
consoleClear();
// fetch cartridge header (maybe, calling "cardReadHeader" on a FC messes with libfat!)
//bool flash_card = is_flash_card();
//bool ir = auxspi_has_infrared();
sNDSHeader nds;
if (slot_1_type != 2)
cardReadHeader((uint8*)&nds);
// search for the correct header
/*
for (int i = 0; i < 0x1000000; i++)
{
char *test = (char*)0x02000000;
if ((test[0]=='C')&&(test[1]=='P')&&(test[2]=='U')&&(test[3]=='D')) {
iprintf("found!");
while(1);
}
test++;
}
*/
//nds = NDS_HEADER;
/*
if (nds.gameTitle[0] == 0xff)
// DSi
nds = NDS_HEADER;
*/
char name[MAXPATHLEN];
// 0) print the mode
@ -158,7 +138,7 @@ void displayPrintUpper()
sprintf(&name[0], "----");
if (slot_1_type == 2) {
sprintf(&name[0], "Flash Card");
} else /*if (nds.gameCode[0])*/ {
} else {
memcpy(&name[0], &nds.gameCode[0], 4);
name[4] = 0x00;
}
@ -170,7 +150,7 @@ void displayPrintUpper()
sprintf(&name[0], "----");
if (slot_1_type == 2) {
sprintf(&name[0], "Flash Card");
} else /*if (nds.gameTitle[0])*/ {
} else {
memcpy(&name[0], &nds.gameTitle[0], 12);
name[12] = 0x00;
}
@ -183,17 +163,17 @@ void displayPrintUpper()
if (slot_1_type == 2) {
sprintf(&name[0], "Flash Card");
} else {
uint8 type = auxspi_save_type();
uint32 size = auxspi_save_size();
uint8 type = auxspi_save_type(ir);
uint8 size = auxspi_save_size_log_2(ir);
switch (type) {
case 1:
sprintf(&name[0], "Eeprom (%i Bytes)", size);
break;
case 2:
sprintf(&name[0], "FRAM (%i kB)", size >> 10);
sprintf(&name[0], "FRAM (%i kB)", 1 << (size - 10));
break;
case 3:
sprintf(&name[0], "Flash (%i kB)", size >> 10);
sprintf(&name[0], "Flash (%i kB)", 1 << (size - 10));
break;
default:
sprintf(&name[0], "unknown");
@ -207,7 +187,6 @@ void displayPrintUpper()
consoleSetWindow(&upperScreen, 10, 5, 22, 1);
consoleClear();
memset(&name[0], 0, MAXPATHLEN);
//if (auxspi_has_infrared()) {
if (slot_1_type == 1) {
sprintf(&name[0], "Infrared");
} else {
@ -260,18 +239,18 @@ void displayPrintUpper()
if (ezflash)
sprintf(name, "SRAM");
else if (gba) {
u8 type = gbatype;
saveTypeGBA type = GetSlot2SaveType(CART_GBA_GAME);
u8 size = gbaGetSaveSizeLog2(type);
switch (type) {
case 1:
case 2:
case SAVE_GBA_EEPROM_05:
case SAVE_GBA_EEPROM_8:
sprintf(name, "EEPROM (%i bytes)", 1 << size);
break;
case 3:
case SAVE_GBA_SRAM_32:
sprintf(name, "SRAM (%i kB)", 1 << (size - 10));
break;
case 4:
case 5:
case SAVE_GBA_FLASH_64:
case SAVE_GBA_FLASH_128:
sprintf(name, "Flash (%i kB)", 1 << (size - 10));
break;
default:
@ -292,7 +271,8 @@ void displayPrintUpper()
if (ezflash)
sprintf(name, "NOR + PSRAM");
else if (gba)
sprintf(name, "(unsupported)");
// TODO: test for RTC, add function for syncing RTC?
sprintf(name, "???");
else if (slot2)
sprintf(name, "----");
else if (dstype == 0)
@ -416,6 +396,9 @@ void displayProgressBar(int cur, int max0)
}
buffer[31] = ']';
buffer[32] = 0;
if (max0 == 0)
buffer[0] = 0;
iprintf("%s", buffer);
}

View File

@ -31,11 +31,7 @@
bool isDsi()
{
#define SCFG_MODE (*(vu8*)0x4004000)
if(SCFG_MODE)
return (REG_DSIMODE != 0) ? true : false;
return false;
return (REG_DSIMODE != 0) ? true : false;
}
bool dsiUnlockSlot1()

View File

@ -78,11 +78,11 @@ void ftpGetFileList(const char *dir, netbuf *ctrl, int &num)
}
}
void fileGetFileList(const char *dir, int num)
void fileGetFileList(const char *dir, int &num)
{
char *buf = (char*)data;
int idx = 0;
memset(buf, 0, 0x8000);
memset(buf, 0, size_buf);
DIR *pdir;
struct dirent *pent;
@ -96,7 +96,7 @@ void fileGetFileList(const char *dir, int num)
stat(fullname, &statbuf);
// TODO: check for buffer overflow!
if (idx + strlen(pent->d_name) < 0x8000-2) {
if (idx + strlen(pent->d_name) < size_buf-2) {
if (S_ISDIR(statbuf.st_mode)) {
int len = sprintf(buf, "d%s\n", pent->d_name);
buf += len;
@ -178,6 +178,10 @@ void fileSelect(const char *startdir, char *out_dir, char *out_fname, netbuf *bu
ftpGetFileList("/", buf, num_files);
else
fileGetFileList(startdir, num_files);
if (num_files == 0) {
displayMessage("ERROR");
while(1);
}
filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
while (!select) {

View File

@ -44,6 +44,7 @@
#include "dsCard.h"
#include "display.h"
#include "globals.h"
inline u32 min(u32 i, u32 j) { return (i < j) ? i : j;}
inline u32 max(u32 i, u32 j) { return (i > j) ? i : j;}
@ -158,7 +159,7 @@ uint8 gbaGetSaveType()
for (int i = 0; i < (0x02000000 >> 2); i++, data++) {
if (*data == MAGIC_EEPR) {
// 2 versions: 512 bytes / 8 kB
return 1; // TODO: Try to figure out how to ID the 512 bytes version... hard way? write/restore!
return 2; // TODO: Try to figure out how to ID the 512 bytes version... hard way? write/restore!
}
if (*data == MAGIC_SRAM) {
// *always* 32 kB
@ -205,21 +206,24 @@ uint32 gbaGetSaveSize(uint8 type)
}
// local function
//#define E_DEBUG
void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false)
{
// waitstates
//*(volatile unsigned short *)0x04000204 = 0x4317;
#ifdef E_DEBUG
char txt[64];
#endif
// TODO: this still does not work... figure out somehow how to do it right!
// waitstates - this is what Rudolph uses...
*(volatile unsigned short *)0x04000204 = 0x4317;
// maximal length of the buffer
u16 buf[68];
// "read" command
// Prepare a "read" command.
u16 length;
// raw command
buf[0] = 1;
buf[1] = 1;
// write address
// address
if (short_addr) {
length = 9;
buf[2] = addr >> 5;
buf[3] = addr >> 4;
buf[4] = addr >> 3;
@ -227,49 +231,8 @@ void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false)
buf[6] = addr >> 1;
buf[7] = addr;
buf[8] = 0;
#if 1
// does not work
char txt[512];
sprintf(txt, "EXMEMCNT = %x", REG_EXMEMCNT);
sysSetBusOwners(true, true);
displayMessage(txt);
//u32 ime = enterCriticalSection();
// EXMEMCNT: 0..1: long sram wait state (18/8) - set to "2", i.e. not the slowest
// EXMEMCNT: 2..3: long ROM wait state (18/8)
REG_EXMEMCNT |= 15;
REG_EXMEMCNT &= ~(1 << 4);
// EXMEMCNT: ~4: 6 waitstates on 2nd access (should be 18 as well, but that's no option!)
dmaCopy((u16*)&buf[0], (u32*)0x09ffff00, 9<<1);
while (*(u16*)0x040000dc != 0);
dmaCopy((u32*)0x09ffff00, (u16*)&buf[0], 68<<1);
while (*(u16*)0x040000dc != 0);
//leaveCriticalSection(ime);
#endif
#if 0
// TEST
//u32 ime = enterCriticalSection();
REG_EXMEMCNT |= 3;
u32 ie = REG_IE;
REG_IE = 1 << 11; // DMA3 only
dmaCopy((u16*)&buf[0], (u32*)0x09ffff00, 9 << 1);
REG_EXMEMCNT |= 3;
dmaCopy((u32*)0x09ffff00, (u16*)&buf[0], 68 << 1);
REG_IE = ie;
//leaveCriticalSection(ime);
#endif
#if 0
#define EEPROM *(u16*)0x0dffff00
for (int i = 0; i < 9; i++) {
EEPROM = buf[i];
swiDelay(10);
}
swiDelay(100);
for (int i = 0; i < 68; i++) {
buf[i] = EEPROM;
swiDelay(10);
}
#endif
} else {
length = 17;
buf[2] = addr >> 13;
buf[3] = addr >> 12;
buf[4] = addr >> 11;
@ -285,54 +248,159 @@ void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false)
buf[14] = addr >> 1;
buf[15] = addr;
buf[16] = 0;
dmaCopy((u16*)&buf[0], (u32*)0x09000000, 17);
dmaCopy((u32*)0x09000000, (u16*)&buf[0], 68);
}
// Extract data (there is only one *bit* per halfword!)
u16 *in_pos = &buf[4];
u8 *out_pos = out;
u8 out_byte;
for(s8 byte = 7; byte >= 0; --byte )
{
out_byte = 0;
for(s8 bit = 7; bit >= 0; --bit )
{
#ifdef E_DEBUG
static u32 eeprom = 0x09ffff00;
// send command to eeprom
displayPrintState("Sending command");
// commenting this out or not does not have any impact on the EEPROM device. Therefore,
// the following command does not "make" it to the hardware!
DC_FlushRange(&buf[0], sizeof(buf));
DMA_SRC(3) = (uint32)&buf[0];
DMA_DEST(3) = (uint32)eeprom;
// there is a bit for eeprom access, but it only seems to freeze the transfer!?
//DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | length; // this bit is expanding to "3 bits"
//DMA_CR(3) = DMA_COPY_HALFWORDS | length;
DMA_CR(3) = DMA_COPY_HALFWORDS | (6 << 27) | length;
while(DMA_CR(3) & DMA_BUSY);
//while ((*(u16*)0x09ffff00 & 1) == 0);
// get answer from eeprom
displayPrintState("listening");
DC_FlushRange(&buf[0], sizeof(buf));
DMA_SRC(3) = (uint32)eeprom;
DMA_DEST(3) = (uint32)&buf[0];
// there is a bit for eeprom access, but it only seems to freeze the transfer!?
//DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | 68; // this bit is expanding to "3 bits"
//DMA_CR(3) = DMA_COPY_HALFWORDS | 68;
DMA_CR(3) = DMA_COPY_HALFWORDS | (6 << 27) | 68;
while(DMA_CR(3) & DMA_BUSY);
//while ((*(u16*)0x09ffff00 & 1) == 0);
/*
sprintf(txt, "byte: %i, Bit: %i, Val: %x", byte, bit, *in_pos);
displayPrintState(txt);
*/
// Extract data (there is only one *bit* per halfword!)
u16 *in_pos = &buf[4];
u8 *out_pos = out;
u8 out_byte;
for(s8 byte = 7; byte >= 0; --byte )
{
out_byte = 0;
for(s8 bit = 7; bit >= 0; --bit )
{
out_byte += ((*in_pos++)&1)<<bit;
}
*out_pos++ = out_byte;
}
*/
// let us study what the hardware *does* give us!
for (u8 i = 0; i < 8; i++)
*out++ = buf[i+4];
}
// local function
void gbaEepromWrite8Bytes(u8 *out, u32 addr, bool short_addr = false)
{
// TODO: this still does not work... figure out somehow how to do it right!
// don't do anything unless we know what we are doing!
#if 0
// waitstates - this is what Rudolph uses...
*(volatile unsigned short *)0x04000204 = 0x4317;
// maximal length of the buffer
u16 buf[68];
// Prepare a "read" command.
u16 length;
// raw command
buf[0] = 1;
buf[1] = 1;
// address
if (short_addr) {
length = 9;
buf[2] = addr >> 5;
buf[3] = addr >> 4;
buf[4] = addr >> 3;
buf[5] = addr >> 2;
buf[6] = addr >> 1;
buf[7] = addr;
buf[8] = 0;
} else {
length = 17;
buf[2] = addr >> 13;
buf[3] = addr >> 12;
buf[4] = addr >> 11;
buf[5] = addr >> 10;
buf[6] = addr >> 9;
buf[7] = addr >> 8;
buf[8] = addr >> 7;
buf[9] = addr >> 6;
buf[10] = addr >> 5;
buf[11] = addr >> 4;
buf[12] = addr >> 3;
buf[13] = addr >> 2;
buf[14] = addr >> 1;
buf[15] = addr;
buf[16] = 0;
}
// send command to eeprom
displayPrintState("Sending command");
static u32 eeprom = 0x09ffff00;
DMA_SRC(3) = (uint32)&buf[0];
DMA_DEST(3) = (uint32)eeprom;
// there is a bit for eeprom access, but it only seems to freeze the transfer!?
//DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | length;
DMA_CR(3) = DMA_COPY_HALFWORDS | length;
while(DMA_CR(3) & DMA_BUSY);
// get answer from eeprom
displayPrintState("listening");
DMA_SRC(3) = (uint32)eeprom;
DMA_DEST(3) = (uint32)&buf[0];
// there is a bit for eeprom access, but it only seems to freeze the transfer!?
DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | 68;
//DMA_CR(3) = DMA_COPY_HALFWORDS | 68;
while(DMA_CR(3) & DMA_BUSY);
// Extract data (there is only one *bit* per halfword!)
// TODO: convert this to write format
u16 *in_pos = &buf[4];
u8 *out_pos = out;
u8 out_byte;
for(s8 byte = 7; byte >= 0; --byte )
{
out_byte = 0;
for(s8 bit = 7; bit >= 0; --bit )
{
out_byte += ((*in_pos++)&1)<<bit;
}
*out_pos++ = out_byte;
}
#endif
out_byte += ((*in_pos++)&1)<<bit;
}
*out_pos++ = out_byte ;
}
displayPrintState("Exit!");
}
bool gbaReadSave(u8 *dst, u8 src, u32 len, u8 type)
{
int nbanks = 2; // for type 4,5
bool eeprom_long = true;
switch (type) {
case 1: {
// FIXME: this does not work yet...
eeprom_long = false;
}
case 2: {
int start, end;
start = src >> 3;
end = (src + len - 1) >> 3;
u8 *tmp = (u8*)malloc((end-start+1) << 3);
u8 *ptr = tmp;
displayPrintState("Reading from Eeprom...");
for (int j = start; j <= end; j++, ptr+=8) {
gbaEepromRead8Bytes(ptr, j, true);
gbaEepromRead8Bytes(ptr, j, eeprom_long);
}
memcpy(dst, tmp, len);
free(tmp);
displayPrintState("Done!");
break;
}
case 2: {
break;
}
case 3: {
@ -345,10 +413,9 @@ bool gbaReadSave(u8 *dst, u8 src, u32 len, u8 type)
break;
}
case 4:
// FLASH - must be opend by register magic, then blind copy
nbanks = 1;
case 5:
// FLASH - must be opend by register magic, then blind copy
nbanks = 2;
for (int j = 0; j < nbanks; j++) {
// we need to wait a few cycles before the hardware reacts!
*(u8*)0x0a005555 = 0xaa;
@ -396,7 +463,7 @@ bool gbaIsAtmel()
*(u8*)0x0a005555 = 0xf0; // leave ID mode
swiDelay(10);
//
char txt[128];
//char txt[128];
sprintf(txt, "Man: %x, Dev: %x", man, dev);
displayPrintState(txt);
if ((man == 0x3d) && (dev == 0x1f))
@ -408,12 +475,25 @@ bool gbaIsAtmel()
bool gbaWriteSave(u8 *dst, u8 src, u32 len, u8 type)
{
int nbanks = 2; // for type 4,5
bool eeprom_long = true;
switch (type) {
case 1:
case 2:
// TODO: how does eeprom work?
case 1: {
eeprom_long = false;
}
case 2: {
int start, end;
start = src >> 3;
end = (src + len - 1) >> 3;
u8 *tmp = (u8*)malloc((end-start+1) << 3);
u8 *ptr = tmp;
for (int j = start; j <= end; j++, ptr+=8) {
gbaEepromWrite8Bytes(ptr, j, eeprom_long);
}
memcpy(dst, tmp, len);
free(tmp);
break;
}
case 3: {
// SRAM: blind write
u32 start = 0x0a000000 + src;
@ -521,4 +601,5 @@ bool gbaFormatSave(u8 type)
swiDelay(10);
break;
}
return true;
}

View File

@ -37,11 +37,11 @@ enum cartTypeGBA {
enum saveTypeGBA {
SAVE_GBA_NONE = 0,
SAVE_GBA_EEPROM_05 = 0x00010001, // 512 bytes
SAVE_GBA_EEPROM_8 = 0x00010002, // 8k
SAVE_GBA_SRAM_32 = 0x00020001, // 32k
SAVE_GBA_FLASH_64 = 0x00040001, // 64k
SAVE_GBA_FLASH_128 = 0x00040002 // 128k
SAVE_GBA_EEPROM_05, // 512 bytes
SAVE_GBA_EEPROM_8, // 8k
SAVE_GBA_SRAM_32, // 32k
SAVE_GBA_FLASH_64, // 64k
SAVE_GBA_FLASH_128 // 128k
};
struct dataSlot2 {

View File

@ -35,4 +35,13 @@ char ftp_user[64] = "ftp_user";
char ftp_pass[64] = "ftp_pass";
int ftp_port = 0;
int ir_delay = 1000;
int ir_delay = 1200;
char device[16] = "/";
char txt[256] = "";
u32 mode = 0;
u32 ezflash = 0;
int slot2 = 0;

View File

@ -40,4 +40,15 @@ extern int ftp_port;
extern int ir_delay;
// all libfat access will be using this device. default value = "/", i.e. "default" DLDI device
extern char device[16];
// text buffer for composing various messages
extern char txt[256];
extern u32 mode;
extern u32 ezflash;
extern int slot2;
#endif // GLOBALS_H

View File

@ -25,6 +25,8 @@
*/
#include <nds.h>
#include <fat.h>
#include <nds/interrupts.h>
#include <nds/arm9/console.h>
#include <sys/dir.h>
@ -47,6 +49,7 @@
#include "auxspi.h"
#include "strings.h"
#include "dsi.h"
using namespace std;
@ -54,6 +57,7 @@ static u32 pitch = 0x40000;
// ---------------------------------------------------------------------
// FIXME: after the slot 1 detection was factored out, swap_cart no longer has perfect accuracy!
bool swap_cart()
{
sNDSHeader nds;
@ -67,9 +71,12 @@ bool swap_cart()
if (keysCurrent() & KEY_A) {
// identify hardware
slot_1_type = get_slot1_type();
// don't try to dump a flash card
if (slot_1_type == 2)
continue;
sysSetBusOwners(true, true);
// this will break DLDI on the Cyclops Evolution, but we need it anyway.
cardReadHeader((u8*)&nds);
//flash_card = false;
displayPrintUpper();
if (!nds.gameTitle[0])
continue;
@ -84,16 +91,21 @@ bool swap_cart()
u32 get_slot1_type()
{
u8 size1 = auxspi_save_size_log_2(false);
sysSetBusOwners(true, true);
// Trying to read the save size in IR mode will fail on non-IR devices.
// If we have success, it is an IR device.
u8 size2 = auxspi_save_size_log_2(true);
if (size2 > 0)
return 1;
if (size1 == size2)
return 2; // flash card
// It is not an IR game, so maybe it is a regular game.
u8 size1 = auxspi_save_size_log_2(false);
if (size1 > 0)
return 0;
if ((size1 == 0) && (size2 != 0))
return 1; // ir device
return 0; // regular game
// No save size test returned a save chip, so it must be a flash card.
return 2;
}
bool swap_card_game(uint32 size)
@ -101,12 +113,74 @@ bool swap_card_game(uint32 size)
return false;
}
// This function is called on boot; it detects the hardware configuration and selects the mode.
u32 hwDetect()
{
// Identify Slot 1 devide. This is used by pretty much everything.
slot_1_type = get_slot1_type();
// First, look for a DSi running in DSi mode.
if (isDsi()) {
size_buf = 1 << 23; // 8 MB memory buffer
return 3;
}
size_buf = 1 << 21; // 2 MB memory buffer
// Identify Slot 2 device.
// First, look for an EZFlash 3in1
uint32 ime = enterCriticalSection();
sysSetBusOwners(true, true);
OpenNorWrite();
ezflash = ReadNorFlashID();
CloseNorWrite();
leaveCriticalSection(ime);
chip_reset();
if (ezflash)
return 2;
// Okay, maybe it is a regular GBA game instead
if (gbaIsGame())
return 1;
// Maybe it is a Slot 2 flash card.
// Detecting slot 2 flash cards is very evil:
// - They don't usually support argv, so we can't simply test that we are
// running from "fat2".
// - We need a passme compatible slot 1 device, i.e. we can't verify that
// there is a flash card in slot 1 (which usually is).
// - There is only a limited number of Slot 2 flash cards on the market, so
// we could test for this (I think there is a library for this). But if we
// boot from Slot 1, a positive Slot 2 test does not mean that we did boot
// from there - the card may be sitting there unused!
//
// --> So we select slot 2 mode the "dumb" way - with an ini parameter. Unless you swap
// the same microSD card between Slot 1 and Slot 2, this should be the safest mode.
// (If you know a smarter way of doing this, feel free to commit a patch!)
//
if (slot2)
return 4;
// Try to identify download play mode. This also introduces various complications:
// - The latest libnds versions include code for the SD-slot on the DSi. It does not work
// from flash cards or download play, but it may still result in a positive DLDI driver
// initialisation. So we can't simply run "fatInitDefault" and test return values.
// - Currently, download play mode aims to "insert game first, then run dlp", i.e.
// it does not support hotswapping the game. So we select this mode if there is *no*
// flash card inserted in Slot 1.
//
if (slot_1_type != 2)
return 5;
// Nothing unique found, so enter WiFi mode
return 0;
}
// --------------------------------------------------------
void hwFormatNor(uint32 page, uint32 count)
{
uint32 ime = hwGrab3in1();
SetSerialMode();
//displayPrintState("Formating NOR memory");
displayProgressBar(0, count);
for (uint32 i = page; i < page+count; i++) {
Block_Erase(i << 18);
@ -139,9 +213,10 @@ void hwBackup3in1()
swap_cart();
displayPrintUpper();
uint8 size = auxspi_save_size_log_2();
bool ir = (slot_1_type == 1) ? true : false;
uint8 size = auxspi_save_size_log_2(ir);
int size_blocks = 1 << max(0, (int8(size) - 18)); // ... in units of 0x40000 bytes - that's 256 kB
uint8 type = auxspi_save_type();
uint8 type = auxspi_save_type(ir);
displayMessage2A(STR_HW_3IN1_FORMAT_NOR, false);
hwFormatNor(0, size_blocks+1);
@ -152,26 +227,27 @@ void hwBackup3in1()
else
size_blocks = 1 << (uint8(size) - 15);
u8 *test = (u8*)malloc(0x8000);
if (test == NULL)
while(1);
u32 LEN = min(1 << size, 0x8000);
for (int i = 0; i < size_blocks; i++) {
displayProgressBar(i+1, size_blocks);
auxspi_read_data(i << 15, data, LEN, type);
auxspi_read_data(i << 15, data, LEN, type, ir);
uint32 ime = hwGrab3in1();
SetSerialMode();
WriteNorFlash((i << 15) + pitch, data, LEN);
hwRelease3in1(ime);
for (int j = 0; j < 4; j++) {
uint32 ime = hwGrab3in1();
ReadNorFlash(test, (i << 15) + pitch, LEN);
hwRelease3in1(ime);
}
// test if NOR memory is sane, i.e. if we can read what we just wrote
ime = hwGrab3in1();
ReadNorFlash(test, (i << 15) + pitch, LEN);
hwRelease3in1(ime);
if (*((vuint16 *)(FlashBase+0x2002)) == 0x227E) {
displayMessage("ERROR: ID mode active!");
displayMessage2A(STR_HW_3IN1_ERR_IDMODE, false);
while(1);
}
if (memcmp(test, data, LEN)) {
displayMessage("ERROR: verifying NOR failed");
displayMessage2A(STR_HW_3IN1_ERR_NOR, false);
while(1);
}
}
@ -201,13 +277,6 @@ void hwBackup3in1()
displayMessage2A(STR_HW_3IN1_PLEASE_REBOOT, false);
ime = hwGrab3in1();
ReadNorFlash((u8*)&data2, 0x1000, sizeof(data2)); // this should work - but it does not!
hwRelease3in1(ime);
char txt[128];
sprintf(txt, "%.12s", &data2.name[0]);
displayMessage(txt);
while(1) {};
}
@ -220,10 +289,12 @@ void hwDump3in1(uint32 size, const char *gamename)
char path[256];
char fname[256] = "";
fileSelect("/", path, fname, 0, true, false);
// look for an unused filename
if (!fname[0]) {
uint32 cnt = 0;
sprintf(fname, "/%s.%i.sav", gamename, cnt);
char txt[256];
//char txt[256];
sprintf(txt, stringsGetMessageString(STR_HW_SEEK_UNUSED_FNAME), fname);
displayMessage2(txt, false);
while (fileExists(fname)) {
@ -238,7 +309,6 @@ void hwDump3in1(uint32 size, const char *gamename)
}
char fullpath[256];
sprintf(fullpath, "%s/%s", path, fname);
char txt[512];
sprintf(txt, stringsGetMessageString(STR_HW_3IN1_DUMP), fullpath);
displayMessage2(txt, false);
@ -259,7 +329,7 @@ void hwDump3in1(uint32 size, const char *gamename)
sprintf(txt, stringsGetMessageString(STR_HW_3IN1_DONE_DUMP), fullpath);
displayMessage2(txt, false);
while (1);
while (!(keysCurrent() & KEY_B)) {};
}
void hwRestore3in1()
@ -270,6 +340,7 @@ void hwRestore3in1()
displayMessageA(STR_HW_SELECT_FILE); // lower screen is used for file browser
fileSelect("/", path, fname, 0, false, false);
char msg[256];
// This does not have to be translated.
sprintf(msg, "%s/%s", path, fname);
displayMessage(msg);
@ -303,13 +374,11 @@ void hwRestore3in1()
ReadNorFlash(test, (i << 15) + pitch, LEN);
hwRelease3in1(ime);
if (*((vuint16 *)(FlashBase+0x2002)) == 0x227E) {
displayMessage("ERROR: ID mode active!");
displayMessage2A(STR_HW_3IN1_ERR_IDMODE, false);
while(1);
}
if (int err = memcmp(test, data, LEN)) {
char txt[128];
sprintf(txt, "ERROR: NOR %x/%x: %x -> %x", abs(err), LEN, data[err], test[err]);
displayMessage(txt);
if (memcmp(test, data, LEN)) {
displayMessage2A(STR_HW_3IN1_ERR_NOR, false);
while(1);
}
}
@ -317,25 +386,30 @@ void hwRestore3in1()
fclose(file);
free(test);
hwRestore3in1_b(size);
hwRestore3in1_b(1 << size);
}
void hwRestore3in1_b(uint32 size_file)
{
bool ir = (slot_1_type == 1) ? true : false;
// Third, swap in a new game
uint32 size = auxspi_save_size_log_2();
uint32 size = auxspi_save_size_log_2(ir);
while ((size_file < size) || (slot_1_type == 2)) {
// TODO: make THIS error message more meaningful!
displayPrintState("File too small or no save chip!");
if (slot_1_type == 2)
displayMessage2A(STR_HW_SWAP_CARD, false);
else if (size_file < size)
displayMessage2A(STR_HW_WRONG_GAME, false);
swap_cart();
size = auxspi_save_size_log_2();
ir = (slot_1_type == 1) ? true : false;
size = auxspi_save_size_log_2(ir);
}
displayPrintUpper();
uint8 type = auxspi_save_type();
uint8 type = auxspi_save_type(ir);
if (type == 3) {
displayMessage2A(STR_HW_FORMAT_GAME, false);
auxspi_erase();
auxspi_erase(ir);
}
// And finally, write the save!
@ -363,7 +437,7 @@ void hwRestore3in1_b(uint32 size_file)
uint32 ime = hwGrab3in1();
ReadNorFlash(data, (i << shift) + pitch, LEN);
hwRelease3in1(ime);
auxspi_write_data(i << shift, data, LEN, type);
auxspi_write_data(i << shift, data, LEN, type, ir);
}
displayProgressBar(1, 1);
@ -375,11 +449,10 @@ void hwRestore3in1_b(uint32 size_file)
// ------------------------------------------------------------
void hwErase()
{
bool ir = (slot_1_type == 1) ? true : false;
displayMessage2A(STR_HW_WARN_DELETE, true);
while (!(keysCurrent() & (KEY_UP | KEY_R | KEY_Y))) {};
auxspi_erase();
displayMessage2A(STR_HW_DID_DELETE, true);
while(1);
auxspi_erase(ir);
}
// ------------------------------------------------------------
@ -388,44 +461,45 @@ void hwBackupFTP(bool dlp)
netbuf *buf, *ndata;
int j;
static int jmax = 10;
bool ir = (slot_1_type == 1) ? true : false;
// Dump save and write it to FTP server
// First: swap card
if (!dlp)
swap_cart();
displayPrintUpper();
uint8 size = auxspi_save_size_log_2();
uint8 size = auxspi_save_size_log_2(ir);
int size_blocks = 1 << max(0, (int8(size) - 18)); // ... in units of 0x40000 bytes - that's 256 kB
uint8 type = auxspi_save_type();
uint8 type = auxspi_save_type(ir);
if (size < 15)
size_blocks = 1;
else
size_blocks = 1 << (uint8(size) - 15);
// Second: connect to FTP server
displayPrintState("FTP: connecting to AP");
displayMessage2A(STR_HW_FTP_SEEK_AP, false);
if (!Wifi_InitDefault(true)) {
displayPrintState("FTP: ERROR: AP not found");
displayMessage2A(STR_HW_FTP_ERR_AP, true);
while(1);
}
displayPrintState("FTP: connecting to FTP server");
displayMessage2A(STR_HW_FTP_SEEK_FTP, false);
char fullname[512];
sprintf(fullname, "%s:%i", ftp_ip, ftp_port);
j = 0;
while (!FtpConnect(fullname, &buf)) {
j++;
if (j >= jmax) {
displayPrintState("FTP: ERROR: FTP server missing");
displayMessage2A(STR_HW_FTP_ERR_FTP, true);
while(1);
}
swiDelay(10000);
}
displayPrintState("FTP: login");
displayMessage2A(STR_HW_FTP_LOGIN, false);
j = 0;
while (!FtpLogin(ftp_user, ftp_pass, buf)) {
j++;
if (j >= jmax) {
displayPrintState("FTP: ERROR: login failed");
displayMessage2A(STR_HW_FTP_ERR_LOGIN, true);
while(1);
}
swiDelay(10000);
@ -435,7 +509,7 @@ void hwBackupFTP(bool dlp)
char fname[256] ="";
memset(fname, 0, 256);
displayMessageA(STR_HW_SELECT_FILE_OW);
displayPrintState("FTP: dir");
displayPrintState("FTP: dir"); // TODO: translate me!
fileSelect("/", fdir, fname, buf, true, false);
bool newfile;
if (!fname[0])
@ -452,7 +526,6 @@ void hwBackupFTP(bool dlp)
int tsize = 0;
sprintf(fname, "%.12s.%i.sav", nds.gameTitle, cnt);
while (FtpSize(fname, &tsize, FTPLIB_IMAGE, buf) != 0) {
char txt[256];
sprintf(txt, stringsGetMessageString(STR_HW_SEEK_UNUSED_FNAME), fname);
displayMessage2(txt, false);
if (cnt < 65536)
@ -462,13 +535,13 @@ void hwBackupFTP(bool dlp)
while(1);
}
sprintf(fname, "%.12s.%i.sav", nds.gameTitle, cnt);
displayPrintState(fname);
}
}
// Fourth: dump save
displayPrintState("");
sprintf(fullname, "Writing file:\n%s%s", fdir, fname);
// This may not have to be translated.
sprintf(fullname, "%s%s", fdir, fname);
displayMessage(fullname);
FtpAccess(fname, FTPLIB_FILE_WRITE, FTPLIB_IMAGE, buf, &ndata);
u32 length = 0x200;
@ -476,19 +549,18 @@ void hwBackupFTP(bool dlp)
length = 1 << size;
for (int i = 0; i < (1 << (size - 9)); i++) {
displayProgressBar(i+1, (size_blocks << 6));
auxspi_read_data(i << 9, (u8*)&data[0], length, type);
int out = 0;
while (out < 512) {
out += FtpWrite((u8*)&data[out], 512-out, ndata);
if (out < 512) {
auxspi_read_data(i << 9, (u8*)&data[0], length, type, ir);
u32 out = 0;
while (out < length) {
u32 delta = FtpWrite((u8*)&data[out], length-out, ndata);
out += delta;
if (delta == 0) {
displayMessage2A(STR_HW_FTP_READ_ONLY, false);
} else {
displayMessage2("", false);
}
if (delta < length) {
displayPrintState(stringsGetMessageString(STR_HW_FTP_SLOW));
/*
debug++;
if (debug >= 2048) {
debug = 0;
displayMessage2("Unable to reach FTP server. Make sure that you have WRITE ACCESS!"
}
*/
} else {
displayPrintState("");
}
@ -500,7 +572,7 @@ void hwBackupFTP(bool dlp)
Wifi_DisconnectAP();
if (dlp) {
displayMessage("Done! Please turn off your DS.");
displayMessage2A(STR_HW_PLEASE_REBOOT, false);
while(1);
}
}
@ -510,32 +582,33 @@ void hwRestoreFTP(bool dlp)
netbuf *buf, *ndata;
int j;
static int jmax = 10;
bool ir = (slot_1_type == 1) ? true : false;
// Dump save and write it to FTP server
// First: connect to FTP server
displayPrintState("FTP: connecting to AP");
displayMessage2A(STR_HW_FTP_SEEK_AP, false);
if (!Wifi_InitDefault(true)) {
displayPrintState("FTP: ERROR: AP not found");
displayMessage2A(STR_HW_FTP_ERR_AP, true);
while(1);
}
displayPrintState("FTP: connecting to FTP server");
displayMessage2A(STR_HW_FTP_SEEK_FTP, false);
char fullname[512];
sprintf(fullname, "%s:%i", ftp_ip, ftp_port);
j = 0;
while (!FtpConnect(fullname, &buf)) {
j++;
if (j >= jmax) {
displayPrintState("FTP: ERROR: FTP server missing");
displayMessage2A(STR_HW_FTP_ERR_FTP, true);
while(1);
}
swiDelay(10000);
}
displayPrintState("FTP: login");
displayMessage2A(STR_HW_FTP_LOGIN, false);
j = 0;
while (!FtpLogin(ftp_user, ftp_pass, buf)) {
j++;
if (j >= jmax) {
displayPrintState("FTP: ERROR: login failed");
displayMessage2A(STR_HW_FTP_ERR_LOGIN, false);
while(1);
}
swiDelay(10000);
@ -545,21 +618,21 @@ void hwRestoreFTP(bool dlp)
char fdir[256] = "";
char fname[256] ="";
memset(fname, 0, 256);
displayMessage("Please select a file name to\nrestore.");
displayMessageA(STR_HW_SELECT_FILE);
displayPrintState("FTP: dir");
fileSelect("/", fdir, fname, buf, true, false);
fileSelect("/", fdir, fname, buf, false, false);
// Third: swap card
if (!dlp)
swap_cart();
displayPrintUpper();
uint8 size = auxspi_save_size_log_2();
uint8 type = auxspi_save_type();
uint8 size = auxspi_save_size_log_2(ir);
uint8 type = auxspi_save_type(ir);
// Fourth: read file
displayPrintState("");
FtpChdir(fdir, buf);
sprintf(fullname, "Reading file:\n%s%s", fdir, fname);
sprintf(fullname, "%s%s", fdir, fname);
displayMessage(fullname);
u32 LEN = 0, num_blocks = 0, shift = 0;
switch (type) {
@ -591,8 +664,9 @@ void hwRestoreFTP(bool dlp)
#endif
}
if ((type == 3) && (insecure)) {
displayPrintState("Formating Flash chip");
auxspi_erase();
displayMessage2A(STR_HW_FORMAT_GAME, false);
//displayPrintState("Formating Flash chip");
auxspi_erase(ir);
}
FtpAccess(fname, FTPLIB_FILE_READ, FTPLIB_IMAGE, buf, &ndata);
u8 *pdata = data;
@ -606,36 +680,26 @@ void hwRestoreFTP(bool dlp)
else
displayPrintState("");
}
/*
int out;
if ((out = FtpRead((u8*)pdata, 512, ndata)) < 512) {
char dings[512];
sprintf(dings, "Error: requested 512, got %i", out);
displayPrintState(dings);
while(1);
}
*/
// does not fit into memory: insecure mode
// does not fit into memory: unsafe mode
// TODO: reactivate this!
if (insecure) {
//char bums[512];
//sprintf(bums, "addr = %x", (i << 9)+(j << shift));
displayPrintState("Writing save (insecure!)");
for (int j = 0; j < 1 << (9-shift); j++) {
auxspi_write_data((i << 9)+(j << shift), ((u8*)pdata)+(j<<shift), LEN, type);
auxspi_write_data((i << 9)+(j << shift), ((u8*)pdata)+(j<<shift), LEN, type, ir);
}
}
pdata += 512;
}
// Write to game (safe mode)
if (!insecure) {
displayMessage("Got file, now writing to game");
if (type == 3) {
displayPrintState("Formating Flash chip");
auxspi_erase();
displayMessage2A(STR_HW_FORMAT_GAME, false);
auxspi_erase(ir);
}
for (int i = 0; i < (1 << (size - shift)); i++) {
displayPrintState("Writing save");
displayMessage2A(STR_HW_WRITE_GAME, false);
displayProgressBar(i+1, 1 << (size - shift));
auxspi_write_data(i << shift, ((u8*)data)+(i<<shift), LEN, type);
auxspi_write_data(i << shift, ((u8*)data)+(i<<shift), LEN, type, ir);
}
}
FtpClose(ndata);
@ -644,7 +708,7 @@ void hwRestoreFTP(bool dlp)
Wifi_DisconnectAP();
if (dlp) {
displayMessage("Done! Please turn off your DS.");
displayMessage2A(STR_HW_PLEASE_REBOOT, false);
while(1);
}
}
@ -656,22 +720,26 @@ void hwBackupGBA(u8 type)
return;
if ((type == 1) || (type == 2)) {
// This is not to be translated, it will be removed at some point.
displayMessage("I can't read this save type\nyet. Please use Rudolphs tool\ninstead.");
return;
}
char path[256];
char fname[256] = "";
char *gamename = (char*)0x080000a0;
fileSelect("/", path, fname, 0, true, false);
// look for an unused filename
if (!fname[0]) {
uint32 cnt = 0;
sprintf(fname, "/%.12s.%i.sav", gamename, cnt);
sprintf(txt, stringsGetMessageString(STR_HW_SEEK_UNUSED_FNAME), fname);
displayMessage2(txt, false);
while (fileExists(fname)) {
if (cnt < 65536)
cnt++;
else {
displayMessage("Unable to get a filename!\nThis means that you have more\nthan 65536 saves! (wow!)\nOops!");
displayMessage2A(STR_ERR_NO_FNAME, true);
while(1);
}
sprintf(fname, "/%.12s.%i.sav", gamename, cnt);
@ -681,11 +749,11 @@ void hwBackupGBA(u8 type)
sprintf(fullpath, "%s/%s", path, fname);
displayMessage(fname);
displayPrintState("Reading save from game");
displayMessage2A(STR_HW_GBA_READ, false);
uint32 size = gbaGetSaveSize(type);
gbaReadSave(data, 0, size, type);
displayPrintState("Writing save to flash card");
displayMessage2A(STR_HW_GBA_DUMP, false);
FILE *file = fopen(fullpath, "wb");
fwrite(data, 1, size, file);
fclose(file);
@ -701,6 +769,7 @@ void hwRestoreGBA()
return;
if ((type == 1) || (type == 2)) {
// This is not to be translated, it will be removed at some point.
displayMessage("I can't write this save type\nyet. Please use Rudolphs tool\ninstead.");
return;
}
@ -712,22 +781,23 @@ void hwRestoreGBA()
fileSelect("/", path, fname, 0);
char fullpath[512];
sprintf(fullpath, "%s/%s", path, fname);
displayMessage(fname);
//displayMessage(fname);
displayPrintState("Reading save from flash card");
sprintf(txt, stringsGetMessageString(STR_HW_GBA_LOAD), fname);
displayMessage2A(STR_HW_GBA_LOAD, false);
FILE *file = fopen(fullpath, "rb");
fread(data, 1, size, file);
fclose(file);
if ((type == 4) || (type == 5)) {
displayPrintState("Deleting old save.");
displayMessage2A(STR_HW_FORMAT_GAME, false);
gbaFormatSave(type);
}
displayPrintState("Writing save to game");
displayMessage2A(STR_HW_WRITE_GAME, false);
gbaWriteSave(data, 0, size, type);
displayPrintState("Done!");
displayMessage2A(STR_HW_PLEASE_REBOOT, false);
while(1);
}

View File

@ -47,7 +47,17 @@ void do_restore_nds_save();
bool swap_cart();
u32 get_slot1_type();
//bool is_flash_card();
// This function was previously found in the main function.
// Return values:
// 0 - no special configuration, WiFi mode
// 1 - GBA game in Slot 2
// 2 - EZFlash 3in1 in Slot 2
// 3 - running in DSi mode
// 4 - running from Slot 2 flash card
// 5 - running from download play or another exploit that does not need a flash card in Slot 1
//
u32 hwDetect();
void hwBackup3in1();
void hwDump3in1(uint32 size, const char *gamename);

View File

@ -53,13 +53,6 @@
using std::max;
uint32 ezflash = 0;
uint32 dstype = 0;
bool gba = 0;
uint32 mode = 0;
bool slot2 = false;
u8 gbatype = 0;
char bootdir[256] = "/";
@ -73,10 +66,9 @@ void mode_dsi()
displayPrintUpper();
displayPrintLower();
// DSi mode, does nothing at the moment
displayPrintState("DSi mode - still unsupported!");
while (1);
displayMessage2A(STR_BOOT_MODE_UNSUPPORTED,true);
while(1);
touchPosition touchXY;
while(1) {
@ -109,7 +101,7 @@ void mode_slot2()
displayPrintUpper();
displayPrintLower();
displayMessage("This mode is DISABLED.\nPlease remove Slot-2 module\nand restart this tool.");
displayMessage2A(STR_BOOT_MODE_UNSUPPORTED,true);
while(1);
touchPosition touchXY;
@ -140,7 +132,6 @@ void mode_slot2()
void mode_3in1()
{
displayPrintUpper();
displayPrintLower();
dsCardData data2;
uint32 ime = hwGrab3in1();
@ -156,6 +147,9 @@ void mode_3in1()
hwFormatNor(0, 1); // clear reboot flag
hwDump3in1(size, name);
}
displayMessage("");
displayProgressBar(0,0);
displayPrintLower();
touchPosition touchXY;
while(1) {
@ -184,6 +178,10 @@ void mode_3in1()
void mode_gba()
{
// This function takes some time, since it needs to parse the entire GBA module
// for a magic string. It is only called when truly necessary. (i.e. once for now)
u8 gbatype = gbaGetSaveType();
// use 3in1 to buffer data
displayPrintState("");
gbatype = gbaGetSaveType();
@ -251,7 +249,7 @@ void mode_wifi()
void mode_dlp()
{
// use 3in1 to buffer data
// use non-flash card based exploits (download play or Sudoku?). untested, and does not work yet!
displayPrintState("");
displayPrintUpper();
displayPrintLower();
@ -275,45 +273,30 @@ void mode_dlp()
if ((touchXY.py > 8*16) && (touchXY.py < 8*24)) {
displayPrintUpper();
hwErase();
displayMessage("Done! Please turn off your DS.");
displayMessage2A(STR_HW_DID_DELETE, true);
while(1);
}
}
}
int main(int argc, char* argv[])
bool loadIniFile(char* path)
{
sysSetBusOwners(true, true);
// Init the screens
displayInit();
// Init DLDI (file system driver)
// TODO: find some way to skip this when loading from a different exploit/download play/not a flash card
int fat = fatInitDefault();
if (fat == 0) {
displayPrintState("DLDI error\n");
while (1) {};
}
// test if our flash card supports argv at all. some R4 clones seem to be very picky!
// (untested due to lack of an R4 myself, but I hope it works)
bool has_argv = false;
if (argc)
has_argv = true;
// Don't try to load ini file in DLP mode, we need to get our options from a different source.
// Still trying to figure something out...
if (mode == 5)
return true;
ini_fd_t ini = 0;
// load ini file...
ini_fd_t ini = 0;
char inipath[256];
if (has_argv) {
if (argv[0]) {
char *last = strrchr(argv[0], '/');
int len = (last - argv[0])+1;
strncpy(bootdir, argv[0], len);
sprintf(inipath, "%s/savegame_manager.ini", bootdir);
if (fileExists(inipath))
ini = ini_open(inipath, "r", "");
}
if (path) {
char *last = strrchr(path, '/');
int len = (last - path)+1;
strncpy(bootdir, path, len);
sprintf(inipath, "%s/savegame_manager.ini", bootdir);
if (fileExists(inipath))
ini = ini_open(inipath, "r", "");
}
if (!ini) {
sprintf(inipath, "/savegame_manager.ini");
@ -321,8 +304,8 @@ int main(int argc, char* argv[])
ini = ini_open(inipath, "r", "");
}
if (!ini) {
displayMessage("Unable to open ini file!\nPlease make sure that it is\n1. in this apps folder, or"
"\n2. in the root folder\nIf 1. does not work, use 2.");
// FIXME
displayMessage2A(STR_BOOT_NO_INI,true);
while (1);
}
@ -335,77 +318,116 @@ int main(int argc, char* argv[])
ini_readString(ini, ftp_pass, 64);
ini_locateKey(ini, "ftp_port");
ini_readInt(ini, &ftp_port);
ini_locateKey(ini, "ir_delay");
ini_locateKey(ini, "ir_delay");
ini_readInt(ini, &ir_delay);
ir_delay = max(ir_delay, 1000);
ini_locateKey(ini, "slot2");
ini_readInt(ini, &slot2);
ini_close(ini);
// delete temp file (which is a remnant of inilib)
remove("/tmpfile");
return true;
}
// This is a new attempt to reliably identify if the flash card has argv support or not,
// including R4 clones which may have *bad* argv support.
bool has_argv(int argc, char* argv[])
{
// no argv support
if (argc == 0)
return false;
// bad argv support: if argc is larger than unity, your flash card can't even do
// a proper negative indicator. let us test for 2 argv arguments, just to be safe.
if (argc > 2)
return false;
/*
// test if argv[0] pointer is valid (scan main memory and WRAM)
if ((argv[0] < 0x02000000) || (argv[0] >= 0x04000000))
return false;
*/
// test if argv[0] contains a valid string
char *arg0 = argv[0];
// test for possible "/path", "fat*:/path" and "sd:/*".
if (*arg0 == 'f')
if (strncasecmp(argv[0], "fat:/", 5) || strncasecmp(argv[0], "fat1:/", 6)
|| strncasecmp(argv[0], "fat2:/", 6))
return true;
if (*arg0 == 's')
if (strncasecmp(argv[0], "sd:/", 4))
return true;
if (*arg0 == '/')
return true;
return false;
}
int main(int argc, char* argv[])
{
sysSetBusOwners(true, true);
// Init the screens
displayInit();
// detect hardware
mode = hwDetect();
// Init DLDI (file system driver), skip for mode == 4,5 which already calls this during
// hardware initialisation
if (mode < 4) {
int fat = fatInitDefault();
if (fat == 0) {
displayMessage2A(STR_BOOT_DLDI_ERROR,true);
while (1);
}
}
// Load the ini file with the FTP settings and more options
if (has_argv(argc, argv))
loadIniFile(argv[0]);
else
loadIniFile(0);
// prepare the global data buffer
data = (u8*)malloc(size_buf);
// This should not be required, but better safe than sorry. On the DS, it *might* be
// possible that no continuous 2 MB are available.
if (data == NULL) {
size_buf >>= 1;
data = (u8*)malloc(size_buf);
}
// load strings
stringsLoadFile(0);
// Identify hardware and branch to corresponding mode
//displayMessage("Identifying hardware...");
// 1) Identify DSi (i.e. memory capacity)
//displayPrintState("ID: DS model");
if (isDsi()) {
dstype = 1;
size_buf = 1 << 23; // 8 MB
} else {
dstype = 0;
size_buf = 1 << 21; // 2 MB
//size_buf = 1 << 14; // 32 kB - TESTING ONLY!
}
data = (u8*)malloc(size_buf);
// is there a game card in slot-1? if so, we have been starten with download-play or a new exploit
slot_1_type = get_slot1_type();
// don't try to identify Slot-2 in DSi mode.
if (dstype == 0) {
//displayPrintState("ID: Slot 2");
uint32 ime = enterCriticalSection();
sysSetBusOwners(true, true);
OpenNorWrite();
ezflash = ReadNorFlashID();
CloseNorWrite();
leaveCriticalSection(ime);
chip_reset();
gba = gbaIsGame();
}
// Try to identify slot-2 device. Try opening slot-2 root directory
if (argv[0][3] == '2')
slot2 = true;
// okay, we got our HW identified; now branch to the corresponding main function/event handler
if (slot_1_type != 2) {
// running from download play, NOR, or a different exploit. enter dlp mode.
mode = 5;
mode_dlp();
} else if (dstype == 1) {
// DSi/DSiXL, branch to SD-card mode when cracked.
mode = 3;
mode_dsi();
} else if (slot2) {
mode = 4;
mode_slot2();
} else if (ezflash != 0) {
// DS with EZFlash found -> branch to 3in1 mode
mode = 2;
mode_3in1();
} else if (gba) {
// GBA game in slot 2 -> branch to GBA mode
mode = 1;
mode_gba();
} else {
// failsafe: enter WiFi mode
mode = 0;
mode_wifi();
switch (mode) {
case 1:
mode_gba();
break;
case 2:
mode_3in1();
break;
case 3:
mode_dsi();
break;
case 4:
mode_slot2();
break;
case 5:
mode_dlp();
break;
default:
mode_wifi();
}
return 0;

View File

@ -31,12 +31,13 @@
#include "libini.h"
#include <nds.h>
#include "fileselect.h"
#include "globals.h"
using namespace std;
// a global string array
char **message_strings;
char txt[512];
//char txt[512];
#define ADD_STRING(id,text) strcpy(txt,text);\
message_strings[id] = new char[strlen(txt)+1];\
@ -59,7 +60,7 @@ bool stringsLoadFile(const char *fname)
message_strings = new char*[STR_LAST];
#ifndef NOT_FINISHED
ini_locateHeading(ini, "");
char txt[512];
//char txt[512];
for (int i = 0; i < STR_LAST; i++) {
sprintf(txt, "%i", i);
ini_locateKey(ini, txt);
@ -71,7 +72,14 @@ bool stringsLoadFile(const char *fname)
// delete temp file (which is a remnant of inilib)
remove("/tmpfile");
#else
ADD_STRING(STR_BOOT_NO_INI,"Unable to open ini file!\nPlease make sure that it is\n1. in this apps folder, or"
"\n2. in the root folder\nIf 1. does not work, use 2.");
ADD_STRING(STR_BOOT_MODE_UNSUPPORTED,"This mode is DISABLED.\nPlease restart the system.");
ADD_STRING(STR_BOOT_DLDI_ERROR,"DLDI initialisation error!");
//
ADD_STRING(STR_HW_SWAP_CARD,"Please take out Slot 1\nflash card and insert a game\n\nPress A when done.");
ADD_STRING(STR_HW_WRONG_GAME,"This game has a save chip\nthat is smaller than the\nsave you are going to\nwrite. Please insert a\ndifferent game.\n\nPress A when done.");
ADD_STRING(STR_HW_PLEASE_REBOOT,"Done! Please power off\n(and restart if you want\nto do more).");
//
ADD_STRING(STR_HW_SELECT_FILE,"Please select a .sav file.");
ADD_STRING(STR_HW_SELECT_FILE_OW,"Please select a file to\noverwrite, or press L+R in afolder to create a new file.");
@ -87,10 +95,25 @@ bool stringsLoadFile(const char *fname)
ADD_STRING(STR_HW_3IN1_PLEASE_REBOOT,"Save has been written to\nthe 3in1. Please power off\nand restart this tool.");
ADD_STRING(STR_HW_3IN1_CLEAR_FLAG,"Preparing to dump your\nsave... Please wait...");
ADD_STRING(STR_HW_3IN1_DUMP,"Dumping the save from the\n3in1 to your flash card.\nFilename:\n%s");
ADD_STRING(STR_HW_3IN1_DONE_DUMP,"Done. Your game save has\nbeen dumped using your\n3in1. Filename:\n%s\n\nPlease restart your DS.");
ADD_STRING(STR_HW_3IN1_DONE_DUMP,"Done. Your game save has\nbeen dumped using your\n3in1. Filename:\n%s\n\nPress (B) to continue.");
ADD_STRING(STR_HW_3IN1_RESTORE,"Done. Your game save has\nbeen restored using your\n3in1.\n\nPlease restart your DS.");
ADD_STRING(STR_HW_3IN1_ERR_IDMODE,"ERROR!\nID mode still active!");
ADD_STRING(STR_HW_3IN1_ERR_NOR,"ERROR!\nNOR memory seems to be\ndamaged!");
//
ADD_STRING(STR_HW_FTP_SEEK_AP,"Connecting to an access\npoint...\n\nplease wait...");
ADD_STRING(STR_HW_FTP_ERR_AP,"ERROR!\nCould not find a compatible\nAccess Point. Please config\nyour WiFi Connection from\na WiFi-enabled game!");
ADD_STRING(STR_HW_FTP_SEEK_FTP,"Connecting to an FTP\nserver...\n\nplease wait...");
ADD_STRING(STR_HW_FTP_ERR_FTP,"ERROR!\nCould not find an FTP\nserver. Please refer to\nthe documentation.");
ADD_STRING(STR_HW_FTP_LOGIN,"Logging in...");
ADD_STRING(STR_HW_FTP_ERR_LOGIN,"ERROR!\nCould not log in to the\nFTP server. Please verify\nyour username and password\nare correct in your\nini file.");
ADD_STRING(STR_HW_FTP_DIR,"Reading FTP directory...");
ADD_STRING(STR_HW_FTP_SLOW,"FTP is slow, please wait...");
ADD_STRING(STR_HW_FTP_READ_ONLY,"WARNING: could not write to\nyour FTP server! Maybe you\nforgot to enable write\naccess?");
//
ADD_STRING(STR_HW_GBA_READ,"Reading save from your game.Please wait...");
ADD_STRING(STR_HW_GBA_DUMP,"Writing save to flash card.\nPlease wait...");
ADD_STRING(STR_HW_GBA_LOAD,"Reading save from your\nflash card. Filename:\n%s\n\nPlease wait...");
ADD_STRING(STR_HW_GBA_RESTORE,"Restoring save to your game\n\nPlease wait...");
//
ADD_STRING(STR_HW_WARN_DELETE,"This will WIPE OUT your\nentire save! ARE YOU SURE?\n\nPress R+up+Y to confim!");
ADD_STRING(STR_HW_DID_DELETE,"Done. Your game save has\nbeen PERMANENTLY deleted.\n\nPlease restart your DS.");

View File

@ -32,8 +32,13 @@
enum {
STR_TITLE_MSG,
STR_BOOT_NO_INI,
STR_BOOT_MODE_UNSUPPORTED,
STR_BOOT_DLDI_ERROR,
//
STR_HW_SWAP_CARD,
STR_HW_WRONG_GAME,
STR_HW_PLEASE_REBOOT,
//
STR_HW_SELECT_FILE,
STR_HW_SELECT_FILE_OW,
@ -51,8 +56,23 @@ enum {
STR_HW_3IN1_DUMP,
STR_HW_3IN1_DONE_DUMP,
STR_HW_3IN1_RESTORE,
STR_HW_3IN1_ERR_IDMODE,
STR_HW_3IN1_ERR_NOR,
//
STR_HW_FTP_SEEK_AP,
STR_HW_FTP_ERR_AP,
STR_HW_FTP_SEEK_FTP,
STR_HW_FTP_ERR_FTP,
STR_HW_FTP_LOGIN,
STR_HW_FTP_ERR_LOGIN,
STR_HW_FTP_DIR,
STR_HW_FTP_SLOW,
STR_HW_FTP_READ_ONLY,
//
STR_HW_GBA_READ,
STR_HW_GBA_DUMP,
STR_HW_GBA_LOAD,
STR_HW_GBA_RESTORE,
//
STR_HW_WARN_DELETE,
STR_HW_DID_DELETE,

View File

@ -1 +1 @@
<pd><ViewState><e p="Savegame Manager\arm7" x="true"></e><e p="Savegame Manager\arm9" x="true"></e><e p="Savegame Manager" x="true"></e><e p="Savegame Manager\arm7\build" x="false"></e><e p="Savegame Manager\arm7\source" x="true"></e><e p="Savegame Manager\arm9\build" x="false"></e><e p="Savegame Manager\arm9\source" x="true"></e></ViewState></pd>
<pd><ViewState><e p="Savegame Manager\arm7" x="false"></e><e p="Savegame Manager\arm9" x="true"></e><e p="Savegame Manager" x="true"></e><e p="Savegame Manager\arm9\build" x="false"></e><e p="Savegame Manager\arm9\source" x="true"></e></ViewState></pd>