2012-08-05 15:48:15 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* Copyright (C) 2012 FIX94
|
|
|
|
*
|
|
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
2012-01-21 22:15:45 +01:00
|
|
|
#include <gccore.h>
|
2012-02-25 23:34:52 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
2012-03-11 20:47:24 +01:00
|
|
|
#include <string.h>
|
2012-07-17 13:30:08 +02:00
|
|
|
#include <ogc/machine/processor.h>
|
2012-12-08 18:30:00 +01:00
|
|
|
#include <ogc/lwp_threads.h>
|
2012-07-12 15:21:14 +02:00
|
|
|
// for directory parsing and low-level file I/O
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <dirent.h>
|
2016-04-02 17:46:06 +02:00
|
|
|
#include "menu/menu.hpp"
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "gc/gc.hpp"
|
2012-11-17 18:30:24 +01:00
|
|
|
#include "gui/text.hpp"
|
2012-09-02 15:34:41 +02:00
|
|
|
#include "devicemounter/DeviceHandler.hpp"
|
2012-12-08 17:17:35 +01:00
|
|
|
#include "gecko/gecko.hpp"
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "fileOps/fileOps.h"
|
2012-12-08 19:45:48 +01:00
|
|
|
#include "homebrew/homebrew.h"
|
2012-08-05 15:48:15 +02:00
|
|
|
#include "loader/utils.h"
|
2012-07-27 19:26:49 +02:00
|
|
|
#include "loader/disc.h"
|
2012-11-17 18:30:24 +01:00
|
|
|
#include "loader/sys.h"
|
2012-08-12 23:26:24 +02:00
|
|
|
#include "memory/memory.h"
|
2012-11-18 14:40:26 +01:00
|
|
|
#include "memory/mem2.hpp"
|
2012-07-27 19:26:49 +02:00
|
|
|
|
2013-09-24 23:24:03 +02:00
|
|
|
// Nintendont
|
|
|
|
NIN_CFG NinCfg;
|
2014-06-24 15:33:54 +02:00
|
|
|
u8 NinDevice = 0;
|
|
|
|
bool NinArgsboot = false;
|
2016-04-02 17:46:06 +02:00
|
|
|
|
|
|
|
void Nintendont_SetOptions(const char *game, const char *gameID, char *CheatPath,char *NewCheatPath, const char *partition,
|
2016-04-03 02:31:02 +02:00
|
|
|
bool cheats, u8 emuMC, u8 videomode, bool widescreen, bool usb_hid, bool native_ctl, bool deflicker, bool wiiu_widescreen, bool NIN_Debugger)
|
2013-09-24 23:24:03 +02:00
|
|
|
{
|
2014-04-25 22:23:21 +02:00
|
|
|
NinDevice = DeviceHandle.PathToDriveType(game);
|
2013-09-24 23:24:03 +02:00
|
|
|
memset(&NinCfg, 0, sizeof(NIN_CFG));
|
|
|
|
NinCfg.Magicbytes = 0x01070CF6;
|
2016-04-02 17:46:06 +02:00
|
|
|
NinCfg.MemCardBlocks = 0x2;//251 blocks
|
|
|
|
|
|
|
|
//check version
|
|
|
|
u32 NIN_cfg_version = NIN_CFG_VERSION;
|
|
|
|
for(u8 i = SD; i < MAXDEVICES; ++i)
|
|
|
|
{
|
|
|
|
const char *dol_path = fmt(NIN_LOADER_PATH, DeviceName[i]);
|
|
|
|
if(!fsop_FileExist(dol_path))
|
|
|
|
continue;
|
|
|
|
u32 filesize = 0;
|
|
|
|
u8 *buffer = fsop_ReadFile(dol_path, &filesize);
|
|
|
|
char NINversion[21];
|
|
|
|
for(u32 i = 0; i < filesize-60; ++i)
|
|
|
|
{
|
|
|
|
// Nintendont Loader..Built : %s %s..Jan 10 2014.11:21:01
|
|
|
|
if((*(vu32*)(buffer+i+2)) == 0x6e74656e && (*(vu32*)(buffer+i+6)) == 0x646f6e74
|
|
|
|
&& (*(vu32*)(buffer+i+11)) == 0x4c6f6164) //'nten' 'dont' 'Load'
|
|
|
|
{
|
|
|
|
for(int k= 30; k <50; ++k)
|
|
|
|
{
|
|
|
|
if((*(vu32*)(buffer+i+k)) == 0x4A616E20 || (*(vu32*)(buffer+i+k)) == 0x46656220 ||
|
|
|
|
(*(vu32*)(buffer+i+k)) == 0x4D617220 || (*(vu32*)(buffer+i+k)) == 0x41707220 ||
|
|
|
|
(*(vu32*)(buffer+i+k)) == 0x4D617920 || (*(vu32*)(buffer+i+k)) == 0x4A756E20 ||
|
|
|
|
(*(vu32*)(buffer+i+k)) == 0x4A756C20 || (*(vu32*)(buffer+i+k)) == 0x41756720 ||
|
|
|
|
(*(vu32*)(buffer+i+k)) == 0x53657020 || (*(vu32*)(buffer+i+k)) == 0x4F637420 ||
|
|
|
|
(*(vu32*)(buffer+i+k)) == 0x4E6F7620 || (*(vu32*)(buffer+i+k)) == 0x44656320 ) // find Month
|
|
|
|
{
|
|
|
|
for(int j = 0 ; j < 20 ; j++)
|
|
|
|
NINversion[j] = *(u8*)(buffer+i+k+j);
|
|
|
|
|
|
|
|
NINversion[11] = ' '; // replace \0 between year and time with a space.
|
|
|
|
NINversion[20] = 0;
|
|
|
|
struct tm time;
|
|
|
|
strptime(NINversion, "%b %d %Y %H:%M:%S", &time);
|
|
|
|
|
|
|
|
const time_t NINLoaderTime = mktime(&time);
|
|
|
|
const time_t v135time = 1407167999;// v1.135
|
|
|
|
|
|
|
|
if(difftime(NINLoaderTime,v135time) > 0)
|
|
|
|
NIN_cfg_version = 3;
|
|
|
|
else
|
|
|
|
NIN_cfg_version = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(buffer);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NinCfg.Version = NIN_cfg_version;
|
|
|
|
|
|
|
|
if(memcmp("0x474851",gameID,3)==0)
|
|
|
|
NinCfg.MaxPads = 1;
|
|
|
|
else
|
|
|
|
NinCfg.MaxPads = 4;
|
|
|
|
|
2013-09-24 23:24:03 +02:00
|
|
|
NinCfg.Config |= NIN_CFG_AUTO_BOOT;
|
2016-04-02 17:46:06 +02:00
|
|
|
|
2014-04-25 22:23:21 +02:00
|
|
|
if(NinDevice != SD)
|
|
|
|
NinCfg.Config |= NIN_CFG_USB;
|
2013-09-24 23:24:03 +02:00
|
|
|
|
2014-04-25 22:23:21 +02:00
|
|
|
if(IsOnWiiU() == true)
|
|
|
|
NinCfg.Config |= NIN_CFG_MEMCARDEMU;
|
2016-04-02 17:46:06 +02:00
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE;
|
2013-09-24 23:24:03 +02:00
|
|
|
|
2016-04-02 17:46:06 +02:00
|
|
|
if((videomode > 3) && (videomode != 6))
|
|
|
|
NinCfg.Config |= NIN_CFG_FORCE_PROG;
|
|
|
|
|
|
|
|
if(usb_hid)
|
|
|
|
NinCfg.Config |= NIN_CFG_HID;
|
|
|
|
|
|
|
|
if(NIN_Debugger)
|
|
|
|
NinCfg.Config |= NIN_CFG_OSREPORT;
|
|
|
|
|
|
|
|
if(native_ctl)
|
|
|
|
NinCfg.Config |= NIN_CFG_NATIVE_SI;
|
|
|
|
|
|
|
|
if(deflicker)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_DF;
|
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
if(wiiu_widescreen)
|
2016-04-02 17:46:06 +02:00
|
|
|
NinCfg.Config |= NIN_CFG_WIIU_WIDE;
|
|
|
|
|
2013-09-24 23:24:03 +02:00
|
|
|
if(widescreen)
|
|
|
|
NinCfg.Config |= NIN_CFG_FORCE_WIDE;
|
2016-04-02 17:46:06 +02:00
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
if(emuMC > 0)
|
2013-09-24 23:24:03 +02:00
|
|
|
NinCfg.Config |= NIN_CFG_MEMCARDEMU;
|
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
if(emuMC > 1)
|
2016-04-02 17:46:06 +02:00
|
|
|
{
|
|
|
|
NinCfg.Config |= NIN_CFG_MC_MULTI;
|
|
|
|
NinCfg.MemCardBlocks = 0x4;//1019 blocks (8MB)
|
|
|
|
}
|
|
|
|
if(CheatPath != NULL && NewCheatPath != NULL && cheats)
|
|
|
|
{
|
|
|
|
const char *ptr = NULL;
|
|
|
|
if(strncasecmp(CheatPath, partition, strlen(partition)) != 0)
|
|
|
|
{
|
|
|
|
fsop_CopyFile(CheatPath, NewCheatPath, NULL, NULL);
|
|
|
|
ptr = strchr(NewCheatPath, '/');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr = strchr(CheatPath, '/');
|
|
|
|
snprintf(NinCfg.CheatPath,sizeof(NinCfg.CheatPath),ptr);
|
|
|
|
NinCfg.Config |= NIN_CFG_CHEAT_PATH;
|
|
|
|
}
|
|
|
|
if(cheats)
|
|
|
|
NinCfg.Config |= NIN_CFG_CHEATS;
|
|
|
|
|
2014-04-25 22:23:21 +02:00
|
|
|
strncpy(NinCfg.GamePath, strchr(game, '/'), 254);
|
2013-09-24 23:24:03 +02:00
|
|
|
if(strstr(NinCfg.GamePath, "boot.bin") != NULL)
|
|
|
|
{
|
|
|
|
*strrchr(NinCfg.GamePath, '/') = '\0'; //boot.bin
|
|
|
|
*(strrchr(NinCfg.GamePath, '/')+1) = '\0'; //sys
|
|
|
|
}
|
2014-04-25 22:23:21 +02:00
|
|
|
memcpy(&NinCfg.GameID, gameID, 4);
|
|
|
|
gprintf("Nintendont Game Path: %s, ID: %08x\n", NinCfg.GamePath, NinCfg.GameID);
|
2013-09-24 23:24:03 +02:00
|
|
|
}
|
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
void Nintendont_BootDisc(u8 emuMC, bool widescreen, bool usb_hid, bool native_ctl, bool deflicker)
|
2016-04-02 17:46:06 +02:00
|
|
|
{
|
|
|
|
memset(&NinCfg, 0, sizeof(NIN_CFG));
|
|
|
|
NinCfg.Magicbytes = 0x01070CF6;
|
|
|
|
FILE * location = fopen("sd:/nincfg.bin", "r");
|
|
|
|
if(location == NULL)
|
|
|
|
{
|
|
|
|
NinCfg.Config |= NIN_CFG_USB;
|
|
|
|
fclose(location);
|
|
|
|
location = NULL;
|
|
|
|
}
|
|
|
|
NinCfg.Version = NIN_CFG_VERSION;
|
|
|
|
NinCfg.Config |= NIN_CFG_AUTO_BOOT;
|
|
|
|
NinCfg.VideoMode |= NIN_VID_AUTO;
|
|
|
|
|
|
|
|
if(usb_hid)
|
|
|
|
NinCfg.Config |= NIN_CFG_HID;
|
2016-04-03 02:31:02 +02:00
|
|
|
if(emuMC == 1)
|
2016-04-02 17:46:06 +02:00
|
|
|
{
|
|
|
|
NinCfg.Config |= NIN_CFG_MEMCARDEMU;
|
|
|
|
NinCfg.MemCardBlocks = 0x2;//251 blocks (2MB)
|
|
|
|
}
|
2016-04-03 02:31:02 +02:00
|
|
|
else if(emuMC == 2)
|
2016-04-02 17:46:06 +02:00
|
|
|
{
|
|
|
|
NinCfg.Config |= NIN_CFG_MEMCARDEMU;
|
|
|
|
NinCfg.Config |= NIN_CFG_MC_MULTI;
|
|
|
|
NinCfg.MemCardBlocks = 0x4;//1019 blocks (8MB)
|
|
|
|
|
|
|
|
}
|
|
|
|
if(native_ctl)
|
|
|
|
NinCfg.Config |= NIN_CFG_NATIVE_SI;
|
|
|
|
if(deflicker)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_DF;
|
|
|
|
if(widescreen)
|
|
|
|
NinCfg.Config |= NIN_CFG_FORCE_WIDE;
|
|
|
|
snprintf(NinCfg.GamePath,sizeof(NinCfg.GamePath),"di");
|
|
|
|
}
|
|
|
|
|
2013-09-24 23:24:03 +02:00
|
|
|
void Nintendont_WriteOptions()
|
|
|
|
{
|
2014-06-24 15:33:54 +02:00
|
|
|
/* Newer Nintendont versions */
|
|
|
|
if(NinArgsboot == true)
|
|
|
|
{
|
2016-04-02 17:46:06 +02:00
|
|
|
gprintf("Writing Arguments\n");
|
2014-06-24 15:33:54 +02:00
|
|
|
AddBootArgument((char*)&NinCfg, sizeof(NIN_CFG));
|
|
|
|
return;
|
|
|
|
}
|
2014-04-25 22:23:21 +02:00
|
|
|
/* general loader */
|
|
|
|
if(DeviceHandle.SD_Inserted())
|
|
|
|
{
|
|
|
|
gprintf("Writing Nintendont CFG: sd:/%s\n", NIN_CFG_PATH);
|
|
|
|
fsop_WriteFile(fmt("sd:/%s", NIN_CFG_PATH), &NinCfg, sizeof(NIN_CFG));
|
|
|
|
}
|
|
|
|
/* for kernel */
|
|
|
|
if(NinDevice != SD)
|
|
|
|
{
|
|
|
|
gprintf("Writing Nintendont USB Kernel CFG: %s:/%s\n", DeviceName[NinDevice], NIN_CFG_PATH);
|
|
|
|
fsop_WriteFile(fmt("%s:/%s", DeviceName[NinDevice], NIN_CFG_PATH), &NinCfg, sizeof(NIN_CFG));
|
|
|
|
}
|
2013-09-24 23:24:03 +02:00
|
|
|
}
|
|
|
|
|
2014-06-24 15:33:54 +02:00
|
|
|
bool Nintendont_Installed()
|
|
|
|
{
|
|
|
|
for(u8 i = SD; i < MAXDEVICES; ++i)
|
|
|
|
{
|
|
|
|
const char *dol_path = fmt(NIN_LOADER_PATH, DeviceName[i]);
|
|
|
|
if(fsop_FileExist(dol_path) == true)
|
|
|
|
{
|
|
|
|
gprintf("Nintendont found\n");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2016-04-02 17:46:06 +02:00
|
|
|
|
2013-09-24 23:24:03 +02:00
|
|
|
bool Nintendont_GetLoader()
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
for(u8 i = SD; i < MAXDEVICES; ++i)
|
|
|
|
{
|
|
|
|
const char *dol_path = fmt(NIN_LOADER_PATH, DeviceName[i]);
|
|
|
|
ret = (LoadHomebrew(dol_path) == 1);
|
|
|
|
if(ret == true)
|
|
|
|
{
|
|
|
|
gprintf("Nintendont loaded: %s\n", dol_path);
|
|
|
|
AddBootArgument(dol_path);
|
2014-06-24 15:33:54 +02:00
|
|
|
//search for argsboot
|
|
|
|
u32 size;
|
|
|
|
const char *dol_ptr = GetHomebrew(&size);
|
|
|
|
for(u32 i = 0; i < size; i += 0x10)
|
|
|
|
{
|
|
|
|
if(strncmp(dol_ptr + i, "argsboot", 8) == 0)
|
|
|
|
{
|
|
|
|
gprintf("Nintendont argsboot found at %08x\n", i);
|
|
|
|
NinArgsboot = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-09-24 23:24:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-12 15:21:14 +02:00
|
|
|
// Devolution
|
2012-11-18 14:40:26 +01:00
|
|
|
u8 *tmp_buffer = NULL;
|
2012-07-28 18:41:48 +02:00
|
|
|
u8 *loader_bin = NULL;
|
2012-11-18 14:40:26 +01:00
|
|
|
u32 loader_size = 0;
|
2012-08-05 15:48:15 +02:00
|
|
|
extern "C" { extern void __exception_closeall(); }
|
2012-07-12 15:21:14 +02:00
|
|
|
static gconfig *DEVO_CONFIG = (gconfig*)0x80000020;
|
2012-12-08 19:45:48 +01:00
|
|
|
#define DEVO_ENTRY ((entry)loader_bin)
|
2012-07-12 15:21:14 +02:00
|
|
|
|
2012-11-17 18:30:24 +01:00
|
|
|
bool DEVO_Installed(const char *path)
|
2012-07-12 17:53:04 +02:00
|
|
|
{
|
2013-06-30 20:40:49 +02:00
|
|
|
loader_size = 0;
|
2012-07-12 17:53:04 +02:00
|
|
|
bool devo = false;
|
2013-06-30 20:40:49 +02:00
|
|
|
fsop_GetFileSizeBytes(fmt(DEVO_LOADER_PATH, path), &loader_size);
|
|
|
|
if(loader_size > 0x80) //Size should be more than 128b
|
2012-07-12 17:53:04 +02:00
|
|
|
{
|
2013-06-30 20:40:49 +02:00
|
|
|
gprintf("Devolution found\n");
|
|
|
|
devo = true;
|
2012-07-12 17:53:04 +02:00
|
|
|
}
|
|
|
|
return devo;
|
|
|
|
}
|
|
|
|
|
2012-11-17 18:30:24 +01:00
|
|
|
void DEVO_GetLoader(const char *path)
|
2012-07-19 20:19:28 +02:00
|
|
|
{
|
2013-06-30 20:40:49 +02:00
|
|
|
loader_size = 0;
|
|
|
|
tmp_buffer = fsop_ReadFile(fmt(DEVO_LOADER_PATH, path), &loader_size);
|
2013-06-29 18:54:21 +02:00
|
|
|
if(tmp_buffer == NULL)
|
2012-11-17 18:30:24 +01:00
|
|
|
gprintf("Devolution: Loader not found!\n");
|
2012-08-24 15:50:17 +02:00
|
|
|
}
|
2012-07-28 18:41:48 +02:00
|
|
|
|
2013-02-10 12:13:33 +01:00
|
|
|
void DEVO_SetOptions(const char *isopath, const char *gameID, bool memcard_emu,
|
|
|
|
bool widescreen, bool activity_led, bool wifi)
|
2012-08-24 15:50:17 +02:00
|
|
|
{
|
|
|
|
// re-mount device we need
|
2012-11-17 18:30:24 +01:00
|
|
|
DeviceHandle.MountDevolution();
|
2012-07-12 18:02:51 +02:00
|
|
|
|
|
|
|
//start writing cfg to mem
|
2012-07-12 15:21:14 +02:00
|
|
|
struct stat st;
|
|
|
|
int data_fd;
|
2012-07-22 20:02:56 +02:00
|
|
|
char iso2path[256];
|
2012-11-17 18:30:24 +01:00
|
|
|
iso2path[255] = '\0';
|
2012-07-12 15:21:14 +02:00
|
|
|
|
2012-07-22 20:02:56 +02:00
|
|
|
stat(isopath, &st);
|
2012-08-24 15:50:17 +02:00
|
|
|
FILE *f = fopen(isopath, "rb");
|
2012-11-17 18:30:24 +01:00
|
|
|
gprintf("Devolution: ISO Header %s\n", isopath);
|
2013-09-02 00:31:46 +02:00
|
|
|
fread((u8*)Disc_ID, 1, 32, f);
|
2012-07-22 20:02:56 +02:00
|
|
|
fclose(f);
|
2013-09-02 00:31:46 +02:00
|
|
|
f = NULL;
|
2012-07-12 15:21:14 +02:00
|
|
|
|
|
|
|
// fill out the Devolution config struct
|
2012-07-27 19:26:49 +02:00
|
|
|
memset(DEVO_CONFIG, 0, sizeof(gconfig));
|
2013-02-10 12:13:33 +01:00
|
|
|
DEVO_CONFIG->signature = DEVO_CONFIG_SIG;
|
|
|
|
DEVO_CONFIG->version = DEVO_CONFIG_VERSION;
|
2012-07-12 15:21:14 +02:00
|
|
|
DEVO_CONFIG->device_signature = st.st_dev;
|
|
|
|
DEVO_CONFIG->disc1_cluster = st.st_ino;
|
2013-02-10 12:13:33 +01:00
|
|
|
|
|
|
|
// Pergame options
|
|
|
|
if(wifi)
|
|
|
|
DEVO_CONFIG->options |= DEVO_CONFIG_WIFILOG;
|
|
|
|
if(widescreen)
|
|
|
|
DEVO_CONFIG->options |= DEVO_CONFIG_WIDE;
|
|
|
|
if(!activity_led)
|
|
|
|
DEVO_CONFIG->options |= DEVO_CONFIG_NOLED;
|
|
|
|
|
2012-07-22 20:02:56 +02:00
|
|
|
// If 2nd iso file tell Devo about it
|
2012-11-17 18:30:24 +01:00
|
|
|
strncpy(iso2path, isopath, 255);
|
|
|
|
char *ptz = strstr(iso2path, "game.iso");
|
2012-07-28 18:41:48 +02:00
|
|
|
if(ptz != NULL)
|
2013-03-11 21:23:24 +01:00
|
|
|
{
|
2012-07-22 20:02:56 +02:00
|
|
|
strncpy(ptz, "gam1.iso", 8);
|
2013-03-11 21:23:24 +01:00
|
|
|
f = fopen(iso2path, "rb");
|
|
|
|
if(f == NULL)
|
|
|
|
{
|
|
|
|
strncpy(ptz, "gam2.iso", 8);
|
|
|
|
f = fopen(iso2path, "rb");
|
|
|
|
if(f == NULL)
|
|
|
|
{
|
|
|
|
strncpy(ptz, "disc2.iso", 9);
|
|
|
|
f = fopen(iso2path, "rb");
|
|
|
|
}
|
|
|
|
}
|
2013-09-02 00:31:46 +02:00
|
|
|
if(f != NULL)
|
|
|
|
{
|
|
|
|
gprintf("Devolution: 2nd ISO File for Multi DVD Game %s\n", iso2path);
|
|
|
|
stat(iso2path, &st);
|
|
|
|
DEVO_CONFIG->disc2_cluster = st.st_ino;
|
|
|
|
fclose(f);
|
|
|
|
}
|
2012-07-22 20:02:56 +02:00
|
|
|
}
|
2012-07-12 15:21:14 +02:00
|
|
|
|
|
|
|
// make sure these directories exist, they are required for Devolution to function correctly
|
2012-11-17 18:30:24 +01:00
|
|
|
fsop_MakeFolder(fmt("%s:/apps", DeviceName[currentPartition]));
|
|
|
|
fsop_MakeFolder(fmt("%s:/apps/gc_devo", DeviceName[currentPartition]));
|
2012-07-12 15:21:14 +02:00
|
|
|
|
2012-07-13 22:00:54 +02:00
|
|
|
if(memcard_emu)
|
2012-07-12 15:21:14 +02:00
|
|
|
{
|
2012-11-17 18:30:24 +01:00
|
|
|
const char *memcard_dir = NULL;
|
2012-07-13 22:00:54 +02:00
|
|
|
// find or create a 16MB memcard file for emulation
|
|
|
|
// this file can be located anywhere since it's passed by cluster, not name
|
2012-10-16 13:52:14 +02:00
|
|
|
// it must be at least 512KB (smallest possible memcard = 59 blocks)
|
2012-07-15 14:43:45 +02:00
|
|
|
if(gameID[3] == 'J') //Japanese Memory Card
|
2012-11-17 18:30:24 +01:00
|
|
|
memcard_dir = fmt("%s:/apps/gc_devo/memcard_jap.bin", DeviceName[currentPartition]);
|
2012-07-15 14:43:45 +02:00
|
|
|
else
|
2012-11-17 18:30:24 +01:00
|
|
|
memcard_dir = fmt("%s:/apps/gc_devo/memcard.bin", DeviceName[currentPartition]);
|
|
|
|
gprintf("Devolution: Memory Card File %s\n", memcard_dir);
|
2012-10-16 13:52:14 +02:00
|
|
|
// check if file doesn't exist
|
2012-11-17 18:30:24 +01:00
|
|
|
if(stat(memcard_dir, &st) == -1 || st.st_size < (1<<19))
|
2012-07-12 15:21:14 +02:00
|
|
|
{
|
2012-07-13 22:00:54 +02:00
|
|
|
// need to enlarge or create it
|
2012-11-17 18:30:24 +01:00
|
|
|
data_fd = open(memcard_dir, O_WRONLY|O_CREAT);
|
2012-07-13 22:00:54 +02:00
|
|
|
if(data_fd >= 0)
|
|
|
|
{
|
2012-10-16 13:52:14 +02:00
|
|
|
// try to make it 16MB (largest possible memcard = 2043 blocks)
|
2012-11-17 18:30:24 +01:00
|
|
|
gprintf("Devolution: Resizing Memory Card File...\n");
|
2012-07-13 22:00:54 +02:00
|
|
|
ftruncate(data_fd, 16<<20);
|
2012-10-16 13:52:14 +02:00
|
|
|
if(fstat(data_fd, &st) == -1 || st.st_size < (1<<19))
|
2012-07-13 22:00:54 +02:00
|
|
|
{
|
|
|
|
// it still isn't big enough. Give up.
|
|
|
|
st.st_ino = 0;
|
|
|
|
}
|
|
|
|
close(data_fd);
|
|
|
|
}
|
|
|
|
else
|
2012-07-12 15:21:14 +02:00
|
|
|
{
|
2012-07-13 22:00:54 +02:00
|
|
|
// couldn't open or create the memory card file
|
2012-07-12 15:21:14 +02:00
|
|
|
st.st_ino = 0;
|
|
|
|
}
|
|
|
|
}
|
2012-11-17 18:30:24 +01:00
|
|
|
gprintf("Devolution: Memory Card at %08x\n", st.st_ino);
|
2012-07-12 15:21:14 +02:00
|
|
|
}
|
2012-07-13 22:00:54 +02:00
|
|
|
else
|
|
|
|
st.st_ino = 0;
|
2012-07-12 15:21:14 +02:00
|
|
|
|
|
|
|
// set FAT cluster for start of memory card file
|
|
|
|
// if this is zero memory card emulation will not be used
|
|
|
|
DEVO_CONFIG->memcard_cluster = st.st_ino;
|
|
|
|
|
|
|
|
// flush disc ID and Devolution config out to memory
|
2013-09-02 00:31:46 +02:00
|
|
|
DCFlushRange((void*)Disc_ID, 64);
|
2012-08-24 15:50:17 +02:00
|
|
|
|
2012-11-17 18:30:24 +01:00
|
|
|
DeviceHandle.UnMountDevolution();
|
2012-07-12 15:21:14 +02:00
|
|
|
}
|
|
|
|
|
2012-07-12 18:02:51 +02:00
|
|
|
void DEVO_Boot()
|
2012-07-12 17:53:04 +02:00
|
|
|
{
|
2012-11-18 14:40:26 +01:00
|
|
|
/* Move our loader into low MEM1 */
|
|
|
|
loader_bin = (u8*)MEM1_lo_alloc(loader_size);
|
|
|
|
memcpy(loader_bin, tmp_buffer, loader_size);
|
|
|
|
DCFlushRange(loader_bin, ALIGN32(loader_size));
|
|
|
|
MEM2_free(tmp_buffer);
|
|
|
|
gprintf("%s\n", (loader_bin+4));
|
2012-12-08 19:45:48 +01:00
|
|
|
/* Boot that binary */
|
|
|
|
JumpToEntry(DEVO_ENTRY);
|
2012-07-12 17:53:04 +02:00
|
|
|
}
|
|
|
|
|
2012-07-12 15:21:14 +02:00
|
|
|
|
|
|
|
// General
|
2012-02-02 23:22:46 +01:00
|
|
|
#define SRAM_ENGLISH 0
|
|
|
|
#define SRAM_GERMAN 1
|
|
|
|
#define SRAM_FRENCH 2
|
|
|
|
#define SRAM_SPANISH 3
|
|
|
|
#define SRAM_ITALIAN 4
|
|
|
|
#define SRAM_DUTCH 5
|
|
|
|
|
2012-08-05 15:48:15 +02:00
|
|
|
extern "C" {
|
2012-01-21 22:15:45 +01:00
|
|
|
syssram* __SYS_LockSram();
|
|
|
|
u32 __SYS_UnlockSram(u32 write);
|
|
|
|
u32 __SYS_SyncSram(void);
|
2012-08-05 15:48:15 +02:00
|
|
|
}
|
2012-01-21 22:15:45 +01:00
|
|
|
|
2016-04-03 02:31:02 +02:00
|
|
|
void GC_SetVideoMode(u8 videomode, u8 loader)
|
2012-01-21 22:15:45 +01:00
|
|
|
{
|
2012-06-24 20:11:12 +02:00
|
|
|
syssram *sram;
|
|
|
|
sram = __SYS_LockSram();
|
2012-07-19 22:23:57 +02:00
|
|
|
GXRModeObj *vmode = VIDEO_GetPreferredMode(0);
|
|
|
|
int vmode_reg = 0;
|
2012-02-21 18:21:12 +01:00
|
|
|
|
2016-04-02 17:46:06 +02:00
|
|
|
if((VIDEO_HaveComponentCable() && (CONF_GetProgressiveScan() > 0)) || ((videomode > 3) && (videomode != 6)))
|
2012-02-21 18:21:12 +01:00
|
|
|
sram->flags |= 0x80; //set progressive flag
|
|
|
|
else
|
|
|
|
sram->flags &= 0x7F; //clear progressive flag
|
|
|
|
|
2016-04-02 17:46:06 +02:00
|
|
|
if(videomode == 1 || videomode == 3 || videomode == 5 || videomode == 6 || videomode == 7)
|
2012-01-23 16:57:30 +01:00
|
|
|
{
|
2012-07-19 22:23:57 +02:00
|
|
|
vmode_reg = 1;
|
2012-03-25 21:52:35 +02:00
|
|
|
sram->flags |= 0x01; // Set bit 0 to set the video mode to PAL
|
|
|
|
sram->ntd |= 0x40; //set pal60 flag
|
2012-01-23 16:57:30 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-25 21:52:35 +02:00
|
|
|
sram->flags &= 0xFE; // Clear bit 0 to set the video mode to NTSC
|
|
|
|
sram->ntd &= 0xBF; //clear pal60 flag
|
|
|
|
}
|
2016-04-02 17:46:06 +02:00
|
|
|
|
2012-03-25 21:52:35 +02:00
|
|
|
if(videomode == 1)
|
2012-06-24 20:11:12 +02:00
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_PAL50;
|
2012-07-19 22:23:57 +02:00
|
|
|
vmode = &TVPal528IntDf;
|
2012-06-24 20:11:12 +02:00
|
|
|
}
|
2012-03-25 21:52:35 +02:00
|
|
|
else if(videomode == 2)
|
2012-06-24 20:11:12 +02:00
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_NTSC;
|
2012-07-19 22:23:57 +02:00
|
|
|
vmode = &TVNtsc480IntDf;
|
2012-06-24 20:11:12 +02:00
|
|
|
}
|
2012-03-25 21:52:35 +02:00
|
|
|
else if(videomode == 3)
|
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_PAL60;
|
2012-07-19 22:23:57 +02:00
|
|
|
vmode = &TVEurgb60Hz480IntDf;
|
|
|
|
vmode_reg = 5;
|
2012-06-24 20:11:12 +02:00
|
|
|
}
|
2016-04-02 17:46:06 +02:00
|
|
|
else if(videomode == 4)
|
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_NTSC;
|
2016-04-02 17:46:06 +02:00
|
|
|
vmode = &TVNtsc480IntDf;// shouldn't this be vmode = &TVNtsc480Prog
|
|
|
|
}
|
|
|
|
else if(videomode == 5)
|
2012-06-24 20:11:12 +02:00
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_PAL60;
|
2016-04-02 17:46:06 +02:00
|
|
|
vmode = &TVEurgb60Hz480IntDf;
|
|
|
|
vmode_reg = 5;
|
|
|
|
}
|
|
|
|
else if(videomode == 6)
|
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_MPAL;
|
2016-04-02 17:46:06 +02:00
|
|
|
vmode = &TVEurgb60Hz480IntDf;
|
2016-04-03 02:31:02 +02:00
|
|
|
vmode_reg = 5;// not sure about this
|
2012-03-25 21:52:35 +02:00
|
|
|
}
|
2016-04-02 17:46:06 +02:00
|
|
|
else if(videomode == 7)
|
2012-03-25 21:52:35 +02:00
|
|
|
{
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
|
|
|
NinCfg.VideoMode |= NIN_VID_FORCE_MPAL;
|
2016-04-02 17:46:06 +02:00
|
|
|
vmode = &TVEurgb60Hz480IntDf;
|
2012-07-19 22:23:57 +02:00
|
|
|
vmode_reg = 5;
|
2012-01-23 16:57:30 +01:00
|
|
|
}
|
2012-02-21 18:01:57 +01:00
|
|
|
|
2012-01-21 22:15:45 +01:00
|
|
|
__SYS_UnlockSram(1); // 1 -> write changes
|
|
|
|
while(!__SYS_SyncSram());
|
|
|
|
|
2012-08-12 23:26:24 +02:00
|
|
|
/* Set video mode register */
|
|
|
|
*Video_Mode = vmode_reg;
|
|
|
|
DCFlushRange((void*)Video_Mode, 4);
|
|
|
|
|
|
|
|
/* Set video mode */
|
|
|
|
if(vmode != 0)
|
|
|
|
VIDEO_Configure(vmode);
|
|
|
|
|
|
|
|
/* Setup video */
|
|
|
|
VIDEO_SetBlack(FALSE);
|
|
|
|
VIDEO_Flush();
|
|
|
|
VIDEO_WaitVSync();
|
|
|
|
if(vmode->viTVMode & VI_NON_INTERLACE)
|
|
|
|
VIDEO_WaitVSync();
|
|
|
|
else while(VIDEO_GetNextField())
|
|
|
|
VIDEO_WaitVSync();
|
|
|
|
|
|
|
|
/* Set black and flush */
|
|
|
|
VIDEO_SetBlack(TRUE);
|
|
|
|
VIDEO_Flush();
|
|
|
|
VIDEO_WaitVSync();
|
|
|
|
if(vmode->viTVMode & VI_NON_INTERLACE)
|
|
|
|
VIDEO_WaitVSync();
|
|
|
|
else while(VIDEO_GetNextField())
|
|
|
|
VIDEO_WaitVSync();
|
2012-02-02 23:22:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 get_wii_language()
|
|
|
|
{
|
|
|
|
switch (CONF_GetLanguage())
|
|
|
|
{
|
|
|
|
case CONF_LANG_GERMAN:
|
|
|
|
return SRAM_GERMAN;
|
|
|
|
case CONF_LANG_FRENCH:
|
|
|
|
return SRAM_FRENCH;
|
|
|
|
case CONF_LANG_SPANISH:
|
|
|
|
return SRAM_SPANISH;
|
|
|
|
case CONF_LANG_ITALIAN:
|
|
|
|
return SRAM_ITALIAN;
|
|
|
|
case CONF_LANG_DUTCH:
|
|
|
|
return SRAM_DUTCH;
|
|
|
|
default:
|
|
|
|
return SRAM_ENGLISH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-25 22:23:21 +02:00
|
|
|
void GC_SetLanguage(u8 lang, u8 loader)
|
2012-02-02 23:22:46 +01:00
|
|
|
{
|
|
|
|
if (lang == 0)
|
|
|
|
lang = get_wii_language();
|
|
|
|
else
|
|
|
|
lang--;
|
|
|
|
|
|
|
|
syssram *sram;
|
|
|
|
sram = __SYS_LockSram();
|
|
|
|
sram->lang = lang;
|
|
|
|
__SYS_UnlockSram(1); // 1 -> write changes
|
|
|
|
while(!__SYS_SyncSram());
|
2014-04-25 22:23:21 +02:00
|
|
|
|
|
|
|
/* write language for nintendont */
|
2016-04-03 02:31:02 +02:00
|
|
|
if(loader == 1)
|
2014-04-25 22:23:21 +02:00
|
|
|
{
|
|
|
|
switch(lang)
|
|
|
|
{
|
|
|
|
case SRAM_GERMAN:
|
|
|
|
NinCfg.Language = NIN_LAN_GERMAN;
|
|
|
|
break;
|
|
|
|
case SRAM_FRENCH:
|
|
|
|
NinCfg.Language = NIN_LAN_FRENCH;
|
|
|
|
break;
|
|
|
|
case SRAM_SPANISH:
|
|
|
|
NinCfg.Language = NIN_LAN_SPANISH;
|
|
|
|
break;
|
|
|
|
case SRAM_ITALIAN:
|
|
|
|
NinCfg.Language = NIN_LAN_ITALIAN;
|
|
|
|
break;
|
|
|
|
case SRAM_DUTCH:
|
|
|
|
NinCfg.Language = NIN_LAN_DUTCH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NinCfg.Language = NIN_LAN_ENGLISH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-02-25 23:34:52 +01:00
|
|
|
}
|