EMC voltage for Mariko; Fix #60; Show battery & voltage info in overlay on Erista
- From previous analysis, EMC voltage is set before AMS loads on Mariko, and will not be set again or changed afterwards. - sys-clk-OC will take care of setting emc voltage on Mariko once it loads. - OS will not hang at boot as it always boots with EMC @ 1600 MHz.
This commit is contained in:
36
Source/sys-clk-OC/common/include/cpp_util.hpp
Normal file
36
Source/sys-clk-OC/common/include/cpp_util.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
template<typename F>
|
||||
class ScopeGuard {
|
||||
public:
|
||||
ScopeGuard(F&& f)
|
||||
: f(f), engaged(true) {};
|
||||
|
||||
~ScopeGuard() {
|
||||
if (engaged)
|
||||
f();
|
||||
};
|
||||
|
||||
ScopeGuard(ScopeGuard&& rhs)
|
||||
: f(std::move(rhs.f)) {};
|
||||
|
||||
void dismiss() { engaged = false; }
|
||||
|
||||
private:
|
||||
F f;
|
||||
bool engaged;
|
||||
};
|
||||
|
||||
struct MakeScopeExit {
|
||||
template<typename F>
|
||||
ScopeGuard<F> operator+=(F&& f) {
|
||||
return ScopeGuard<F>(std::move(f));
|
||||
};
|
||||
};
|
||||
|
||||
#define STRING_CAT2(x, y) x##y
|
||||
#define STRING_CAT(x, y) STRING_CAT2(x, y)
|
||||
#define SCOPE_GUARD MakeScopeExit() += [&]() __attribute__((always_inline))
|
||||
#define SCOPE_EXIT auto STRING_CAT(scope_exit_, __LINE__) = SCOPE_GUARD
|
||||
@@ -11,6 +11,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "cpp_util.hpp"
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
@@ -14,14 +14,34 @@ float I2c_Max17050_GetBatteryCurrent();
|
||||
|
||||
const u8 MAX17050_CURRENT_REG = 0x0A;
|
||||
|
||||
// Max77812 Mariko-specific buck converter
|
||||
typedef enum I2c_Max77812_Volt_Type {
|
||||
// Buck Converter
|
||||
typedef enum I2c_BuckConverter_Reg {
|
||||
I2c_Max77620_SD1VOLT_REG = 0x16,
|
||||
I2c_Max77621_VOLT_REG = 0x00,
|
||||
I2c_Max77812_CPUVOLT_REG = 0x26,
|
||||
I2c_Max77812_GPUVOLT_REG = 0x23,
|
||||
I2c_Max77812_MEMVOLT_REG = 0x25,
|
||||
} I2c_Max77812_Volt_Type;
|
||||
I2c_Max77812_MEMVOLT_REG = 0x25, // Master 3 (GPU 1 + 2, DRAM 3, CPU 4)
|
||||
} I2c_BuckConverter_Reg;
|
||||
|
||||
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type);
|
||||
typedef struct I2c_BuckConverter_Domain {
|
||||
I2cDevice device;
|
||||
I2c_BuckConverter_Reg reg;
|
||||
u8 volt_mask;
|
||||
u32 uv_step;
|
||||
u32 uv_min;
|
||||
u32 uv_max;
|
||||
u8 por_val;
|
||||
} I2c_BuckConverter_Domain;
|
||||
|
||||
const I2c_BuckConverter_Domain I2c_Erista_CPU = { I2cDevice_Max77621Cpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||
const I2c_BuckConverter_Domain I2c_Erista_GPU = { I2cDevice_Max77621Gpu, I2c_Max77621_VOLT_REG, 0x7F, 6250, 606250, 1400000, };
|
||||
const I2c_BuckConverter_Domain I2c_Erista_DRAM = { I2cDevice_Max77620Pmic, I2c_Max77620_SD1VOLT_REG, 0x7F, 12500, 600000, 1250000, };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_CPU = { I2cDevice_Max77812_2, I2c_Max77812_CPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_GPU = { I2cDevice_Max77812_2, I2c_Max77812_GPUVOLT_REG, 0xFF, 5000, 250000, 1525000, 0x78 };
|
||||
const I2c_BuckConverter_Domain I2c_Mariko_DRAM = { I2cDevice_Max77812_2, I2c_Max77812_MEMVOLT_REG, 0xFF, 5000, 250000, 650000, 0x78 };
|
||||
|
||||
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain);
|
||||
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt);
|
||||
|
||||
// Bq24193 Battery management
|
||||
u32 I2c_Bq24193_Convert_Raw_mA(u8 raw);
|
||||
|
||||
@@ -83,24 +83,58 @@ float I2c_Max17050_GetBatteryCurrent() {
|
||||
return (s16)val * (1.5625 / (SenseResistor * CGain));
|
||||
}
|
||||
|
||||
u32 I2c_Max77812_GetMVOUT(I2c_Max77812_Volt_Type type) {
|
||||
u8 reg = (u8)type;
|
||||
u32 I2c_BuckConverter_MultiplierToMvOut(const I2c_BuckConverter_Domain* domain, u8 multiplier) {
|
||||
return (domain->uv_min + domain->uv_step * multiplier) / 1000;
|
||||
}
|
||||
|
||||
const u32 MIN_MV = 250;
|
||||
const u32 MV_STEP = 5;
|
||||
const u8 RESET_VAL = 0x78;
|
||||
u8 I2c_BuckConverter_MvOutToMultiplier(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||
u32 uvolt = mvolt * 1000;
|
||||
if (uvolt < domain->uv_min)
|
||||
uvolt = domain->uv_min;
|
||||
if (uvolt > domain->uv_max)
|
||||
uvolt = domain->uv_max;
|
||||
|
||||
u8 val = RESET_VAL;
|
||||
// Retry 3 times if received RESET_VAL
|
||||
return (uvolt - domain->uv_min) / domain->uv_step;
|
||||
}
|
||||
|
||||
u32 I2c_BuckConverter_GetMvOut(const I2c_BuckConverter_Domain* domain) {
|
||||
u8 val;
|
||||
Result res;
|
||||
// Retry 3 times if failed or received POR value
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (I2cRead_OutU8(I2cDevice_Max77812_2, reg, &val))
|
||||
return 0u;
|
||||
if (val != RESET_VAL)
|
||||
break;
|
||||
svcSleepThread(10);
|
||||
res = I2cRead_OutU8(domain->device, domain->reg, &val);
|
||||
if (R_FAILED(res) || (domain->por_val && val == domain->por_val)) {
|
||||
svcSleepThread(1000);
|
||||
continue;
|
||||
}
|
||||
return I2c_BuckConverter_MultiplierToMvOut(domain, val & domain->volt_mask);
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
|
||||
return val * MV_STEP + MIN_MV;
|
||||
Result I2c_BuckConverter_SetMvOut(const I2c_BuckConverter_Domain* domain, u32 mvolt) {
|
||||
u8 val;
|
||||
Result res = I2cRead_OutU8(domain->device, domain->reg, &val);
|
||||
if (R_FAILED(res))
|
||||
return res;
|
||||
|
||||
u8 multiplier = I2c_BuckConverter_MvOutToMultiplier(domain, mvolt);
|
||||
val &= ~domain->volt_mask;
|
||||
val |= multiplier & domain->volt_mask;
|
||||
|
||||
res = I2cSet_U8(domain->device, domain->reg, val);
|
||||
if (R_FAILED(res))
|
||||
return res;
|
||||
|
||||
svcSleepThread(1000);
|
||||
u8 new_val;
|
||||
res = I2cRead_OutU8(domain->device, domain->reg, &new_val);
|
||||
if (R_FAILED(res))
|
||||
return res;
|
||||
if (new_val != val)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 I2c_Bq24193_Convert_mA_Raw(u32 ma) {
|
||||
|
||||
@@ -65,7 +65,6 @@ void MiscGui::listUI()
|
||||
addConfigToggle(SysClkConfigValue_AutoCPUBoost);
|
||||
}
|
||||
|
||||
addConfigToggle(SysClkConfigValue_AllowUnsafeFrequencies);
|
||||
addConfigToggle(SysClkConfigValue_SyncReverseNXMode);
|
||||
addConfigToggle(SysClkConfigValue_GovernorExperimental);
|
||||
|
||||
@@ -86,7 +85,7 @@ void MiscGui::listUI()
|
||||
uint32_t current_ma = val * 100;
|
||||
this->configList->values[SysClkConfigValue_ChargingCurrentLimit] = current_ma;
|
||||
|
||||
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA", this->configList->values[SysClkConfigValue_ChargingCurrentLimit]);
|
||||
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA (Now: %+.2f mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], this->i2cInfo->batCurrent);
|
||||
this->chargingCurrentHeader->setText(chargingCurrentBarDesc);
|
||||
|
||||
Result rc = sysclkIpcSetConfigValues(this->configList);
|
||||
@@ -109,7 +108,7 @@ void MiscGui::listUI()
|
||||
}
|
||||
this->configList->values[SysClkConfigValue_ChargingLimitPercentage] = val;
|
||||
|
||||
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (%u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
|
||||
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
|
||||
this->chargingLimitHeader->setText(chargingLimitBarDesc);
|
||||
this->chargingLimitBar->setIcon(PsmGetBatteryStateIcon(this->chargeInfo));
|
||||
|
||||
@@ -144,13 +143,11 @@ void MiscGui::listUI()
|
||||
this->listElement->addItem(this->backlightToggle);
|
||||
|
||||
// Info
|
||||
if (this->isMariko) {
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Info"));
|
||||
this->listElement->addItem(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString(this->infoNames, false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString(this->infoVals, false, x + 120, y + 20, SMALL_TEXT_SIZE, VALUE_COLOR);
|
||||
}), SMALL_TEXT_SIZE * 12 + 20);
|
||||
}
|
||||
this->listElement->addItem(new tsl::elm::CategoryHeader("Info"));
|
||||
this->listElement->addItem(new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) {
|
||||
renderer->drawString(this->infoNames, false, x, y + 20, SMALL_TEXT_SIZE, DESC_COLOR);
|
||||
renderer->drawString(this->infoVals, false, x + 120, y + 20, SMALL_TEXT_SIZE, VALUE_COLOR);
|
||||
}), SMALL_TEXT_SIZE * 12 + 20);
|
||||
}
|
||||
|
||||
void MiscGui::refresh() {
|
||||
@@ -175,16 +172,14 @@ void MiscGui::refresh() {
|
||||
this->backlightToggle->setState(lblstatus);
|
||||
|
||||
this->chargingCurrentBar->setProgress(this->configList->values[SysClkConfigValue_ChargingCurrentLimit] / 100);
|
||||
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA", this->configList->values[SysClkConfigValue_ChargingCurrentLimit]);
|
||||
snprintf(chargingCurrentBarDesc, sizeof(chargingCurrentBarDesc), "Battery Charging Current: %lu mA (Now: %+.2f mA)", this->configList->values[SysClkConfigValue_ChargingCurrentLimit], this->i2cInfo->batCurrent);
|
||||
this->chargingCurrentHeader->setText(chargingCurrentBarDesc);
|
||||
|
||||
this->chargingLimitBar->setProgress(this->configList->values[SysClkConfigValue_ChargingLimitPercentage]);
|
||||
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (%u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
|
||||
snprintf(chargingLimitBarDesc, sizeof(chargingLimitBarDesc), "Battery Charging Limit: %lu%% (Now: %u%%)", this->configList->values[SysClkConfigValue_ChargingLimitPercentage], this->batteryChargePerc);
|
||||
this->chargingLimitHeader->setText(chargingLimitBarDesc);
|
||||
|
||||
if (this->isMariko) {
|
||||
I2cGetInfo(this->i2cInfo);
|
||||
UpdateInfo(this->infoVals, sizeof(this->infoVals));
|
||||
}
|
||||
I2cGetInfo(this->i2cInfo);
|
||||
UpdateInfo(this->infoVals, sizeof(this->infoVals));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ class MiscGui : public BaseMenuGui
|
||||
protected:
|
||||
typedef struct {
|
||||
float batCurrent;
|
||||
u32 cpuVolt = 620;
|
||||
u32 gpuVolt = 610;
|
||||
u32 dramVolt = 600;
|
||||
u32 cpuVolt;
|
||||
u32 gpuVolt;
|
||||
u32 dramVolt;
|
||||
} I2cInfo;
|
||||
|
||||
void PsmUpdate(uint32_t dispatchId = 0)
|
||||
@@ -57,11 +57,12 @@ class MiscGui : public BaseMenuGui
|
||||
{
|
||||
i2cInitialize();
|
||||
|
||||
i2cInfo->batCurrent = I2c_Max17050_GetBatteryCurrent();
|
||||
float batCurrent = I2c_Max17050_GetBatteryCurrent();
|
||||
i2cInfo->batCurrent = std::abs(batCurrent) < 10. ? 0. : batCurrent;
|
||||
|
||||
i2cInfo->cpuVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_CPUVOLT_REG);
|
||||
i2cInfo->gpuVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_GPUVOLT_REG);
|
||||
i2cInfo->dramVolt = I2c_Max77812_GetMVOUT(I2c_Max77812_MEMVOLT_REG);
|
||||
i2cInfo->cpuVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_CPU : &I2c_Erista_CPU);
|
||||
i2cInfo->gpuVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_GPU : &I2c_Erista_GPU);
|
||||
i2cInfo->dramVolt = I2c_BuckConverter_GetMvOut(isMariko ? &I2c_Mariko_DRAM : &I2c_Erista_DRAM);
|
||||
|
||||
I2c_Bq24193_GetFastChargeCurrentLimit(reinterpret_cast<u32 *>(&(chargeInfo->ChargeCurrentLimit)));
|
||||
|
||||
@@ -78,16 +79,13 @@ class MiscGui : public BaseMenuGui
|
||||
if (chargeInfo->ChargeVoltageLimit)
|
||||
snprintf(chargeVoltLimit, sizeof(chargeVoltLimit), ", %umV", chargeInfo->ChargeVoltageLimit);
|
||||
|
||||
char chargWattsInfo[50] = "";
|
||||
char chargWattsInfo[30] = "";
|
||||
if (chargeInfo->ChargerType)
|
||||
snprintf(chargWattsInfo, sizeof(chargWattsInfo), " %.1fV/%.1fA (%.1fW)", chargerVoltLimit, chargerCurrLimit, chargerOutWatts);
|
||||
|
||||
char batCurInfo[30] = "";
|
||||
if (std::abs(i2cInfo->batCurrent) < 10)
|
||||
snprintf(batCurInfo, sizeof(batCurInfo), "0mA");
|
||||
else
|
||||
snprintf(batCurInfo, sizeof(batCurInfo), "%+.2fmA (%+.2fW)",
|
||||
i2cInfo->batCurrent, i2cInfo->batCurrent * (float)chargeInfo->VoltageAvg / 1000'000);
|
||||
snprintf(batCurInfo, sizeof(batCurInfo), "%+.2fmA (%+.2fW)",
|
||||
i2cInfo->batCurrent, i2cInfo->batCurrent * (float)chargeInfo->VoltageAvg / 1000'000);
|
||||
|
||||
snprintf(out, outsize,
|
||||
"%s%s\n"
|
||||
@@ -155,10 +153,21 @@ class MiscGui : public BaseMenuGui
|
||||
I2cInfo* i2cInfo;
|
||||
LblBacklightSwitchStatus lblstatus = LblBacklightSwitchStatus_Disabled;
|
||||
|
||||
const char* infoNames = "Charger:\nBattery:\nCurrent Limit:\nCharging Limit:\nRaw Charge:\nBattery Age:\nPower Role:\nCurrent Flow:\n\nCPU Volt:\nGPU Volt:\nDRAM Volt:";
|
||||
const char* infoNames =
|
||||
"Charger:\n"\
|
||||
"Battery:\n"\
|
||||
"Current Limit:\n"\
|
||||
"Charging Limit:\n"\
|
||||
"Raw Charge:\n"\
|
||||
"Battery Age:\n"\
|
||||
"Power Role:\n"\
|
||||
"Current Flow:\n\n"\
|
||||
"CPU Volt:\n"\
|
||||
"GPU Volt:\n"\
|
||||
"DRAM Volt:";
|
||||
char infoVals[300] = "";
|
||||
char chargingLimitBarDesc[40] = "";
|
||||
char chargingCurrentBarDesc[45] = "";
|
||||
char chargingLimitBarDesc[50] = "";
|
||||
char chargingCurrentBarDesc[60] = "";
|
||||
u32 batteryChargePerc = 0;
|
||||
u8 frameCounter = 60;
|
||||
};
|
||||
|
||||
@@ -185,11 +185,14 @@ void FileUtils::Exit()
|
||||
void FileUtils::ParseLoaderKip() {
|
||||
const char* dirs[] = { "/", "/atmosphere/", "/atmosphere/kips/", "/bootloader/" };
|
||||
char* full_path = new char[0x200];
|
||||
SCOPE_EXIT { delete[] full_path; };
|
||||
|
||||
for (auto const& dir : dirs) {
|
||||
struct dirent *entry = NULL;
|
||||
DIR *dp = opendir(dir);
|
||||
if (!dp)
|
||||
continue;
|
||||
SCOPE_EXIT { closedir(dp); };
|
||||
|
||||
while ((entry = readdir(dp))) {
|
||||
if (entry->d_type != DT_REG)
|
||||
@@ -219,18 +222,15 @@ void FileUtils::ParseLoaderKip() {
|
||||
continue;
|
||||
|
||||
if (R_SUCCEEDED(CustParser(full_path, filesize))) {
|
||||
LogLine("Parsed cust config from %s, maxMemFreq: %u MHz, boostCpuFreq: %u MHz",
|
||||
LogLine("Parsed cust config from \"%s\", maxMemFreq: %u MHz, boostCpuFreq: %u MHz",
|
||||
full_path,
|
||||
Clocks::maxMemFreq / 1'000'000,
|
||||
Clocks::boostCpuFreq / 1'000'000
|
||||
);
|
||||
delete[] full_path;
|
||||
return;
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
delete[] full_path;
|
||||
}
|
||||
|
||||
Result FileUtils::CustParser(const char* filepath, size_t filesize) {
|
||||
@@ -245,17 +245,17 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) {
|
||||
FILE* fp = fopen(filepath, "r");
|
||||
if (!fp)
|
||||
return ParseError_OpenReadFailed;
|
||||
SCOPE_EXIT { fclose(fp); };
|
||||
|
||||
constexpr uint8_t KIP_MAGIC[] = {'K', 'I', 'P', '1', 'L', 'o', 'a', 'd', 'e', 'r'};
|
||||
constexpr size_t BLOCK_SIZE = 0x1000;
|
||||
|
||||
char* tmp_block = new char[BLOCK_SIZE];
|
||||
SCOPE_EXIT { delete[] tmp_block; };
|
||||
fread(tmp_block, sizeof(char), BLOCK_SIZE, fp);
|
||||
|
||||
if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC))) {
|
||||
delete[] tmp_block;
|
||||
if (memcmp(KIP_MAGIC, tmp_block, sizeof(KIP_MAGIC)))
|
||||
return ParseError_WrongKipMagic;
|
||||
}
|
||||
|
||||
CustTable table {};
|
||||
|
||||
@@ -274,23 +274,15 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) {
|
||||
}
|
||||
|
||||
found:
|
||||
delete[] tmp_block;
|
||||
|
||||
if (!cust_pos) {
|
||||
fclose(fp);
|
||||
if (!cust_pos)
|
||||
return ParseError_CustNotFound;
|
||||
}
|
||||
|
||||
memset(reinterpret_cast<void*>(&table), 0, sizeof(CustTable));
|
||||
fsetpos(fp, &cust_pos);
|
||||
if (!fread(reinterpret_cast<char*>(&table), 1, sizeof(CustTable), fp)) {
|
||||
fclose(fp);
|
||||
if (!fread(reinterpret_cast<char*>(&table), 1, sizeof(CustTable), fp))
|
||||
return ParseError_OpenReadFailed;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (table.custRev != 2)
|
||||
if (table.custRev != CUST_REV)
|
||||
return ParseError_WrongCustRev;
|
||||
|
||||
if (Clocks::GetIsMariko()) {
|
||||
@@ -298,6 +290,11 @@ Result FileUtils::CustParser(const char* filepath, size_t filesize) {
|
||||
Clocks::boostCpuFreq = table.marikoCpuBoostClock * 1000;
|
||||
if (table.marikoEmcMaxClock)
|
||||
Clocks::maxMemFreq = table.marikoEmcMaxClock * 1000;
|
||||
if (table.marikoEmcVolt && table.marikoEmcVolt >= 600'000 && table.marikoEmcVolt <= 650'000) {
|
||||
u32 mvolt = table.marikoEmcVolt / 1000;
|
||||
Result res = I2c_BuckConverter_SetMvOut(&I2c_Mariko_DRAM, mvolt);
|
||||
LogLine("Set EMC volt to %u mV: %s", mvolt, R_FAILED(res) ? "Failed" : "OK");
|
||||
}
|
||||
} else {
|
||||
if (table.eristaEmcMaxClock)
|
||||
Clocks::maxMemFreq = table.eristaEmcMaxClock * 1000;
|
||||
@@ -335,6 +332,7 @@ Result FileUtils::mkdir_p(const char* dirpath) {
|
||||
|
||||
size_t path_len = strnlen(dirpath, 0x1000);
|
||||
char* path_copy = new char[path_len];
|
||||
SCOPE_EXIT { delete[] path_copy; };
|
||||
memcpy(path_copy, dirpath, path_len);
|
||||
char* p = path_copy;
|
||||
while (*p) {
|
||||
@@ -344,7 +342,7 @@ Result FileUtils::mkdir_p(const char* dirpath) {
|
||||
|
||||
if (R_FAILED(mkdir_wrapper(path_copy))) {
|
||||
res = -1;
|
||||
goto end;
|
||||
return res;
|
||||
}
|
||||
|
||||
*p = '/';
|
||||
@@ -355,7 +353,5 @@ Result FileUtils::mkdir_p(const char* dirpath) {
|
||||
if (R_FAILED(mkdir_wrapper(path_copy)))
|
||||
res = -1;
|
||||
|
||||
end:
|
||||
delete[] path_copy;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class FileUtils
|
||||
static void ParseLoaderKip();
|
||||
static Result mkdir_p(const char* dirpath);
|
||||
protected:
|
||||
static const uint16_t CUST_REV = 3;
|
||||
typedef struct CustTable {
|
||||
uint8_t cust[4] = {'C', 'U', 'S', 'T'};
|
||||
uint16_t custRev;
|
||||
@@ -47,7 +48,7 @@ class FileUtils
|
||||
uint32_t marikoCpuMaxVolt;
|
||||
uint32_t marikoGpuMaxClock;
|
||||
uint32_t marikoEmcMaxClock;
|
||||
uint32_t eristaCpuOCEnable;
|
||||
uint32_t marikoEmcVolt;
|
||||
uint32_t eristaCpuMaxVolt;
|
||||
uint32_t eristaEmcMaxClock;
|
||||
uint32_t eristaEmcVolt;
|
||||
|
||||
Reference in New Issue
Block a user