- Add gui_emu_tools: emuMMC Manage window with correct positioning (LV_PROTECT_PARENT + re-parent to win) - Tools: single SD button (tap = SD partition manager, 3s hold = eMMC) - Remove emuSD from Nyx UI (tabs, UMS, partition manager); keep bootloader emusd - Shorten Create emuMMC description text by one character - Storage/build/config and dependency updates Co-authored-by: Cursor <cursoragent@cursor.com>
295 lines
6.5 KiB
C
295 lines
6.5 KiB
C
#include "emusd.h"
|
|
#include <bdk.h>
|
|
#include <storage/boot_storage.h>
|
|
#include <storage/emmc.h>
|
|
#include <storage/file_based_storage.h>
|
|
#include <storage/sd.h>
|
|
#include <storage/sdmmc.h>
|
|
#include <string.h>
|
|
#include <utils/ini.h>
|
|
#include <libs/fatfs/ff.h>
|
|
#include "../config.h"
|
|
#include "gfx_utils.h"
|
|
|
|
|
|
FATFS emusd_fs;
|
|
bool emusd_mounted = false;
|
|
bool emusd_initialized = false;
|
|
emusd_cfg_t emu_sd_cfg = {0};
|
|
extern hekate_config h_cfg;
|
|
|
|
static bool emusd_get_mounted() {
|
|
return emusd_mounted;
|
|
}
|
|
|
|
void emusd_load_cfg()
|
|
{
|
|
emu_sd_cfg.enabled = 0;
|
|
emu_sd_cfg.fs_ver = 0;
|
|
emu_sd_cfg.id = 0;
|
|
emu_sd_cfg.sector = 0;
|
|
if(!emu_sd_cfg.path) {
|
|
emu_sd_cfg.path = (char*)malloc(0x200);
|
|
}
|
|
if(!emu_sd_cfg.emummc_file_based_path){
|
|
emu_sd_cfg.emummc_file_based_path = (char*)malloc(0x200);
|
|
}
|
|
|
|
LIST_INIT(ini_sections);
|
|
if(ini_parse(&ini_sections, "emuSD/emusd.ini", false))
|
|
{
|
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
|
{
|
|
if(ini_sec->type == INI_CHOICE)
|
|
{
|
|
if(strcmp(ini_sec->name, "emusd")){
|
|
continue;
|
|
}
|
|
|
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
|
{
|
|
if(!strcmp(kv->key, "enabled")){
|
|
emu_sd_cfg.enabled = atoi(kv->val);
|
|
} else if(!strcmp(kv->key, "sector")){
|
|
emu_sd_cfg.sector = strtol(kv->val, NULL, 16);
|
|
} else if(!strcmp(kv->key, "path")){
|
|
emu_sd_cfg.path = kv->val;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool emusd_mount() {
|
|
if (emusd_mounted) {
|
|
return true;
|
|
}
|
|
|
|
if (emusd_storage_init_mmc()){
|
|
return false;
|
|
}
|
|
|
|
int res = f_mount(&emusd_fs, "emusd:", 1);
|
|
|
|
if(res) {
|
|
EPRINTFARGS("emusd mount fail %d", res);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool emusd_unmount() {
|
|
f_mount(NULL, "emusd:", 1);
|
|
emusd_mounted = false;
|
|
return true;
|
|
}
|
|
|
|
bool emusd_set_path(char *path) {
|
|
FIL fp;
|
|
bool found = false;
|
|
// TODO: use emu_sd.file_path instead
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "");
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
|
|
if(!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
|
|
{
|
|
if(!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
|
|
if(emu_sd_cfg.sector){
|
|
found = true;
|
|
emu_sd_cfg.enabled = 4;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
|
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
|
|
if (!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
|
|
{
|
|
if (!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
|
|
if (emu_sd_cfg.sector){
|
|
found = true;
|
|
emu_sd_cfg.enabled = 4;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
|
|
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
|
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/file_based");
|
|
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
|
|
{
|
|
emu_sd_cfg.sector = 0;
|
|
emu_sd_cfg.path = path;
|
|
emu_sd_cfg.enabled = 1;
|
|
|
|
found = true;
|
|
goto out;
|
|
}
|
|
|
|
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, "");
|
|
strcat(emu_sd_cfg.emummc_file_based_path, path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/file_emmc_based");
|
|
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
|
|
{
|
|
emu_sd_cfg.sector = 0;
|
|
emu_sd_cfg.path = path;
|
|
emu_sd_cfg.enabled = 4;
|
|
|
|
found = true;
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
return found;
|
|
}
|
|
|
|
int emusd_storage_init_mmc() {
|
|
if(!emusd_initialized) {
|
|
if (!emu_sd_cfg.enabled || h_cfg.emummc_force_disable) {
|
|
if(!sd_initialize(false)){
|
|
return 1;
|
|
}
|
|
emusd_initialized = true;
|
|
return 0;
|
|
}
|
|
|
|
bool file_based = false;
|
|
if(emu_sd_cfg.enabled == 4){
|
|
if(!emu_sd_cfg.sector){
|
|
//file based
|
|
if(!emmc_mount()){
|
|
return 1;
|
|
}
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, "emmc:");
|
|
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
|
|
file_based = true;
|
|
}else{
|
|
if(!emmc_initialize(false)){
|
|
return 1;
|
|
}
|
|
}
|
|
}else{
|
|
if(!emu_sd_cfg.sector){
|
|
//file based
|
|
if(!sd_mount()){
|
|
return 1;
|
|
}
|
|
strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
|
|
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
|
|
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
|
|
file_based = true;
|
|
}else{
|
|
if(!sd_initialize(false)){
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(file_based){
|
|
return file_based_storage_init(emu_sd_cfg.emummc_file_based_path) == 0;
|
|
}
|
|
|
|
emusd_initialized = true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int emusd_storage_end() {
|
|
if(!h_cfg.emummc_force_disable && emu_sd_cfg.enabled && !emu_sd_cfg.sector){
|
|
file_based_storage_end();
|
|
}
|
|
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable || emu_sd_cfg.enabled == 1){
|
|
sd_unmount();
|
|
}else{
|
|
emmc_unmount();
|
|
}
|
|
emusd_initialized = false;
|
|
return 0;
|
|
}
|
|
|
|
int emusd_storage_write(u32 sector, u32 num_sectors, void *buf) {
|
|
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
|
|
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
|
}else if(emu_sd_cfg.sector){
|
|
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
|
|
sector += emu_sd_cfg.sector;
|
|
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
|
}else{
|
|
return file_based_storage_write(sector, num_sectors, buf);
|
|
}
|
|
}
|
|
|
|
int emusd_storage_read(u32 sector, u32 num_sectors, void *buf) {
|
|
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
|
|
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
|
}else if(emu_sd_cfg.sector){
|
|
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
|
|
sector += emu_sd_cfg.sector;
|
|
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
|
}else{
|
|
return file_based_storage_read(sector, num_sectors, buf);
|
|
}
|
|
}
|
|
|
|
sdmmc_storage_t *emusd_get_storage() {
|
|
return emu_sd_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
|
|
}
|
|
|
|
|
|
bool emusd_is_gpt() {
|
|
if(emu_sd_cfg.enabled) {
|
|
return emusd_fs.part_type;
|
|
} else {
|
|
return sd_fs.part_type;
|
|
}
|
|
}
|
|
|
|
int emusd_get_fs_type() {
|
|
if(emu_sd_cfg.enabled) {
|
|
return emusd_fs.fs_type;
|
|
} else {
|
|
return sd_fs.fs_type;
|
|
}
|
|
}
|
|
|
|
void *emusd_file_read(const char *path, u32 *fsize) {
|
|
if(emu_sd_cfg.enabled) {
|
|
char *path1 = malloc(0x100);
|
|
strcpy(path1, "emusd:");
|
|
strcat(path1, path);
|
|
FIL fp;
|
|
if (!emusd_get_mounted())
|
|
return NULL;
|
|
|
|
if (f_open(&fp, path, FA_READ) != FR_OK)
|
|
return NULL;
|
|
|
|
u32 size = f_size(&fp);
|
|
if (fsize)
|
|
*fsize = size;
|
|
|
|
void *buf = malloc(size);
|
|
|
|
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
|
{
|
|
free(buf);
|
|
f_close(&fp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
f_close(&fp);
|
|
|
|
return buf;
|
|
} else {
|
|
return boot_storage_file_read(path, fsize);
|
|
}
|
|
} |