/**************************************************************************** * 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 . ****************************************************************************/ #include #include #include #include #include #include // for directory parsing and low-level file I/O #include #include #include #include #include "menu/menu.hpp" #include "gc/gc.hpp" #include "gui/text.hpp" #include "devicemounter/DeviceHandler.hpp" #include "gecko/gecko.hpp" #include "fileOps/fileOps.h" #include "homebrew/homebrew.h" #include "loader/utils.h" #include "loader/disc.h" #include "loader/sys.h" #include "memory/memory.h" #include "memory/mem2.hpp" /* since Nintendont v1.98 argsboot is supported. and since wiiflow lite doesn't support versions less than v3.358 we will use argsboot every time. */ // Nintendont NIN_CFG NinCfg; u8 NinDevice = 0; bool NinArgsboot = false; void Nintendont_SetOptions(const char *game, const char *gameID, char *CheatPath, char *NewCheatPath, const char *partition, bool cheats, u8 emuMC, u8 videomode, bool widescreen, bool led, bool native_ctl, bool deflicker, bool wiiu_widescreen, bool NIN_Debugger, bool tri_arcade, bool cc_rumble, bool ipl) { //clear nincfg and set magicbytes now in case of return when NINRev=0 below memset(&NinCfg, 0, sizeof(NIN_CFG)); NinCfg.Magicbytes = 0x01070CF6; //check version u32 NIN_cfg_version = NIN_CFG_VERSION; char NINVersion[7]= ""; u32 NINRev = 0; for(u8 i = SD; i < MAXDEVICES; ++i) { const char *dol_path = fmt(NIN_LOADER_PATH, DeviceName[i]); if(!fsop_FileExist(dol_path)) continue; u8 *buffer = NULL; u32 filesize = 0; const char *str = "$$Version:"; buffer = fsop_ReadFile(dol_path, &filesize); // if buffer is NULL then out of memory - hopefully that doesn't happen and shouldn't for(u32 i = 0; i < filesize; i += 32) { if(memcmp(buffer+i, str, strlen(str)) == 0) { // get nintendont version (NINVersion) from current position in nintendont boot.dol (buffer) snprintf(NINVersion, sizeof(NINVersion), "%s", buffer+i+strlen(str)); // get revision from version and use it to get NinCfg version NINRev = atoi(strchr(NINVersion, '.')+1); break; } } free(buffer); break; } if(NINRev == 0 || NINRev < 358) return;// nintendont not found or revision is less than 358(was 135) thus too old for wiiflow lite /*if(NINRev >= 135 && NINRev < 354) NIN_cfg_version = 3; else if(NINRev >= 354 && NINRev < 358) NIN_cfg_version = 4;*/ else if(NINRev >= 358 && NINRev < 368) NIN_cfg_version = 5; else if(NINRev >= 368 && NINRev < 424) NIN_cfg_version = 6; else if(NINRev >= 424 && NINRev < 431) NIN_cfg_version = 7; NinCfg.Version = NIN_cfg_version; /*if(memcmp("0x474851",gameID,3)==0) // old fix for simpsons hit & run - r155 fixed this NinCfg.MaxPads = 1; else*/ NinCfg.MaxPads = 4; NinCfg.VideoMode |= NIN_VID_FORCE;// always force video? if((videomode > 3) && (videomode != 6)) { NinCfg.Config |= NIN_CFG_FORCE_PROG; NinCfg.VideoMode |= NIN_VID_PROG; } NinCfg.Config |= NIN_CFG_AUTO_BOOT; NinDevice = DeviceHandle.PathToDriveType(game); if(NinDevice != SD) NinCfg.Config |= NIN_CFG_USB; if(NIN_Debugger && IsOnWiiU() == false) //wii only NinCfg.Config |= NIN_CFG_OSREPORT; if(native_ctl && IsOnWiiU() == false) //wii only NinCfg.Config |= NIN_CFG_NATIVE_SI; if(deflicker) NinCfg.VideoMode |= NIN_VID_FORCE_DF; if(wiiu_widescreen && IsOnWiiU() == true) //wii u vwii only NinCfg.Config |= NIN_CFG_WIIU_WIDE; if(widescreen) NinCfg.Config |= NIN_CFG_FORCE_WIDE; if(led) NinCfg.Config |= NIN_CFG_LED; if(tri_arcade) NinCfg.Config |= NIN_CFG_ARCADE_MODE; if(cc_rumble) NinCfg.Config |= NIN_CFG_BIT_CC_RUMBLE; if(ipl) NinCfg.Config |= NIN_CFG_SKIP_IPL; NinCfg.MemCardBlocks = 0x2; //251 blocks if(emuMC > 0 || IsOnWiiU() == true) //force memcardemu for wii u vwii NinCfg.Config |= NIN_CFG_MEMCARDEMU; if(emuMC > 1) { 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; strncpy(NinCfg.GamePath, strchr(game, '/'), 254); if(strstr(NinCfg.GamePath, "boot.bin") != NULL) { *strrchr(NinCfg.GamePath, '/') = '\0'; //boot.bin *(strrchr(NinCfg.GamePath, '/')+1) = '\0'; //sys } memcpy(&NinCfg.GameID, gameID, 4); gprintf("Nintendont Game Path: %s, ID: %08x\n", NinCfg.GamePath, NinCfg.GameID); } void Nintendont_BootDisc(u8 emuMC, bool widescreen, bool cc_rumble, bool native_ctl, bool deflicker) { 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(cc_rumble) NinCfg.Config |= NIN_CFG_BIT_CC_RUMBLE; if(emuMC == 1) { NinCfg.Config |= NIN_CFG_MEMCARDEMU; NinCfg.MemCardBlocks = 0x2;//251 blocks (2MB) } else if(emuMC == 2) { 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"); } void Nintendont_WriteOptions() { gprintf("Writing Arguments\n"); AddBootArgument((char*)&NinCfg, sizeof(NIN_CFG)); } /*void Nintendont_WriteOptions() { // Newer Nintendont versions if(NinArgsboot == true) { gprintf("Writing Arguments\n"); AddBootArgument((char*)&NinCfg, sizeof(NIN_CFG)); return; } // 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)); } }*/ 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; } 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); break; //search for argsboot not needed 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; } } break; } } return ret; } // Devolution u8 *tmp_buffer = NULL; u8 *loader_bin = NULL; u32 loader_size = 0; extern "C" { extern void __exception_closeall(); } static gconfig *DEVO_CONFIG = (gconfig*)0x80000020; #define DEVO_ENTRY ((entry)loader_bin) bool DEVO_Installed(const char *path) { loader_size = 0; bool devo = false; fsop_GetFileSizeBytes(fmt(DEVO_LOADER_PATH, path), &loader_size); if(loader_size > 0x80) //Size should be more than 128b { gprintf("Devolution found\n"); devo = true; } return devo; } void DEVO_GetLoader(const char *path) { loader_size = 0; tmp_buffer = fsop_ReadFile(fmt(DEVO_LOADER_PATH, path), &loader_size); if(tmp_buffer == NULL) gprintf("Devolution: Loader not found!\n"); } void DEVO_SetOptions(const char *isopath, const char *gameID, bool memcard_emu, bool widescreen, bool activity_led, bool wifi) { // re-mount device we need DeviceHandle.MountDevolution(); //start writing cfg to mem struct stat st; int data_fd; char iso2path[256]; iso2path[255] = '\0'; stat(isopath, &st); FILE *f = fopen(isopath, "rb"); gprintf("Devolution: ISO Header %s\n", isopath); fread((u8*)Disc_ID, 1, 32, f); fclose(f); f = NULL; // fill out the Devolution config struct memset(DEVO_CONFIG, 0, sizeof(gconfig)); DEVO_CONFIG->signature = DEVO_CONFIG_SIG; DEVO_CONFIG->version = DEVO_CONFIG_VERSION; DEVO_CONFIG->device_signature = st.st_dev; DEVO_CONFIG->disc1_cluster = st.st_ino; // 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; // If 2nd iso file tell Devo about it strncpy(iso2path, isopath, 255); char *ptz = strstr(iso2path, "game.iso"); if(ptz != NULL) { strncpy(ptz, "gam1.iso", 8); 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"); } } 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); } } // make sure these directories exist, they are required for Devolution to function correctly fsop_MakeFolder(fmt("%s:/apps", DeviceName[currentPartition])); fsop_MakeFolder(fmt("%s:/apps/gc_devo", DeviceName[currentPartition])); if(memcard_emu) { const char *memcard_dir = NULL; // find or create a 16MB memcard file for emulation // this file can be located anywhere since it's passed by cluster, not name // it must be at least 512KB (smallest possible memcard = 59 blocks) if(gameID[3] == 'J') //Japanese Memory Card memcard_dir = fmt("%s:/apps/gc_devo/memcard_jap.bin", DeviceName[currentPartition]); else memcard_dir = fmt("%s:/apps/gc_devo/memcard.bin", DeviceName[currentPartition]); gprintf("Devolution: Memory Card File %s\n", memcard_dir); // check if file doesn't exist if(stat(memcard_dir, &st) == -1 || st.st_size < (1<<19)) { // need to enlarge or create it data_fd = open(memcard_dir, O_WRONLY|O_CREAT); if(data_fd >= 0) { // try to make it 16MB (largest possible memcard = 2043 blocks) gprintf("Devolution: Resizing Memory Card File...\n"); ftruncate(data_fd, 16<<20); if(fstat(data_fd, &st) == -1 || st.st_size < (1<<19)) { // it still isn't big enough. Give up. st.st_ino = 0; } close(data_fd); } else { // couldn't open or create the memory card file st.st_ino = 0; } } gprintf("Devolution: Memory Card at %08x\n", st.st_ino); } else st.st_ino = 0; // 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 DCFlushRange((void*)Disc_ID, 64); DeviceHandle.UnMountDevolution(); } void DEVO_Boot() { /* 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)); /* Boot that binary */ JumpToEntry(DEVO_ENTRY); } // General #define SRAM_ENGLISH 0 #define SRAM_GERMAN 1 #define SRAM_FRENCH 2 #define SRAM_SPANISH 3 #define SRAM_ITALIAN 4 #define SRAM_DUTCH 5 extern "C" { syssram* __SYS_LockSram(); u32 __SYS_UnlockSram(u32 write); u32 __SYS_SyncSram(void); } void GC_SetVideoMode(u8 videomode, u8 loader) { syssram *sram; sram = __SYS_LockSram(); GXRModeObj *vmode = VIDEO_GetPreferredMode(0); int vmode_reg = 0;// VI_NTSC if((VIDEO_HaveComponentCable() && (CONF_GetProgressiveScan() > 0)) || ((videomode > 3) && (videomode != 6))) sram->flags |= 0x80; //set progressive flag else sram->flags &= 0x7F; //clear progressive flag if(videomode == 1 || videomode == 3 || videomode == 5 || videomode == 6 || videomode == 7) { vmode_reg = 1;// VI_PAL sram->flags |= 0x01; // Set bit 0 to set the video mode to PAL sram->ntd |= 0x40; //set pal60 flag } else { sram->flags &= 0xFE; // Clear bit 0 to set the video mode to NTSC sram->ntd &= 0xBF; //clear pal60 flag } /* should the sram pal60 flag be cleared for PAL50? */ if(videomode == 1)// PAL50 { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_PAL50; vmode = &TVPal528IntDf; } else if(videomode == 2)// NTSC { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_NTSC; vmode = &TVNtsc480IntDf; } else if(videomode == 3)// PAL60 { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_PAL60; vmode = &TVEurgb60Hz480IntDf; vmode_reg = 5;// VI_EURGB60 } else if(videomode == 4)// NTSC 480P { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_NTSC; vmode = &TVNtsc480Prog; } else if(videomode == 5)// PAL 480P { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_PAL60; vmode = &TVEurgb60Hz480Prog; vmode_reg = 5; } else if(videomode == 6)// MPAL { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_MPAL; vmode = &TVEurgb60Hz480IntDf; vmode_reg = 2;// VI_MPAL } else if(videomode == 7)// MPAL Prog { if(loader == 1) NinCfg.VideoMode |= NIN_VID_FORCE_MPAL; vmode = &TVEurgb60Hz480Prog; vmode_reg = 2; } __SYS_UnlockSram(1); // 1 -> write changes while(!__SYS_SyncSram()); /* 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(); } 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; } } void GC_SetLanguage(u8 lang, u8 loader) { 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()); /* write language for nintendont */ if(loader == 1) { 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; } } }