NAND Emulation:

- Fixed Nand Emulation from SD-card.
- Fixed "CheckSave" functions.
- Fixed feature to flash a save file from emulated NAND back to real NAND.
- Some minor code cleanups and bug fixes.

neek2o: (neek2o r93+ only)
- Fixed return to channel function for titles on emulated NAND
- Added an option in wiiflow.ini: launchwiiflow in "NEEK2O" domain
  If this option is set to "no" the "exit to" option in home menu 
  will launch neek2o SM instead of the "DWFA" channel.
- If the return to channel option is set.. neek2o will return to 
  that specific title if that title exists on the emulated nand, even
  if the title was launched from real NAND.
This commit is contained in:
overjoy.psm 2012-09-09 22:38:42 +00:00
parent 4e345b651f
commit 37787dbcd9
17 changed files with 118 additions and 77 deletions

View File

@ -119,10 +119,13 @@ s32 Nand::Nand_Unmount(NandDevice *Device)
s32 Nand::Nand_Enable(NandDevice *Device) s32 Nand::Nand_Enable(NandDevice *Device)
{ {
gprintf("Enabling NAND Emulator\n"); gprintf("Enabling NAND Emulator...");
s32 fd = IOS_Open("/dev/fs", 0); s32 fd = IOS_Open("/dev/fs", 0);
if(fd < 0) if(fd < 0)
{
gprintf(" failed!\n");
return fd; return fd;
}
int NandPathlen = strlen(NandPath) + 1; int NandPathlen = strlen(NandPath) + 1;
@ -138,6 +141,7 @@ s32 Nand::Nand_Enable(NandDevice *Device)
s32 ret = IOS_Ioctlv(fd, 100, 2, 0, vector); s32 ret = IOS_Ioctlv(fd, 100, 2, 0, vector);
IOS_Close(fd); IOS_Close(fd);
gprintf(" %s!\n", ret < 0 ? "failed" : "OK");
return ret; return ret;
} }
@ -192,6 +196,11 @@ s32 Nand::Disable_Emu()
return 0; return 0;
} }
bool Nand::EmulationEnabled(void)
{
return emu_enabled;
}
void Nand::Set_NandPath(string path) void Nand::Set_NandPath(string path)
{ {
if(isalnum(*(path.begin()))) if(isalnum(*(path.begin())))

View File

@ -61,6 +61,7 @@ public:
void Init(string path, u32 partition, bool disable = false); void Init(string path, u32 partition, bool disable = false);
s32 Enable_Emu(); s32 Enable_Emu();
s32 Disable_Emu(); s32 Disable_Emu();
bool EmulationEnabled(void);
void Set_Partition(u32 partition) { Partition = partition; }; void Set_Partition(u32 partition) { Partition = partition; };
void Set_FullMode(bool fullmode) { FullMode = fullmode ? 0x100 : 0; }; void Set_FullMode(bool fullmode) { FullMode = fullmode ? 0x100 : 0; };

View File

@ -429,3 +429,11 @@ bool DeviceHandler::UsablePartitionMounted()
} }
return false; return false;
} }
bool DeviceHandler::PartitionUsableForNandEmu(int Partition)
{
if(IsInserted(Partition) && GetFSType(Partition) == PART_FS_FAT)
return true;
return false;
}

View File

@ -86,6 +86,7 @@ class DeviceHandler
bool USB0_Inserted() { if(usb0) return usb0->IsInserted(); return false; } bool USB0_Inserted() { if(usb0) return usb0->IsInserted(); return false; }
bool USB1_Inserted() { if(usb1) return usb1->IsInserted(); return false; } bool USB1_Inserted() { if(usb1) return usb1->IsInserted(); return false; }
bool UsablePartitionMounted(); bool UsablePartitionMounted();
bool PartitionUsableForNandEmu(int Partition);
void WaitForDevice(const DISC_INTERFACE *Handle); void WaitForDevice(const DISC_INTERFACE *Handle);
void UnMountSD() { if(sd) delete sd; sd = NULL; } void UnMountSD() { if(sd) delete sd; sd = NULL; }

View File

@ -123,9 +123,8 @@ void CachedList::LoadChannels(string path, u32 channelType, string m_lastLanguag
//gprintf("%s\n", m_database.c_str()); //gprintf("%s\n", m_database.c_str());
struct stat filestat, cache; struct stat filestat, cache;
string newpath = sfmt("%s%s", path.c_str(), "title"); /*** Removed that stupid check overhere! ***/
/*** Will replace it soon with something better!! ***/
if(stat(newpath.c_str(), &filestat) == -1) return;
m_update = force_update[COVERFLOW_CHANNEL] || m_lastLanguage != m_curLanguage || stat(m_database.c_str(), &cache) == -1 || filestat.st_mtime > cache.st_mtime; m_update = force_update[COVERFLOW_CHANNEL] || m_lastLanguage != m_curLanguage || stat(m_database.c_str(), &cache) == -1 || filestat.st_mtime > cache.st_mtime;
} }

View File

@ -413,6 +413,7 @@ void CList<dir_discHdr>::GetChannels(vector<dir_discHdr> &headerlist, string set
} }
u32 count = m_channels.Count(); u32 count = m_channels.Count();
gprintf("PFFF: Channel count: %d\n", count);
headerlist.reserve(count); headerlist.reserve(count);

View File

@ -77,7 +77,7 @@ bool Load_Neek2o_Kernel()
return false; return false;
} }
s32 Launch_nk(u64 TitleID, const char *nandpath) s32 Launch_nk(u64 TitleID, const char *nandpath, u64 ReturnTo)
{ {
if(neek2o()) if(neek2o())
{ {
@ -93,7 +93,13 @@ s32 Launch_nk(u64 TitleID, const char *nandpath)
return 0; return 0;
memset(MC, 0, sizeof(memcfg)); memset(MC, 0, sizeof(memcfg));
MC->magic = 0x666c6f77; MC->magic = 0x666c6f77;
if(TitleID)
MC->titleid = TitleID; MC->titleid = TitleID;
if(ReturnTo)
{
MC->returnto = ReturnTo;
MC->config |= NCON_EXT_RETURN_TO;
}
if(nandpath != NULL) if(nandpath != NULL)
{ {

View File

@ -5,6 +5,8 @@ enum ExtNANDCfg
{ {
NCON_EXT_DI_PATH = (1<<0), NCON_EXT_DI_PATH = (1<<0),
NCON_EXT_NAND_PATH = (1<<1), NCON_EXT_NAND_PATH = (1<<1),
NCON_HIDE_EXT_PATH = (1<<2),
NCON_EXT_RETURN_TO = (1<<3),
}; };
typedef struct _memcfg typedef struct _memcfg
@ -12,10 +14,9 @@ typedef struct _memcfg
u32 magic; u32 magic;
u64 titleid; u64 titleid;
u32 config; u32 config;
u64 returnto;
u32 paddinga; u32 paddinga;
u32 paddingb; u32 paddingb;
u32 paddingc;
u32 paddingd;
char dipath[256]; char dipath[256];
char nandpath[256]; char nandpath[256];
} memcfg; } memcfg;
@ -24,7 +25,7 @@ typedef struct _memcfg
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
s32 Launch_nk(u64 TitleID, const char *nandpath); s32 Launch_nk(u64 TitleID, const char *nandpath, u64 ReturnTo);
bool Load_Neek2o_Kernel(); bool Load_Neek2o_Kernel();
bool neek2o(void); bool neek2o(void);

View File

@ -108,8 +108,10 @@ void Sys_Exit(void)
/* Shutdown Inputs */ /* Shutdown Inputs */
Close_Inputs(); Close_Inputs();
WII_Initialize(); WII_Initialize();
if(ExitOption == EXIT_TO_NEEK2O) if(ExitOption == EXIT_TO_WFNK2O)
Launch_nk(0x1000144574641LL, NeekPath); Launch_nk(0x1000144574641LL, NeekPath, 0);
else if(ExitOption == EXIT_TO_SMNK2O)
Launch_nk(0, NeekPath, 0);
else if(ExitOption == EXIT_TO_BOOTMII) else if(ExitOption == EXIT_TO_BOOTMII)
IOS_ReloadIOS(0xfe); IOS_ReloadIOS(0xfe);
else if(ExitOption == EXIT_TO_HBC) else if(ExitOption == EXIT_TO_HBC)

View File

@ -22,7 +22,8 @@ enum
EXIT_TO_PRIILOADER, EXIT_TO_PRIILOADER,
EXIT_TO_DISABLE, EXIT_TO_DISABLE,
EXIT_TO_BOOTMII, EXIT_TO_BOOTMII,
EXIT_TO_NEEK2O, EXIT_TO_WFNK2O,
EXIT_TO_SMNK2O,
BUTTON_CALLBACK, BUTTON_CALLBACK,
}; };

View File

@ -275,7 +275,7 @@ void CMenu::init(void)
m_DMLgameDir = sfmt("%%s:/%s", m_cfg.getString("DML", "dir_usb_games", "games").c_str()); m_DMLgameDir = sfmt("%%s:/%s", m_cfg.getString("DML", "dir_usb_games", "games").c_str());
m_cfg.getString("NAND", "path", ""); m_cfg.getString("NAND", "path", "");
m_cfg.getInt("NAND", "partition", 0); m_cfg.getInt("NAND", "partition", 1);
m_cfg.getBool("NAND", "disable", true); m_cfg.getBool("NAND", "disable", true);
_installed_cios.clear(); _installed_cios.clear();
@ -2052,13 +2052,16 @@ const wstringEx CMenu::_fmt(const char *key, const wchar_t *def)
bool CMenu::_loadChannelList(void) bool CMenu::_loadChannelList(void)
{ {
string emuPath; string emuPath;
int emuPartition = -1;
m_partRequest = m_cfg.getInt("NAND", "partition", 0);
int emuPartition = _FindEmuPart(&emuPath, m_partRequest, false);
bool disable_emu = (m_cfg.getBool("NAND", "disable", true) || neek2o()); bool disable_emu = (m_cfg.getBool("NAND", "disable", true) || neek2o());
static bool last_emu_state = disable_emu; static bool last_emu_state = disable_emu;
if(!disable_emu)
{
m_partRequest = m_cfg.getInt("NAND", "partition", 1);
emuPartition = _FindEmuPart(&emuPath, m_partRequest, false);
if(emuPartition < 0) if(emuPartition < 0)
emuPartition = _FindEmuPart(&emuPath, m_partRequest, true); emuPartition = _FindEmuPart(&emuPath, m_partRequest, true);
@ -2066,13 +2069,16 @@ bool CMenu::_loadChannelList(void)
return false; return false;
else else
currentPartition = emuPartition; currentPartition = emuPartition;
}
static u8 lastPartition = currentPartition; static u8 lastPartition = currentPartition;
static bool first = true; static bool first = true;
static bool failed = false;
bool changed = lastPartition != currentPartition || last_emu_state != disable_emu || first || failed; bool changed = lastPartition != currentPartition || last_emu_state != disable_emu || first;
if(changed)
UpdateCache(COVERFLOW_CHANNEL);
gprintf("%s, which is %s\n", disable_emu ? "NAND" : DeviceName[emuPartition], changed ? "refreshing." : "cached."); gprintf("%s, which is %s\n", disable_emu ? "NAND" : DeviceName[emuPartition], changed ? "refreshing." : "cached.");
@ -2096,19 +2102,15 @@ bool CMenu::_loadChannelList(void)
Nand::Instance()->Init(emuPath.c_str(), currentPartition, disable_emu); Nand::Instance()->Init(emuPath.c_str(), currentPartition, disable_emu);
if(Nand::Instance()->Enable_Emu() < 0) if(Nand::Instance()->Enable_Emu() < 0)
{
Nand::Instance()->Disable_Emu(); Nand::Instance()->Disable_Emu();
failed = true;
} gprintf("Using path: \"%s\" for NAND emulation\n", nandpath.c_str());
else
failed = false;
gprintf("nandpath = %s\n", nandpath.c_str());
} }
if(!DeviceHandler::Instance()->IsInserted(currentPartition)) if(!DeviceHandler::Instance()->IsInserted(currentPartition))
DeviceHandler::Instance()->Mount(currentPartition); DeviceHandler::Instance()->Mount(currentPartition);
if(!failed) if(Nand::Instance()->EmulationEnabled() || disable_emu)
{ {
m_gameList.LoadChannels(disable_emu ? "" : nandpath, 0, m_cfg.getString("NAND", "lastlanguage", "EN").c_str()); m_gameList.LoadChannels(disable_emu ? "" : nandpath, 0, m_cfg.getString("NAND", "lastlanguage", "EN").c_str());
m_cfg.setString("NAND", "lastlanguage", m_loc.getString(m_curLanguage, "gametdb_code", "EN")); m_cfg.setString("NAND", "lastlanguage", m_loc.getString(m_curLanguage, "gametdb_code", "EN"));

View File

@ -1083,13 +1083,19 @@ void CMenu::_launchChannel(dir_discHdr *hdr)
error(_t("errneek1", L"Cannot launch neek2o. Verify your neek2o setup")); error(_t("errneek1", L"Cannot launch neek2o. Verify your neek2o setup"));
Sys_Exit(); Sys_Exit();
} }
int rtrnID = 0;
if(rtrn != NULL && strlen(rtrn) == 4)
rtrnID = rtrn[0] << 24 | rtrn[1] << 16 | rtrn[2] << 8 | rtrn[3];
ShutdownBeforeExit(); ShutdownBeforeExit();
Launch_nk(gameTitle, emuPath.size() > 1 ? emuPath.c_str() : NULL); Launch_nk(gameTitle, emuPath.size() > 1 ? emuPath.c_str() : NULL, rtrnID ? (((u64)(0x00010001) << 32) | (rtrnID & 0xFFFFFFFF)) : rtrnID);
} }
if(!forwarder || neek2o()) if(!forwarder || neek2o())
{ {
if(!emu_disabled) if(!emu_disabled)
{ {
DeviceHandler::Instance()->UnMount(emuPartition);
Nand::Instance()->Init(emuPath.c_str(), emuPartition, false); Nand::Instance()->Init(emuPath.c_str(), emuPartition, false);
Nand::Instance()->Enable_Emu(); Nand::Instance()->Enable_Emu();
} }
@ -1099,7 +1105,7 @@ void CMenu::_launchChannel(dir_discHdr *hdr)
if(_loadIOS(gameIOS, userIOS, id) == LOAD_IOS_FAILED) if(_loadIOS(gameIOS, userIOS, id) == LOAD_IOS_FAILED)
Sys_Exit(); Sys_Exit();
} }
if(CurrentIOS.Type == IOS_TYPE_D2X && rtrn != NULL && strlen(rtrn) == 4) if((CurrentIOS.Type == IOS_TYPE_D2X || neek2o()) && rtrn != NULL && strlen(rtrn) == 4)
{ {
int rtrnID = rtrn[0] << 24 | rtrn[1] << 16 | rtrn[2] << 8 | rtrn[3]; int rtrnID = rtrn[0] << 24 | rtrn[1] << 16 | rtrn[2] << 8 | rtrn[3];
@ -1273,6 +1279,11 @@ void CMenu::_launchGame(dir_discHdr *hdr, bool dvd)
Nand::Instance()->CreatePath("%s:/wiiflow/nandemu", DeviceName[emuPartition]); Nand::Instance()->CreatePath("%s:/wiiflow/nandemu", DeviceName[emuPartition]);
} }
} }
m_cfg.setInt("GAMES", "savepartition", emuPartition);
m_cfg.setString("GAMES", "savepath", emuPath);
m_cfg.save();
char basepath[64]; char basepath[64];
snprintf(basepath, sizeof(basepath), "%s:%s", DeviceName[emuPartition], emuPath.c_str()); snprintf(basepath, sizeof(basepath), "%s:%s", DeviceName[emuPartition], emuPath.c_str());

View File

@ -146,7 +146,13 @@ bool CMenu::_ExitTo(void)
exitHandler(PRIILOADER_DEF); exitHandler(PRIILOADER_DEF);
} }
else else
exitHandler(EXIT_TO_BOOTMII); {
bool nkWiiflow = m_cfg.getBool("NEEK2O", "launchwiiflow", true);
if(nkWiiflow)
exitHandler(EXIT_TO_WFNK2O);
else
exitHandler(EXIT_TO_SMNK2O);
}
break; break;
} }
} }

View File

@ -822,7 +822,7 @@ int CMenu::main(void)
_launchHomebrew(fmt("%s/boot.dol", m_appDir.c_str()), m_homebrewArgs); _launchHomebrew(fmt("%s/boot.dol", m_appDir.c_str()), m_homebrewArgs);
return 0; return 0;
} }
else if(Sys_GetExitTo() == EXIT_TO_NEEK2O) else if(Sys_GetExitTo() == EXIT_TO_SMNK2O || Sys_GetExitTo() == EXIT_TO_WFNK2O)
{ {
string emuPath; string emuPath;
_FindEmuPart(&emuPath, m_cfg.getInt("NAND", "partition", 0), false); _FindEmuPart(&emuPath, m_cfg.getInt("NAND", "partition", 0), false);

View File

@ -61,14 +61,14 @@ static bool _saveExists(const char *path)
bool CMenu::_TestEmuNand(int epart, const char *path, bool indept) bool CMenu::_TestEmuNand(int epart, const char *path, bool indept)
{ {
bool haveValidENand = true;
char basepath[64]; char basepath[64];
char testpath[MAX_FAT_PATH]; char testpath[MAX_FAT_PATH];
snprintf(basepath, sizeof(basepath), "%s:%s", DeviceName[epart], path); snprintf(basepath, sizeof(basepath), "%s:%s", DeviceName[epart], path);
DIR *d; DIR *d;
d = opendir(basepath); d = opendir(basepath);
if(!d) if(!d)
haveValidENand = false; return false;
else else
closedir(d); closedir(d);
@ -77,29 +77,22 @@ bool CMenu::_TestEmuNand(int epart, const char *path, bool indept)
// Check Wiimotes && Region // Check Wiimotes && Region
snprintf(testpath, sizeof(testpath), "%s:%s/shared2/sys/SYSCONF", DeviceName[epart], path); snprintf(testpath, sizeof(testpath), "%s:%s/shared2/sys/SYSCONF", DeviceName[epart], path);
if(!fsop_FileExist(testpath)) if(!fsop_FileExist(testpath))
{ return false;
//gprintf("Nandcheck: SYSCONF not found\n");
haveValidENand = false;
}
snprintf(testpath, sizeof(testpath), "%s:%s/title/00000001/00000002/data/setting.txt", DeviceName[epart], path); snprintf(testpath, sizeof(testpath), "%s:%s/title/00000001/00000002/data/setting.txt", DeviceName[epart], path);
if(!fsop_FileExist(testpath)) if(!fsop_FileExist(testpath))
{ return false;
//gprintf("Nandcheck: setting.txt not found\n");
haveValidENand = false;
}
// Check Mii's // Check Mii's
snprintf(testpath, sizeof(testpath), "%s:%s/shared2/menu/FaceLib/RFL_DB.dat", DeviceName[epart], path); snprintf(testpath, sizeof(testpath), "%s:%s/shared2/menu/FaceLib/RFL_DB.dat", DeviceName[epart], path);
if(!fsop_FileExist(testpath)) if(!fsop_FileExist(testpath))
{ return false;
//gprintf("Nandcheck: Mii's not found\n");
haveValidENand = false;
} }
} return true;
return haveValidENand;
} }
int CMenu::_FindEmuPart(string *emuPath, int part, bool searchvalid) int CMenu::_FindEmuPart(string *emuPath, int part, bool searchvalid)
{ {
Nand::Instance()->Disable_Emu();
int emuPartition = -1; int emuPartition = -1;
string tmpPath; string tmpPath;
if(m_current_view == COVERFLOW_CHANNEL) if(m_current_view == COVERFLOW_CHANNEL)
@ -125,24 +118,25 @@ int CMenu::_FindEmuPart(string *emuPath, int part, bool searchvalid)
} }
} }
if(_TestEmuNand(emuPartition, tmpPath.c_str(), true) && DeviceHandler::Instance()->IsInserted(emuPartition) && DeviceHandler::Instance()->GetFSType(emuPartition) == PART_FS_FAT) if(!DeviceHandler::Instance()->IsInserted(emuPartition))
DeviceHandler::Instance()->Mount(emuPartition);
if(_TestEmuNand(emuPartition, tmpPath.c_str(), true) && DeviceHandler::Instance()->PartitionUsableForNandEmu(emuPartition))
{ {
*emuPath = tmpPath; *emuPath = tmpPath;
return emuPartition; return emuPartition;
} }
else else
{ {
emuPartition = part;
bool fllscn = emuPartition == -1; bool fllscn = emuPartition == -1;
for(u8 i = emuPartition; i <= USB8; ++i) for(u8 i = part; i <= USB8; ++i)
{ {
if(!DeviceHandler::Instance()->IsInserted(emuPartition) || DeviceHandler::Instance()->GetFSType(emuPartition) != PART_FS_FAT) if(!DeviceHandler::Instance()->IsInserted(i))
{ DeviceHandler::Instance()->Mount(i);
emuPartition++;
if(!DeviceHandler::Instance()->PartitionUsableForNandEmu(i))
continue; continue;
}
else
{
if(_TestEmuNand(i, tmpPath.c_str(), true) || searchvalid) if(_TestEmuNand(i, tmpPath.c_str(), true) || searchvalid)
{ {
if(m_current_view == COVERFLOW_CHANNEL) if(m_current_view == COVERFLOW_CHANNEL)
@ -155,11 +149,10 @@ int CMenu::_FindEmuPart(string *emuPath, int part, bool searchvalid)
return i; return i;
} }
}
if(i == USB8 && !fllscn) if(i == USB8 && !fllscn)
{ {
i = 0; i = -1;
fllscn = true; fllscn = true;
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<pd><ViewState><e p="Wiiflow" x="true"></e><e p="Wiiflow\resources" x="false"></e><e p="Wiiflow\data" x="false"></e><e p="Wiiflow\scripts" x="false"></e><e p="Wiiflow\source" x="false"></e><e p="Wiiflow\wii" x="false"></e><e p="Wiiflow\docs" x="false"></e><e p="Wiiflow\portlibs" x="false"></e></ViewState></pd> <pd><ViewState><e p="Wiiflow" x="true"></e><e p="Wiiflow\resources" x="false"></e><e p="Wiiflow\data" x="false"></e><e p="Wiiflow\scripts" x="false"></e><e p="Wiiflow\source" x="true"></e><e p="Wiiflow\source\network" x="false"></e><e p="Wiiflow\source\channel" x="false"></e><e p="Wiiflow\source\menu" x="true"></e><e p="Wiiflow\docs" x="false"></e><e p="Wiiflow\portlibs" x="false"></e><e p="Wiiflow\source\banner" x="false"></e><e p="Wiiflow\source\cheats" x="false"></e><e p="Wiiflow\source\config" x="false"></e><e p="Wiiflow\source\devicemounter" x="false"></e><e p="Wiiflow\source\fileOps" x="false"></e><e p="Wiiflow\source\gc" x="false"></e><e p="Wiiflow\source\gecko" x="false"></e><e p="Wiiflow\source\gui" x="false"></e><e p="Wiiflow\source\homebrew" x="false"></e><e p="Wiiflow\source\libwbfs" x="false"></e><e p="Wiiflow\source\list" x="false"></e><e p="Wiiflow\source\loader" x="true"></e><e p="Wiiflow\source\memory" x="false"></e><e p="Wiiflow\source\music" x="false"></e><e p="Wiiflow\source\plugin" x="false"></e><e p="Wiiflow\source\unzip" x="false"></e><e p="Wiiflow\source\wstringEx" x="false"></e><e p="Wiiflow\wii" x="false"></e></ViewState></pd>