mirror of
https://github.com/wiiu-env/AutobootModule.git
synced 2024-11-22 10:59:15 +01:00
Wait for USB devices until they are ready, reduce screen corruption, refactor code
This commit is contained in:
parent
c93d45fb38
commit
93ce6e97ac
62
source/BootUtils.cpp
Normal file
62
source/BootUtils.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "BootUtils.h"
|
||||||
|
|
||||||
|
#include <nn/cmpt/cmpt.h>
|
||||||
|
#include <nn/act.h>
|
||||||
|
#include <sysapp/launch.h>
|
||||||
|
#include <sysapp/title.h>
|
||||||
|
#include <padscore/kpad.h>
|
||||||
|
|
||||||
|
void bootWiiUMenu() {
|
||||||
|
nn::act::Initialize();
|
||||||
|
nn::act::SlotNo slot = nn::act::GetSlotNo();
|
||||||
|
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
|
||||||
|
nn::act::Finalize();
|
||||||
|
|
||||||
|
if (defaultSlot) { //normal menu boot
|
||||||
|
SYSLaunchMenu();
|
||||||
|
} else { //show mii select
|
||||||
|
_SYSLaunchMenuWithCheckingAccount(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootHomebrewLauncher() {
|
||||||
|
uint64_t titleId = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER);
|
||||||
|
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void launchvWiiTitle(uint32_t titleId_low, uint32_t titleId_high) {
|
||||||
|
// we need to init kpad for cmpt
|
||||||
|
KPADInit();
|
||||||
|
|
||||||
|
// Try to find a screen type that works
|
||||||
|
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_BOTH);
|
||||||
|
if (CMPTCheckScreenState() < 0) {
|
||||||
|
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_DRC);
|
||||||
|
if (CMPTCheckScreenState() < 0) {
|
||||||
|
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_TV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t dataSize = 0;
|
||||||
|
CMPTGetDataSize(&dataSize);
|
||||||
|
|
||||||
|
void *dataBuffer = memalign(0x40, dataSize);
|
||||||
|
|
||||||
|
if (titleId_low == 0 && titleId_high == 0) {
|
||||||
|
CMPTLaunchMenu(dataBuffer, dataSize);
|
||||||
|
} else {
|
||||||
|
CMPTLaunchTitle(dataBuffer, dataSize, titleId_low, titleId_high);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dataBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootvWiiMenu() {
|
||||||
|
launchvWiiTitle(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootHomebrewChannel() {
|
||||||
|
launchvWiiTitle(0x00010001, 0x4f484243); // 'OHBC'
|
||||||
|
}
|
11
source/BootUtils.h
Normal file
11
source/BootUtils.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
void bootWiiUMenu();
|
||||||
|
|
||||||
|
void bootHomebrewLauncher();
|
||||||
|
|
||||||
|
void bootvWiiMenu();
|
||||||
|
|
||||||
|
void bootHomebrewChannel();
|
@ -1,4 +1,5 @@
|
|||||||
#include "DrawUtils.h"
|
#include "DrawUtils.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <coreinit/memory.h>
|
#include <coreinit/memory.h>
|
||||||
@ -7,6 +8,7 @@
|
|||||||
#include <png.h>
|
#include <png.h>
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
#include "MenuUtils.h"
|
||||||
|
|
||||||
// buffer width
|
// buffer width
|
||||||
#define TV_WIDTH 0x500
|
#define TV_WIDTH 0x500
|
||||||
@ -24,6 +26,25 @@ static FT_Library ft_lib = nullptr;
|
|||||||
static FT_Face ft_face = nullptr;
|
static FT_Face ft_face = nullptr;
|
||||||
static Color font_col = {0xFFFFFFFF};
|
static Color font_col = {0xFFFFFFFF};
|
||||||
|
|
||||||
|
void* DrawUtils::InitOSScreen(){
|
||||||
|
OSScreenInit();
|
||||||
|
|
||||||
|
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||||
|
uint32_t drcBufferSize = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
auto *screenBuffer = (uint8_t *) memalign(0x100, tvBufferSize + drcBufferSize);
|
||||||
|
if (screenBuffer == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
||||||
|
OSScreenSetBufferEx(SCREEN_DRC, screenBuffer + tvBufferSize);
|
||||||
|
|
||||||
|
OSScreenEnableEx(SCREEN_TV, TRUE);
|
||||||
|
OSScreenEnableEx(SCREEN_DRC, TRUE);
|
||||||
|
return screenBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
void DrawUtils::initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize)
|
void DrawUtils::initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize)
|
||||||
{
|
{
|
||||||
DrawUtils::tvBuffer = (uint8_t*) tvBuffer;
|
DrawUtils::tvBuffer = (uint8_t*) tvBuffer;
|
||||||
|
@ -25,6 +25,7 @@ union Color {
|
|||||||
|
|
||||||
class DrawUtils {
|
class DrawUtils {
|
||||||
public:
|
public:
|
||||||
|
static void* InitOSScreen();
|
||||||
static void initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize);
|
static void initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize);
|
||||||
static void beginDraw();
|
static void beginDraw();
|
||||||
static void endDraw();
|
static void endDraw();
|
||||||
|
156
source/MenuUtils.cpp
Normal file
156
source/MenuUtils.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "MenuUtils.h"
|
||||||
|
#include "DrawUtils.h"
|
||||||
|
|
||||||
|
#include <coreinit/screen.h>
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <vpad/input.h>
|
||||||
|
#include <gx2/state.h>
|
||||||
|
|
||||||
|
#include "icon_png.h"
|
||||||
|
|
||||||
|
const char *menu_options[] = {
|
||||||
|
"Wii U Menu",
|
||||||
|
"Homebrew Launcher",
|
||||||
|
"vWii System Menu",
|
||||||
|
"vWii Homebrew Channel",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *autoboot_config_strings[] = {
|
||||||
|
"wiiu_menu",
|
||||||
|
"homebrew_launcher",
|
||||||
|
"vwii_system_menu",
|
||||||
|
"vwii_homebrew_channel",
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int32_t readAutobootOption(std::string &configPath) {
|
||||||
|
FILE *f = fopen(configPath.c_str(), "r");
|
||||||
|
if (f) {
|
||||||
|
char buf[128]{};
|
||||||
|
fgets(buf, sizeof(buf), f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < sizeof(autoboot_config_strings) / sizeof(char *); i++) {
|
||||||
|
if (strncmp(autoboot_config_strings[i], buf, strlen(autoboot_config_strings[i])) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeAutobootOption(std::string &configPath, int32_t autobootOption) {
|
||||||
|
FILE *f = fopen(configPath.c_str(), "w");
|
||||||
|
if (f) {
|
||||||
|
if (autobootOption >= 0) {
|
||||||
|
fputs(autoboot_config_strings[autobootOption], f);
|
||||||
|
} else {
|
||||||
|
fputs("none", f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput) {
|
||||||
|
auto screenBuffer = DrawUtils::InitOSScreen();
|
||||||
|
if (!screenBuffer) {
|
||||||
|
OSFatal("Failed to alloc memory for screen");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||||
|
uint32_t drcBufferSize = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||||
|
|
||||||
|
DrawUtils::initBuffers(screenBuffer, tvBufferSize, screenBuffer + tvBufferSize, drcBufferSize);
|
||||||
|
DrawUtils::initFont();
|
||||||
|
|
||||||
|
uint32_t selected = autobootOptionInput > 0 ? autobootOptionInput : 0;
|
||||||
|
int autoboot = autobootOptionInput;
|
||||||
|
bool redraw = true;
|
||||||
|
while (true) {
|
||||||
|
VPADStatus vpad{};
|
||||||
|
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
||||||
|
|
||||||
|
if (vpad.trigger & VPAD_BUTTON_UP) {
|
||||||
|
if (selected > 0) {
|
||||||
|
selected--;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
} else if (vpad.trigger & VPAD_BUTTON_DOWN) {
|
||||||
|
if (selected < sizeof(menu_options) / sizeof(char *) - 1) {
|
||||||
|
selected++;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
} else if (vpad.trigger & VPAD_BUTTON_A) {
|
||||||
|
break;
|
||||||
|
} else if (vpad.trigger & VPAD_BUTTON_X) {
|
||||||
|
autoboot = -1;
|
||||||
|
redraw = true;
|
||||||
|
} else if (vpad.trigger & VPAD_BUTTON_Y) {
|
||||||
|
autoboot = selected;
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redraw) {
|
||||||
|
DrawUtils::beginDraw();
|
||||||
|
DrawUtils::clear(COLOR_BACKGROUND);
|
||||||
|
|
||||||
|
// draw buttons
|
||||||
|
uint32_t index = 8 + 24 + 8 + 4;
|
||||||
|
for (uint32_t i = 0; i < sizeof(menu_options) / sizeof(char *); i++) {
|
||||||
|
if (i == selected) {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||||
|
} else {
|
||||||
|
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, (i == (uint32_t) autoboot) ? COLOR_AUTOBOOT : COLOR_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawUtils::setFontSize(24);
|
||||||
|
DrawUtils::setFontColor((i == (uint32_t) autoboot) ? COLOR_AUTOBOOT : COLOR_TEXT);
|
||||||
|
DrawUtils::print(16 * 2, index + 8 + 24, menu_options[i]);
|
||||||
|
index += 42 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawUtils::setFontColor(COLOR_TEXT);
|
||||||
|
|
||||||
|
// draw top bar
|
||||||
|
DrawUtils::setFontSize(24);
|
||||||
|
DrawUtils::drawPNG(16, 2, icon_png);
|
||||||
|
DrawUtils::print(64 + 2, 6 + 24, "Tiramisu Boot Selector");
|
||||||
|
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
||||||
|
|
||||||
|
// draw bottom bar
|
||||||
|
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
||||||
|
DrawUtils::setFontSize(18);
|
||||||
|
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||||
|
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue000 Choose", true);
|
||||||
|
const char *autobootHints = "\ue002 Clear Autoboot / \ue003 Select Autoboot";
|
||||||
|
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(autobootHints) / 2, SCREEN_HEIGHT - 8, autobootHints, true);
|
||||||
|
|
||||||
|
DrawUtils::endDraw();
|
||||||
|
|
||||||
|
redraw = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawUtils::beginDraw();
|
||||||
|
DrawUtils::clear(COLOR_BLACK);
|
||||||
|
DrawUtils::endDraw();
|
||||||
|
|
||||||
|
DrawUtils::deinitFont();
|
||||||
|
|
||||||
|
// Call GX2Init to shut down OSScreen
|
||||||
|
GX2Init(nullptr);
|
||||||
|
|
||||||
|
free(screenBuffer);
|
||||||
|
|
||||||
|
if (autoboot != autobootOptionInput) {
|
||||||
|
writeAutobootOption(configPath, autoboot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
26
source/MenuUtils.h
Normal file
26
source/MenuUtils.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define COLOR_WHITE Color(0xffffffff)
|
||||||
|
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||||
|
#define COLOR_BACKGROUND COLOR_BLACK
|
||||||
|
#define COLOR_TEXT COLOR_WHITE
|
||||||
|
#define COLOR_TEXT2 Color(0xB3ffffff)
|
||||||
|
#define COLOR_AUTOBOOT Color(0xaeea00ff)
|
||||||
|
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||||
|
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BOOT_OPTION_WII_U_MENU,
|
||||||
|
BOOT_OPTION_HOMEBREW_LAUNCHER,
|
||||||
|
BOOT_OPTION_VWII_SYSTEM_MENU,
|
||||||
|
BOOT_OPTION_VWII_HOMEBREW_CHANNEL,
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t readAutobootOption(std::string &configPath);
|
||||||
|
|
||||||
|
void writeAutobootOption(std::string &configPath, int32_t autobootOption);
|
||||||
|
|
||||||
|
int32_t handleMenuScreen(std::string &configPath, int32_t autobootOptionInput);
|
221
source/QuickStartUtils.cpp
Normal file
221
source/QuickStartUtils.cpp
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "QuickStartUtils.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "BootUtils.h"
|
||||||
|
|
||||||
|
#include <coreinit/exit.h>
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <coreinit/memdefaultheap.h>
|
||||||
|
#include <coreinit/foreground.h>
|
||||||
|
#include <nn/acp/title.h>
|
||||||
|
#include <nn/act/client_cpp.h>
|
||||||
|
#include <nn/ccr/sys_caffeine.h>
|
||||||
|
#include <nn/sl.h>
|
||||||
|
#include <sysapp/title.h>
|
||||||
|
#include <sysapp/launch.h>
|
||||||
|
#include <proc_ui/procui.h>
|
||||||
|
|
||||||
|
extern "C" void __fini_wut();
|
||||||
|
|
||||||
|
static void StartAppletAndExit() {
|
||||||
|
DEBUG_FUNCTION_LINE("Wait for applet");
|
||||||
|
ProcUIInit(OSSavesDone_ReadyToRelease);
|
||||||
|
|
||||||
|
bool doProcUi = true;
|
||||||
|
bool launchWiiUMenuOnNextForeground = false;
|
||||||
|
while (true) {
|
||||||
|
switch (ProcUIProcessMessages(true)) {
|
||||||
|
case PROCUI_STATUS_EXITING: {
|
||||||
|
doProcUi = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PROCUI_STATUS_RELEASE_FOREGROUND: {
|
||||||
|
ProcUIDrawDoneRelease();
|
||||||
|
launchWiiUMenuOnNextForeground = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PROCUI_STATUS_IN_FOREGROUND: {
|
||||||
|
if (launchWiiUMenuOnNextForeground) {
|
||||||
|
bootWiiUMenu();
|
||||||
|
launchWiiUMenuOnNextForeground = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PROCUI_STATUS_IN_BACKGROUND: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(1));
|
||||||
|
if (!doProcUi) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProcUIShutdown();
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Exit to Wii U Menu");
|
||||||
|
|
||||||
|
deinitLogging();
|
||||||
|
__fini_wut();
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int32_t SYSSwitchToBrowser(void *);
|
||||||
|
extern "C" int32_t SYSSwitchToEShop(void *);
|
||||||
|
extern "C" int32_t _SYSSwitchTo(uint32_t pfid);
|
||||||
|
|
||||||
|
void loadConsoleAccount(const char *data_uuid) {
|
||||||
|
nn::act::Initialize();
|
||||||
|
for (int32_t i = 0; i < 13; i++) {
|
||||||
|
char uuid[16];
|
||||||
|
auto result = nn::act::GetUuidEx(uuid, i);
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
if (memcmp(uuid, data_uuid, 8) == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Load Console account %d", i);
|
||||||
|
nn::act::LoadConsoleAccount(i, 0, nullptr, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nn::act::Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getQuickBoot() {
|
||||||
|
auto bootCheck = CCRSysCaffeineBootCheck();
|
||||||
|
if (bootCheck == 0) {
|
||||||
|
nn::sl::Initialize(MEMAllocFromDefaultHeapEx, MEMFreeToDefaultHeap);
|
||||||
|
char path[0x80];
|
||||||
|
nn::sl::GetDefaultDatabasePath(path, 0x80, 0x0005001010066000); // ECO process
|
||||||
|
FSCmdBlock cmdBlock;
|
||||||
|
FSInitCmdBlock(&cmdBlock);
|
||||||
|
|
||||||
|
auto fileStream = new nn::sl::FileStream;
|
||||||
|
auto *fsClient = (FSClient *) memalign(0x40, sizeof(FSClient));
|
||||||
|
memset(fsClient, 0, sizeof(*fsClient));
|
||||||
|
FSAddClient(fsClient, FS_ERROR_FLAG_NONE);
|
||||||
|
|
||||||
|
fileStream->Initialize(fsClient, &cmdBlock, path, "r");
|
||||||
|
|
||||||
|
auto database = new nn::sl::LaunchInfoDatabase;
|
||||||
|
database->Load(fileStream, nn::sl::REGION_EUR);
|
||||||
|
|
||||||
|
CCRAppLaunchParam data; // load sys caffeine data
|
||||||
|
// load app launch param
|
||||||
|
CCRSysCaffeineGetAppLaunchParam(&data);
|
||||||
|
|
||||||
|
// get launch info for id
|
||||||
|
nn::sl::LaunchInfo info;
|
||||||
|
auto result = database->GetLaunchInfoById(&info, data.titleId);
|
||||||
|
|
||||||
|
delete database;
|
||||||
|
delete fileStream;
|
||||||
|
|
||||||
|
FSDelClient(fsClient, FS_ERROR_FLAG_NONE);
|
||||||
|
|
||||||
|
nn::sl::Finalize();
|
||||||
|
|
||||||
|
if (!result.IsSuccess()) {
|
||||||
|
DEBUG_FUNCTION_LINE("GetLaunchInfoById failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Trying to autoboot for titleId %016llX", info.titleId);
|
||||||
|
|
||||||
|
if (info.titleId == 0x0005001010040000L ||
|
||||||
|
info.titleId == 0x0005001010040100L ||
|
||||||
|
info.titleId == 0x0005001010040200L) {
|
||||||
|
DEBUG_FUNCTION_LINE("Skip quick starting into the Wii U Menu");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.titleId == 0x000500301001220AL ||
|
||||||
|
info.titleId == 0x000500301001210AL ||
|
||||||
|
info.titleId == 0x000500301001200AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching the browser");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
SYSSwitchToBrowser(nullptr);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.titleId == 0x000500301001400AL ||
|
||||||
|
info.titleId == 0x000500301001410AL ||
|
||||||
|
info.titleId == 0x000500301001420AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching the Eshop");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
SYSSwitchToEShop(nullptr);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.titleId == 0x000500301001800AL ||
|
||||||
|
info.titleId == 0x000500301001810AL ||
|
||||||
|
info.titleId == 0x000500301001820AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching the Download Management");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
_SYSSwitchTo(12);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.titleId == 0x000500301001600AL ||
|
||||||
|
info.titleId == 0x000500301001610AL ||
|
||||||
|
info.titleId == 0x000500301001620AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching Miiverse");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
_SYSSwitchTo(9);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.titleId == 0x000500301001500AL ||
|
||||||
|
info.titleId == 0x000500301001510AL ||
|
||||||
|
info.titleId == 0x000500301001520AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching Friendlist");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
_SYSSwitchTo(11);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.titleId == 0x000500301001300AL ||
|
||||||
|
info.titleId == 0x000500301001310AL ||
|
||||||
|
info.titleId == 0x000500301001320AL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Launching TVii");
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
_SYSSwitchTo(3);
|
||||||
|
|
||||||
|
StartAppletAndExit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SYSCheckTitleExists(info.titleId)) {
|
||||||
|
DEBUG_FUNCTION_LINE("Title %016llX doesn't exist", info.titleId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPTitleListType titleInfo;
|
||||||
|
int32_t handle = MCP_Open();
|
||||||
|
auto err = MCP_GetTitleInfo(handle, info.titleId, &titleInfo);
|
||||||
|
MCP_Close(handle);
|
||||||
|
if (err == 0) {
|
||||||
|
loadConsoleAccount(data.uuid);
|
||||||
|
ACPAssignTitlePatch(&titleInfo);
|
||||||
|
_SYSLaunchTitleWithStdArgsInNoSplash(info.titleId, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE("No quick start");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
3
source/QuickStartUtils.h
Normal file
3
source/QuickStartUtils.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
bool getQuickBoot();
|
144
source/StorageUtils.cpp
Normal file
144
source/StorageUtils.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include <cstdlib>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "StorageUtils.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <coreinit/title.h>
|
||||||
|
#include <nn/spm.h>
|
||||||
|
#include <nn/acp/save.h>
|
||||||
|
#include <nsysuhs/uhs.h>
|
||||||
|
#include <sysapp/title.h>
|
||||||
|
|
||||||
|
static void InitEmptyExternalStorage() {
|
||||||
|
DEBUG_FUNCTION_LINE("Fallback to empty ExtendedStorage");
|
||||||
|
nn::spm::VolumeId empty{};
|
||||||
|
nn::spm::SetDefaultExtendedStorageVolumeId(empty);
|
||||||
|
|
||||||
|
nn::spm::StorageIndex storageIndex = 0;
|
||||||
|
nn::spm::SetExtendedStorage(&storageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int numberUSBStorageDevicesConnected() {
|
||||||
|
DEBUG_FUNCTION_LINE("Check if USB Storage is connected");
|
||||||
|
auto *handle = (UhsHandle *) memalign(0x40, sizeof(UhsHandle));
|
||||||
|
if (!handle) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(handle, 0, sizeof(UhsHandle));
|
||||||
|
auto *config = (UhsConfig *) memalign(0x40, sizeof(UhsConfig));
|
||||||
|
if (!config) {
|
||||||
|
free(config);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
memset(config, 0, sizeof(UhsConfig));
|
||||||
|
|
||||||
|
config->controller_num = 0;
|
||||||
|
uint32_t size = 5120;
|
||||||
|
void *buffer = memalign(0x40, size);
|
||||||
|
if (buffer == nullptr) {
|
||||||
|
free(handle);
|
||||||
|
free(config);
|
||||||
|
}
|
||||||
|
memset(buffer, 0, size);
|
||||||
|
|
||||||
|
config->buffer = buffer;
|
||||||
|
config->buffer_size = size;
|
||||||
|
|
||||||
|
if (UhsClientOpen(handle, config) != UHS_STATUS_OK) {
|
||||||
|
DEBUG_FUNCTION_LINE("UhsClient failed");
|
||||||
|
free(handle);
|
||||||
|
free(config);
|
||||||
|
free(buffer);
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
UhsInterfaceProfile profiles[10];
|
||||||
|
UhsInterfaceFilter filter = {
|
||||||
|
.match_params = MATCH_ANY
|
||||||
|
};
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
if ((result = UhsQueryInterfaces(handle, &filter, profiles, 10)) <= UHS_STATUS_OK) {
|
||||||
|
DEBUG_FUNCTION_LINE("UhsQueryInterfaces failed");
|
||||||
|
UhsClientClose(handle);
|
||||||
|
free(handle);
|
||||||
|
free(config);
|
||||||
|
free(buffer);
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto found = 0;
|
||||||
|
for (int i = 0; i < result; i++) {
|
||||||
|
if (profiles[i].if_desc.bInterfaceClass == USBCLASS_STORAGE) {
|
||||||
|
DEBUG_FUNCTION_LINE("Found USBCLASS_STORAGE");
|
||||||
|
found++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UhsClientClose(handle);
|
||||||
|
free(handle);
|
||||||
|
free(config);
|
||||||
|
free(config->buffer);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initExternalStorage() {
|
||||||
|
if (OSGetTitleID() == _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER)) {
|
||||||
|
// nn::spm functions always call OSFatal when they fail, so we make sure have permission to use
|
||||||
|
// the lib before actually using it.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int connectedStorage = 0;
|
||||||
|
if ((connectedStorage = numberUSBStorageDevicesConnected()) <= 0) {
|
||||||
|
nn::spm::Initialize();
|
||||||
|
InitEmptyExternalStorage();
|
||||||
|
nn::spm::Finalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Connected StorageDevices = %d", connectedStorage);
|
||||||
|
|
||||||
|
nn::spm::Initialize();
|
||||||
|
|
||||||
|
nn::spm::StorageListItem items[0x20];
|
||||||
|
int tries = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
while (tries < 600) {
|
||||||
|
int32_t numItems = nn::spm::GetStorageList(items, 0x20);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Number of items: %d", numItems);
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < numItems; i++) {
|
||||||
|
if (items[i].type == nn::spm::STORAGE_TYPE_WFS) {
|
||||||
|
nn::spm::StorageInfo info{};
|
||||||
|
if (nn::spm::GetStorageInfo(&info, &items[i].index) == 0) {
|
||||||
|
DEBUG_FUNCTION_LINE("Using %s for extended storage", info.path);
|
||||||
|
|
||||||
|
nn::spm::SetExtendedStorage(&items[i].index);
|
||||||
|
ACPMountExternalStorage();
|
||||||
|
|
||||||
|
nn::spm::SetDefaultExtendedStorageVolumeId(info.volumeId);
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found || (connectedStorage == numItems)) {
|
||||||
|
DEBUG_FUNCTION_LINE("Found all expected items, breaking.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(16));
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
DEBUG_FUNCTION_LINE("USB Storage is connected but either it's not connected or we ran into a timeout.");
|
||||||
|
InitEmptyExternalStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
nn::spm::Finalize();
|
||||||
|
}
|
||||||
|
|
3
source/StorageUtils.h
Normal file
3
source/StorageUtils.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void initExternalStorage();
|
38
source/logger.cpp
Normal file
38
source/logger.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <whb/log_cafe.h>
|
||||||
|
#include <whb/log_udp.h>
|
||||||
|
#include <whb/log_module.h>
|
||||||
|
|
||||||
|
uint32_t moduleLogInit = false;
|
||||||
|
uint32_t cafeLogInit = false;
|
||||||
|
uint32_t udpLogInit = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void initLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!(moduleLogInit = WHBLogModuleInit())) {
|
||||||
|
cafeLogInit = WHBLogCafeInit();
|
||||||
|
udpLogInit = WHBLogUdpInit();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinitLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (moduleLogInit) {
|
||||||
|
WHBLogModuleDeinit();
|
||||||
|
moduleLogInit = false;
|
||||||
|
}
|
||||||
|
if (cafeLogInit) {
|
||||||
|
WHBLogCafeDeinit();
|
||||||
|
cafeLogInit = false;
|
||||||
|
}
|
||||||
|
if (udpLogInit) {
|
||||||
|
WHBLogUdpDeinit();
|
||||||
|
udpLogInit = false;
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
@ -28,6 +28,10 @@ extern "C" {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void initLogging();
|
||||||
|
|
||||||
|
void deinitLogging();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
512
source/main.cpp
512
source/main.cpp
@ -1,524 +1,55 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <gx2/state.h>
|
|
||||||
#include <coreinit/debug.h>
|
|
||||||
#include <coreinit/thread.h>
|
|
||||||
#include <coreinit/foreground.h>
|
|
||||||
#include <coreinit/screen.h>
|
|
||||||
#include <coreinit/filesystem.h>
|
|
||||||
#include <coreinit/memdefaultheap.h>
|
|
||||||
#include <coreinit/title.h>
|
|
||||||
#include <vpad/input.h>
|
#include <vpad/input.h>
|
||||||
#include <sysapp/launch.h>
|
#include <coreinit/debug.h>
|
||||||
#include <sysapp/title.h>
|
#include <gx2/state.h>
|
||||||
#include <padscore/kpad.h>
|
#include "StorageUtils.h"
|
||||||
#include <proc_ui/procui.h>
|
#include "QuickStartUtils.h"
|
||||||
#include <nn/acp.h>
|
|
||||||
#include <nn/act.h>
|
|
||||||
#include <nn/cmpt.h>
|
|
||||||
#include <nn/ccr/sys_caffeine.h>
|
|
||||||
#include <nn/sl.h>
|
|
||||||
#include <nn/spm.h>
|
|
||||||
|
|
||||||
#include <whb/log_module.h>
|
|
||||||
#include <whb/log_udp.h>
|
|
||||||
#include <whb/log_cafe.h>
|
|
||||||
|
|
||||||
#include "DrawUtils.h"
|
#include "DrawUtils.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "icon_png.h"
|
|
||||||
|
|
||||||
#define COLOR_WHITE Color(0xffffffff)
|
#include "BootUtils.h"
|
||||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
#include "MenuUtils.h"
|
||||||
#define COLOR_BACKGROUND COLOR_BLACK
|
|
||||||
#define COLOR_TEXT COLOR_WHITE
|
|
||||||
#define COLOR_TEXT2 Color(0xB3ffffff)
|
|
||||||
#define COLOR_AUTOBOOT Color(0xaeea00ff)
|
|
||||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
|
||||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4ff)
|
|
||||||
|
|
||||||
void bootWiiUMenu();
|
void clearScreen() {
|
||||||
|
auto buffer = DrawUtils::InitOSScreen();
|
||||||
void StartAppletAndExit() {
|
if (!buffer) {
|
||||||
DEBUG_FUNCTION_LINE("Wait for applet");
|
OSFatal("Failed to alloc memory for screen");
|
||||||
ProcUIInit(OSSavesDone_ReadyToRelease);
|
|
||||||
|
|
||||||
bool doProcUi = true;
|
|
||||||
bool launchWiiUMenuOnNextForeground = false;
|
|
||||||
while (true) {
|
|
||||||
switch (ProcUIProcessMessages(true)) {
|
|
||||||
case PROCUI_STATUS_EXITING: {
|
|
||||||
doProcUi = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PROCUI_STATUS_RELEASE_FOREGROUND: {
|
|
||||||
ProcUIDrawDoneRelease();
|
|
||||||
launchWiiUMenuOnNextForeground = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PROCUI_STATUS_IN_FOREGROUND: {
|
|
||||||
if (launchWiiUMenuOnNextForeground) {
|
|
||||||
bootWiiUMenu();
|
|
||||||
launchWiiUMenuOnNextForeground = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PROCUI_STATUS_IN_BACKGROUND: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
OSSleepTicks(OSMillisecondsToTicks(1));
|
|
||||||
if (!doProcUi) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ProcUIShutdown();
|
DrawUtils::clear(COLOR_BACKGROUND);
|
||||||
DEBUG_FUNCTION_LINE("Exit to Wii U Menu");
|
|
||||||
_Exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BOOT_OPTION_WII_U_MENU,
|
|
||||||
BOOT_OPTION_HOMEBREW_LAUNCHER,
|
|
||||||
BOOT_OPTION_VWII_SYSTEM_MENU,
|
|
||||||
BOOT_OPTION_VWII_HOMEBREW_CHANNEL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *menu_options[] = {
|
|
||||||
"Wii U Menu",
|
|
||||||
"Homebrew Launcher",
|
|
||||||
"vWii System Menu",
|
|
||||||
"vWii Homebrew Channel",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *autoboot_config_strings[] = {
|
|
||||||
"wiiu_menu",
|
|
||||||
"homebrew_launcher",
|
|
||||||
"vwii_system_menu",
|
|
||||||
"vwii_homebrew_channel",
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string configPath;
|
|
||||||
|
|
||||||
int32_t readAutobootOption() {
|
|
||||||
FILE *f = fopen(configPath.c_str(), "r");
|
|
||||||
if (f) {
|
|
||||||
char buf[128]{};
|
|
||||||
fgets(buf, sizeof(buf), f);
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sizeof(autoboot_config_strings) / sizeof(char *); i++) {
|
|
||||||
if (strncmp(autoboot_config_strings[i], buf, strlen(autoboot_config_strings[i])) == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeAutobootOption(int32_t autobootOption) {
|
|
||||||
FILE *f = fopen(configPath.c_str(), "w");
|
|
||||||
if (f) {
|
|
||||||
if (autobootOption >= 0) {
|
|
||||||
fputs(autoboot_config_strings[autobootOption], f);
|
|
||||||
} else {
|
|
||||||
fputs("none", f);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int32_t SYSSwitchToBrowser(void *);
|
|
||||||
extern "C" int32_t SYSSwitchToEShop(void *);
|
|
||||||
extern "C" int32_t _SYSSwitchTo(uint32_t pfid);
|
|
||||||
|
|
||||||
void loadConsoleAccount(const char *data_uuid) {
|
|
||||||
nn::act::Initialize();
|
|
||||||
for (int32_t i = 0; i < 13; i++) {
|
|
||||||
char uuid[16];
|
|
||||||
auto result = nn::act::GetUuidEx(uuid, i);
|
|
||||||
if (result.IsSuccess()) {
|
|
||||||
if (memcmp(uuid, data_uuid, 8) == 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("Load Console account %d", i);
|
|
||||||
nn::act::LoadConsoleAccount(i, 0, nullptr, false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nn::act::Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getQuickBoot() {
|
|
||||||
auto bootCheck = CCRSysCaffeineBootCheck();
|
|
||||||
if (bootCheck == 0) {
|
|
||||||
nn::sl::Initialize(MEMAllocFromDefaultHeapEx, MEMFreeToDefaultHeap);
|
|
||||||
char path[0x80];
|
|
||||||
nn::sl::GetDefaultDatabasePath(path, 0x80, 0x0005001010066000); // ECO process
|
|
||||||
FSCmdBlock cmdBlock;
|
|
||||||
FSInitCmdBlock(&cmdBlock);
|
|
||||||
|
|
||||||
auto fileStream = new nn::sl::FileStream;
|
|
||||||
auto *fsClient = (FSClient *) memalign(0x40, sizeof(FSClient));
|
|
||||||
memset(fsClient, 0, sizeof(*fsClient));
|
|
||||||
FSAddClient(fsClient, FS_ERROR_FLAG_NONE);
|
|
||||||
|
|
||||||
fileStream->Initialize(fsClient, &cmdBlock, path, "r");
|
|
||||||
|
|
||||||
auto database = new nn::sl::LaunchInfoDatabase;
|
|
||||||
database->Load(fileStream, nn::sl::REGION_EUR);
|
|
||||||
|
|
||||||
CCRAppLaunchParam data; // load sys caffeine data
|
|
||||||
// load app launch param
|
|
||||||
CCRSysCaffeineGetAppLaunchParam(&data);
|
|
||||||
|
|
||||||
// get launch info for id
|
|
||||||
nn::sl::LaunchInfo info;
|
|
||||||
auto result = database->GetLaunchInfoById(&info, data.titleId);
|
|
||||||
|
|
||||||
delete database;
|
|
||||||
delete fileStream;
|
|
||||||
|
|
||||||
FSDelClient(fsClient, FS_ERROR_FLAG_NONE);
|
|
||||||
|
|
||||||
nn::sl::Finalize();
|
|
||||||
|
|
||||||
if (!result.IsSuccess()) {
|
|
||||||
DEBUG_FUNCTION_LINE("GetLaunchInfoById failed.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Trying to autoboot for titleId %016llX", info.titleId);
|
|
||||||
|
|
||||||
if (info.titleId == 0x0005001010040000L ||
|
|
||||||
info.titleId == 0x0005001010040100L ||
|
|
||||||
info.titleId == 0x0005001010040200L) {
|
|
||||||
DEBUG_FUNCTION_LINE("Skip quick booting into the Wii U Menu");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.titleId == 0x000500301001220AL ||
|
|
||||||
info.titleId == 0x000500301001210AL ||
|
|
||||||
info.titleId == 0x000500301001200AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching the browser");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
SYSSwitchToBrowser(nullptr);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (info.titleId == 0x000500301001400AL ||
|
|
||||||
info.titleId == 0x000500301001410AL ||
|
|
||||||
info.titleId == 0x000500301001420AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching the Eshop");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
SYSSwitchToEShop(nullptr);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (info.titleId == 0x000500301001800AL ||
|
|
||||||
info.titleId == 0x000500301001810AL ||
|
|
||||||
info.titleId == 0x000500301001820AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching the Download Management");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
_SYSSwitchTo(12);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (info.titleId == 0x000500301001600AL ||
|
|
||||||
info.titleId == 0x000500301001610AL ||
|
|
||||||
info.titleId == 0x000500301001620AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching Miiverse");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
_SYSSwitchTo(9);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (info.titleId == 0x000500301001500AL ||
|
|
||||||
info.titleId == 0x000500301001510AL ||
|
|
||||||
info.titleId == 0x000500301001520AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching Friendlist");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
_SYSSwitchTo(11);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (info.titleId == 0x000500301001300AL ||
|
|
||||||
info.titleId == 0x000500301001310AL ||
|
|
||||||
info.titleId == 0x000500301001320AL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Launching TVii");
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
_SYSSwitchTo(3);
|
|
||||||
|
|
||||||
StartAppletAndExit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SYSCheckTitleExists(info.titleId)) {
|
|
||||||
DEBUG_FUNCTION_LINE("Title %016llX doesn't exist", info.titleId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCPTitleListType titleInfo;
|
|
||||||
int32_t handle = MCP_Open();
|
|
||||||
auto err = MCP_GetTitleInfo(handle, info.titleId, &titleInfo);
|
|
||||||
MCP_Close(handle);
|
|
||||||
if (err == 0) {
|
|
||||||
loadConsoleAccount(data.uuid);
|
|
||||||
ACPAssignTitlePatch(&titleInfo);
|
|
||||||
_SYSLaunchTitleWithStdArgsInNoSplash(info.titleId, nullptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE("No quick boot");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void initExternalStorage() {
|
|
||||||
if (OSGetTitleID() == _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER)) {
|
|
||||||
// nn::spm functions always call OSFatal when they fail, so we make sure have permission to use
|
|
||||||
// the lib before actually using it.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nn::spm::Initialize();
|
|
||||||
|
|
||||||
nn::spm::StorageListItem items[0x20];
|
|
||||||
int32_t numItems = nn::spm::GetStorageList(items, 0x20);
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
for (int32_t i = 0; i < numItems; i++) {
|
|
||||||
if (items[i].type == nn::spm::STORAGE_TYPE_WFS) {
|
|
||||||
nn::spm::StorageInfo info{};
|
|
||||||
if (nn::spm::GetStorageInfo(&info, &items[i].index) == 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("Using %s for extended storage", info.path);
|
|
||||||
|
|
||||||
nn::spm::SetExtendedStorage(&items[i].index);
|
|
||||||
ACPMountExternalStorage();
|
|
||||||
|
|
||||||
nn::spm::SetDefaultExtendedStorageVolumeId(info.volumeId);
|
|
||||||
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
DEBUG_FUNCTION_LINE("Fallback to empty ExtendedStorage");
|
|
||||||
nn::spm::VolumeId empty{};
|
|
||||||
nn::spm::SetDefaultExtendedStorageVolumeId(empty);
|
|
||||||
|
|
||||||
nn::spm::StorageIndex storageIndex = 0;
|
|
||||||
nn::spm::SetExtendedStorage(&storageIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
nn::spm::Finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootWiiUMenu() {
|
|
||||||
nn::act::Initialize();
|
|
||||||
nn::act::SlotNo slot = nn::act::GetSlotNo();
|
|
||||||
nn::act::SlotNo defaultSlot = nn::act::GetDefaultAccount();
|
|
||||||
nn::act::Finalize();
|
|
||||||
|
|
||||||
if (defaultSlot) { //normal menu boot
|
|
||||||
SYSLaunchMenu();
|
|
||||||
} else { //show mii select
|
|
||||||
_SYSLaunchMenuWithCheckingAccount(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootHomebrewLauncher() {
|
|
||||||
uint64_t titleId = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_MII_MAKER);
|
|
||||||
_SYSLaunchTitleWithStdArgsInNoSplash(titleId, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void launchvWiiTitle(uint32_t titleId_low, uint32_t titleId_high) {
|
|
||||||
// we need to init kpad for cmpt
|
|
||||||
KPADInit();
|
|
||||||
|
|
||||||
// Try to find a screen type that works
|
|
||||||
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_BOTH);
|
|
||||||
if (CMPTCheckScreenState() < 0) {
|
|
||||||
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_DRC);
|
|
||||||
if (CMPTCheckScreenState() < 0) {
|
|
||||||
CMPTAcctSetScreenType(CMPT_SCREEN_TYPE_TV);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t dataSize = 0;
|
|
||||||
CMPTGetDataSize(&dataSize);
|
|
||||||
|
|
||||||
void *dataBuffer = memalign(0x40, dataSize);
|
|
||||||
|
|
||||||
if (titleId_low == 0 && titleId_high == 0) {
|
|
||||||
CMPTLaunchMenu(dataBuffer, dataSize);
|
|
||||||
} else {
|
|
||||||
CMPTLaunchTitle(dataBuffer, dataSize, titleId_low, titleId_high);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dataBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootvWiiMenu() {
|
|
||||||
launchvWiiTitle(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bootHomebrewChannel() {
|
|
||||||
launchvWiiTitle(0x00010001, 0x4f484243); // 'OHBC'
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t handleMenuScreen(int32_t autobootOptionInput) {
|
|
||||||
OSScreenInit();
|
|
||||||
|
|
||||||
uint32_t tvBufferSize = OSScreenGetBufferSizeEx(SCREEN_TV);
|
|
||||||
uint32_t drcBufferSize = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
|
||||||
|
|
||||||
auto *screenBuffer = (uint8_t *) memalign(0x100, tvBufferSize + drcBufferSize);
|
|
||||||
if (screenBuffer == nullptr) {
|
|
||||||
OSFatal("Failed to allocate screenBuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
OSScreenSetBufferEx(SCREEN_TV, screenBuffer);
|
|
||||||
OSScreenSetBufferEx(SCREEN_DRC, screenBuffer + tvBufferSize);
|
|
||||||
|
|
||||||
OSScreenEnableEx(SCREEN_TV, TRUE);
|
|
||||||
OSScreenEnableEx(SCREEN_DRC, TRUE);
|
|
||||||
|
|
||||||
DrawUtils::initBuffers(screenBuffer, tvBufferSize, screenBuffer + tvBufferSize, drcBufferSize);
|
|
||||||
DrawUtils::initFont();
|
|
||||||
|
|
||||||
uint32_t selected = autobootOptionInput > 0 ? autobootOptionInput : 0;
|
|
||||||
int autoboot = autobootOptionInput;
|
|
||||||
bool redraw = true;
|
|
||||||
while (true) {
|
|
||||||
VPADStatus vpad{};
|
|
||||||
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
|
||||||
|
|
||||||
if (vpad.trigger & VPAD_BUTTON_UP) {
|
|
||||||
if (selected > 0) {
|
|
||||||
selected--;
|
|
||||||
redraw = true;
|
|
||||||
}
|
|
||||||
} else if (vpad.trigger & VPAD_BUTTON_DOWN) {
|
|
||||||
if (selected < sizeof(menu_options) / sizeof(char *) - 1) {
|
|
||||||
selected++;
|
|
||||||
redraw = true;
|
|
||||||
}
|
|
||||||
} else if (vpad.trigger & VPAD_BUTTON_A) {
|
|
||||||
break;
|
|
||||||
} else if (vpad.trigger & VPAD_BUTTON_X) {
|
|
||||||
autoboot = -1;
|
|
||||||
redraw = true;
|
|
||||||
} else if (vpad.trigger & VPAD_BUTTON_Y) {
|
|
||||||
autoboot = selected;
|
|
||||||
redraw = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (redraw) {
|
|
||||||
DrawUtils::beginDraw();
|
|
||||||
DrawUtils::clear(COLOR_BACKGROUND);
|
|
||||||
|
|
||||||
// draw buttons
|
|
||||||
uint32_t index = 8 + 24 + 8 + 4;
|
|
||||||
for (uint32_t i = 0; i < sizeof(menu_options) / sizeof(char *); i++) {
|
|
||||||
if (i == selected) {
|
|
||||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
|
||||||
} else {
|
|
||||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16 * 2, 44, 2, (i == (uint32_t) autoboot) ? COLOR_AUTOBOOT : COLOR_BORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawUtils::setFontSize(24);
|
|
||||||
DrawUtils::setFontColor((i == (uint32_t) autoboot) ? COLOR_AUTOBOOT : COLOR_TEXT);
|
|
||||||
DrawUtils::print(16 * 2, index + 8 + 24, menu_options[i]);
|
|
||||||
index += 42 + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawUtils::setFontColor(COLOR_TEXT);
|
|
||||||
|
|
||||||
// draw top bar
|
|
||||||
DrawUtils::setFontSize(24);
|
|
||||||
DrawUtils::drawPNG(16, 2, icon_png);
|
|
||||||
DrawUtils::print(64 + 2, 6 + 24, "Tiramisu Boot Selector");
|
|
||||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
|
||||||
|
|
||||||
// draw bottom bar
|
|
||||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_WHITE);
|
|
||||||
DrawUtils::setFontSize(18);
|
|
||||||
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
|
||||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue000 Choose", true);
|
|
||||||
const char *autobootHints = "\ue002 Clear Autoboot / \ue003 Select Autoboot";
|
|
||||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(autobootHints) / 2, SCREEN_HEIGHT - 8, autobootHints, true);
|
|
||||||
|
|
||||||
DrawUtils::endDraw();
|
|
||||||
|
|
||||||
redraw = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawUtils::beginDraw();
|
|
||||||
DrawUtils::clear(COLOR_BLACK);
|
|
||||||
DrawUtils::endDraw();
|
|
||||||
|
|
||||||
DrawUtils::deinitFont();
|
|
||||||
|
|
||||||
// Call GX2Init to shut down OSScreen
|
// Call GX2Init to shut down OSScreen
|
||||||
GX2Init(nullptr);
|
GX2Init(nullptr);
|
||||||
|
|
||||||
free(screenBuffer);
|
free(buffer);
|
||||||
|
|
||||||
if (autoboot != autobootOptionInput) {
|
|
||||||
writeAutobootOption(autoboot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return selected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t main(int32_t argc, char **argv) {
|
int32_t main(int32_t argc, char **argv) {
|
||||||
#ifdef DEBUG
|
initLogging();
|
||||||
if (!WHBLogModuleInit()) {
|
DEBUG_FUNCTION_LINE("Hello from Autoboot Module");
|
||||||
WHBLogCafeInit();
|
|
||||||
WHBLogUdpInit();
|
// Clear screen to avoid screen corruptions when loading the Wii U Menu
|
||||||
}
|
clearScreen();
|
||||||
#endif // DEBUG
|
|
||||||
DEBUG_FUNCTION_LINE("Hello from Autoboot");
|
|
||||||
|
|
||||||
initExternalStorage();
|
initExternalStorage();
|
||||||
|
|
||||||
if (getQuickBoot()) {
|
if (getQuickBoot()) {
|
||||||
|
deinitLogging();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
configPath = "fs:/vol/exernal01/wiiu/autoboot.cfg";
|
std::string configPath = "fs:/vol/exernal01/wiiu/autoboot.cfg";
|
||||||
if (argc >= 1) {
|
if (argc >= 1) {
|
||||||
configPath = std::string(argv[0]) + "/autoboot.cfg";
|
configPath = std::string(argv[0]) + "/autoboot.cfg";
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t bootSelection = readAutobootOption();
|
int32_t bootSelection = readAutobootOption(configPath);
|
||||||
|
|
||||||
VPADStatus vpad{};
|
VPADStatus vpad{};
|
||||||
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
VPADRead(VPAD_CHAN_0, &vpad, 1, nullptr);
|
||||||
|
|
||||||
if ((bootSelection == -1) || (vpad.hold & VPAD_BUTTON_PLUS)) {
|
if ((bootSelection == -1) || (vpad.hold & VPAD_BUTTON_PLUS)) {
|
||||||
bootSelection = handleMenuScreen(bootSelection);
|
bootSelection = handleMenuScreen(configPath, bootSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bootSelection >= 0) {
|
if (bootSelection >= 0) {
|
||||||
@ -543,5 +74,6 @@ int32_t main(int32_t argc, char **argv) {
|
|||||||
bootWiiUMenu();
|
bootWiiUMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinitLogging();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
1
source/main.h
Normal file
1
source/main.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
Loading…
Reference in New Issue
Block a user