diff --git a/source/core/spi.c b/source/core/spi.c index a62e1ea..a1a5bea 100644 --- a/source/core/spi.c +++ b/source/core/spi.c @@ -406,7 +406,7 @@ static Result spi_is_data_mirrored(SaveChip chip, u32 size, bool* mirrored) { return res; } -static Result spi_get_save_chip_internal(SaveChip* chip, SaveChip base) { +static Result spi_get_save_chip(SaveChip* chip, SaveChip base) { Result res = 0; u32 jedecId = 0; @@ -454,7 +454,7 @@ static Result spi_get_save_chip_internal(SaveChip* chip, SaveChip base) { break; default: if(base < CHIP_FLASH_256KB_INFRARED) { - res = spi_get_save_chip_internal(&c, CHIP_FLASH_256KB_INFRARED); + res = spi_get_save_chip(&c, CHIP_FLASH_256KB_INFRARED); } else { res = R_FBI_UNSUPPORTED_OPERATION; } @@ -471,14 +471,10 @@ static Result spi_get_save_chip_internal(SaveChip* chip, SaveChip base) { return res; } -static Result spi_get_save_chip(SaveChip* chip) { - return spi_get_save_chip_internal(chip, CHIP_EEPROM_512B); -} - static SaveChip curr_chip = CHIP_NONE; Result spi_init_card() { - return spi_get_save_chip(&curr_chip); + return spi_get_save_chip(&curr_chip, CHIP_EEPROM_512B); } Result spi_deinit_card() { diff --git a/source/ui/section/action/action.h b/source/ui/section/action/action.h index 8866145..1058ff8 100644 --- a/source/ui/section/action/action.h +++ b/source/ui/section/action/action.h @@ -39,6 +39,7 @@ void action_delete_title(linked_list* items, list_item* selected); void action_launch_title(linked_list* items, list_item* selected); void action_extract_smdh(linked_list* items, list_item* selected); void action_import_seed(linked_list* items, list_item* selected); +void action_erase_twl_save(linked_list* items, list_item* selected); void action_export_twl_save(linked_list* items, list_item* selected); void action_import_twl_save(linked_list* items, list_item* selected); void action_browse_title_save_data(linked_list* items, list_item* selected); diff --git a/source/ui/section/action/erasetwlsave.c b/source/ui/section/action/erasetwlsave.c new file mode 100644 index 0000000..30b21cb --- /dev/null +++ b/source/ui/section/action/erasetwlsave.c @@ -0,0 +1,186 @@ +#include +#include +#include + +#include <3ds.h> + +#include "action.h" +#include "../task/task.h" +#include "../../error.h" +#include "../../info.h" +#include "../../list.h" +#include "../../prompt.h" +#include "../../ui.h" +#include "../../../core/linkedlist.h" +#include "../../../core/screen.h" +#include "../../../core/spi.h" +#include "../../../core/util.h" + +typedef struct { + title_info* title; + + data_op_data eraseInfo; +} erase_twl_save_data; + +static void action_erase_twl_save_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) { + ui_draw_title_info(view, ((erase_twl_save_data*) data)->title, x1, y1, x2, y2); +} + +static Result action_erase_twl_save_is_src_directory(void* data, u32 index, bool* isDirectory) { + *isDirectory = false; + return 0; +} + +static Result action_erase_twl_save_make_dst_directory(void* data, u32 index) { + return 0; +} + +static Result action_erase_twl_save_open_src(void* data, u32 index, u32* handle) { + return 0; +} + +static Result action_erase_twl_save_close_src(void* data, u32 index, bool succeeded, u32 handle) { + return 0; +} + +static Result action_erase_twl_save_get_src_size(void* data, u32 handle, u64* size) { + Result res = 0; + + u32 saveSize = 0; + if(R_SUCCEEDED(res = spi_init_card()) && R_SUCCEEDED(res = spi_get_save_size(&saveSize)) && R_SUCCEEDED(res = spi_deinit_card())) { + *size = saveSize; + } + + return res; +} + +static Result action_erase_twl_save_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) { + memset(buffer, 0, size); + *bytesRead = size; + + return 0; +} + +static Result action_erase_twl_save_open_dst(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle) { + return spi_init_card(); +} + +static Result action_erase_twl_save_close_dst(void* data, u32 index, bool succeeded, u32 handle) { + return spi_deinit_card(); +} + +static Result action_erase_twl_save_write_dst(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size) { + return spi_write_save(bytesWritten, buffer, (u32) offset, size); +} + +static Result action_erase_twl_save_suspend_copy(void* data, u32 index, u32* srcHandle, u32* dstHandle) { + return 0; +} + +static Result action_erase_twl_save_restore_copy(void* data, u32 index, u32* srcHandle, u32* dstHandle) { + return 0; +} + +static Result action_erase_twl_save_suspend(void* data, u32 index) { + return 0; +} + +static Result action_erase_twl_save_restore(void* data, u32 index) { + return 0; +} + +static bool action_erase_twl_save_error(void* data, u32 index, Result res) { + erase_twl_save_data* eraseData = (erase_twl_save_data*) data; + + if(res == R_FBI_CANCELLED) { + prompt_display("Failure", "Erase cancelled.", COLOR_TEXT, false, eraseData->title, ui_draw_title_info, NULL); + } else { + error_display_res(eraseData->title, ui_draw_title_info, res, "Failed to erase save."); + } + + return false; +} + +static void action_erase_twl_save_update(ui_view* view, void* data, float* progress, char* text) { + erase_twl_save_data* eraseData = (erase_twl_save_data*) data; + + if(eraseData->eraseInfo.finished) { + ui_pop(); + info_destroy(view); + + if(R_SUCCEEDED(eraseData->eraseInfo.result)) { + prompt_display("Success", "Save erased.", COLOR_TEXT, false, eraseData->title, ui_draw_title_info, NULL); + } + + free(data); + + return; + } + + if(hidKeysDown() & KEY_B) { + svcSignalEvent(eraseData->eraseInfo.cancelEvent); + } + + *progress = eraseData->eraseInfo.currTotal != 0 ? (float) ((double) eraseData->eraseInfo.currProcessed / (double) eraseData->eraseInfo.currTotal) : 0; + snprintf(text, PROGRESS_TEXT_MAX, "%.2f %s / %.2f %s", util_get_display_size(eraseData->eraseInfo.currProcessed), util_get_display_size_units(eraseData->eraseInfo.currProcessed), util_get_display_size(eraseData->eraseInfo.currTotal), util_get_display_size_units(eraseData->eraseInfo.currTotal)); +} + +static void action_erase_twl_save_onresponse(ui_view* view, void* data, bool response) { + if(response) { + erase_twl_save_data* eraseData = (erase_twl_save_data*) data; + + Result res = task_data_op(&eraseData->eraseInfo); + if(R_SUCCEEDED(res)) { + info_display("Erasing Save", "Press B to cancel.", true, data, action_erase_twl_save_update, action_erase_twl_save_draw_top); + } else { + error_display_res(eraseData->title, ui_draw_title_info, res, "Failed to initiate save erase."); + free(data); + } + } else { + free(data); + } +} + +void action_erase_twl_save(linked_list* items, list_item* selected) { + erase_twl_save_data* data = (erase_twl_save_data*) calloc(1, sizeof(erase_twl_save_data)); + if(data == NULL) { + error_display(NULL, NULL, "Failed to allocate erase TWL save data."); + + return; + } + + data->title = (title_info*) selected->data; + + data->eraseInfo.data = data; + + data->eraseInfo.op = DATAOP_COPY; + + data->eraseInfo.copyBufferSize = 16 * 1024; + data->eraseInfo.copyEmpty = true; + + data->eraseInfo.total = 1; + + data->eraseInfo.isSrcDirectory = action_erase_twl_save_is_src_directory; + data->eraseInfo.makeDstDirectory = action_erase_twl_save_make_dst_directory; + + data->eraseInfo.openSrc = action_erase_twl_save_open_src; + data->eraseInfo.closeSrc = action_erase_twl_save_close_src; + data->eraseInfo.getSrcSize = action_erase_twl_save_get_src_size; + data->eraseInfo.readSrc = action_erase_twl_save_read_src; + + data->eraseInfo.openDst = action_erase_twl_save_open_dst; + data->eraseInfo.closeDst = action_erase_twl_save_close_dst; + data->eraseInfo.writeDst = action_erase_twl_save_write_dst; + + data->eraseInfo.suspendCopy = action_erase_twl_save_suspend_copy; + data->eraseInfo.restoreCopy = action_erase_twl_save_restore_copy; + + data->eraseInfo.suspend = action_erase_twl_save_suspend; + data->eraseInfo.restore = action_erase_twl_save_restore; + + data->eraseInfo.error = action_erase_twl_save_error; + + data->eraseInfo.finished = true; + + prompt_display("Confirmation", "Erase the save of the selected title?", COLOR_TEXT, true, data, action_erase_twl_save_draw_top, action_erase_twl_save_onresponse); +} \ No newline at end of file diff --git a/source/ui/section/action/exporttwlsave.c b/source/ui/section/action/exporttwlsave.c index b43352c..b9b95b3 100644 --- a/source/ui/section/action/exporttwlsave.c +++ b/source/ui/section/action/exporttwlsave.c @@ -1,7 +1,7 @@ +#include #include #include <3ds.h> -#include #include "action.h" #include "../task/task.h" diff --git a/source/ui/section/action/importtwlsave.c b/source/ui/section/action/importtwlsave.c index cc68f3b..96ea912 100644 --- a/source/ui/section/action/importtwlsave.c +++ b/source/ui/section/action/importtwlsave.c @@ -1,7 +1,7 @@ +#include #include #include <3ds.h> -#include #include "action.h" #include "../task/task.h" diff --git a/source/ui/section/action/installcdn.c b/source/ui/section/action/installcdn.c index 1d496f6..2ec269a 100644 --- a/source/ui/section/action/installcdn.c +++ b/source/ui/section/action/installcdn.c @@ -296,7 +296,7 @@ void action_install_cdn_noprompt(volatile bool* done, ticket_info* info, bool fi Result res = 0; - u8 n3ds = false; + bool n3ds = false; if(R_FAILED(APT_CheckNew3DS(&n3ds)) || n3ds || ((data->ticket->titleId >> 28) & 0xF) != 2) { FS_MediaType dest = ((data->ticket->titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; diff --git a/source/ui/section/action/installcias.c b/source/ui/section/action/installcias.c index 13735fc..b887b16 100644 --- a/source/ui/section/action/installcias.c +++ b/source/ui/section/action/installcias.c @@ -116,7 +116,7 @@ static Result action_install_cias_open_dst(void* data, u32 index, void* initialR FS_MediaType dest = ((titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; - u8 n3ds = false; + bool n3ds = false; if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((titleId >> 28) & 0xF) == 2) { return R_FBI_WRONG_SYSTEM; } diff --git a/source/ui/section/networkinstall.c b/source/ui/section/networkinstall.c index 3224aef..1784d19 100644 --- a/source/ui/section/networkinstall.c +++ b/source/ui/section/networkinstall.c @@ -138,7 +138,7 @@ static Result networkinstall_open_dst(void* data, u32 index, void* initialReadBl FS_MediaType dest = ((titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; - u8 n3ds = false; + bool n3ds = false; if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((titleId >> 28) & 0xF) == 2) { return R_FBI_WRONG_SYSTEM; } diff --git a/source/ui/section/qrinstall.c b/source/ui/section/qrinstall.c index 3ff6f76..cd98207 100644 --- a/source/ui/section/qrinstall.c +++ b/source/ui/section/qrinstall.c @@ -140,7 +140,7 @@ static Result qrinstall_open_dst(void* data, u32 index, void* initialReadBlock, FS_MediaType dest = ((titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; - u8 n3ds = false; + bool n3ds = false; if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((titleId >> 28) & 0xF) == 2) { return R_FBI_WRONG_SYSTEM; } diff --git a/source/ui/section/titles.c b/source/ui/section/titles.c index 31f1ef9..bf5b9b3 100644 --- a/source/ui/section/titles.c +++ b/source/ui/section/titles.c @@ -19,6 +19,7 @@ static list_item import_seed = {"Import Seed", COLOR_TEXT, action_import_seed}; static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_title_save_data}; static list_item import_save_data = {"Import Save Data", COLOR_TEXT, action_import_twl_save}; static list_item export_save_data = {"Export Save Data", COLOR_TEXT, action_export_twl_save}; +static list_item erase_save_data = {"Erase Save Data", COLOR_TEXT, action_erase_twl_save}; static list_item import_secure_value = {"Import Secure Value", COLOR_TEXT, action_import_secure_value}; static list_item export_secure_value = {"Export Secure Value", COLOR_TEXT, action_export_secure_value}; static list_item delete_secure_value = {"Delete Secure Value", COLOR_TEXT, action_delete_secure_value}; @@ -93,6 +94,7 @@ static void titles_action_update(ui_view* view, void* data, linked_list* items, } else if(info->mediaType == MEDIATYPE_GAME_CARD) { linked_list_add(items, &import_save_data); linked_list_add(items, &export_save_data); + linked_list_add(items, &erase_save_data); } } }