2022-01-16 01:04:43 +01:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <malloc.h>
|
|
|
|
|
|
|
|
#include "StorageUtils.h"
|
|
|
|
#include "logger.h"
|
|
|
|
|
|
|
|
#include <coreinit/thread.h>
|
|
|
|
#include <coreinit/title.h>
|
|
|
|
#include <nn/acp/save.h>
|
2022-02-02 19:57:14 +01:00
|
|
|
#include <nn/spm.h>
|
2022-01-16 01:04:43 +01:00
|
|
|
#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) {
|
2022-02-04 21:42:53 +01:00
|
|
|
free(handle);
|
2022-01-16 01:04:43 +01:00
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
memset(config, 0, sizeof(UhsConfig));
|
|
|
|
|
|
|
|
config->controller_num = 0;
|
2022-02-03 14:01:11 +01:00
|
|
|
uint32_t size = 5120;
|
|
|
|
void *buffer = memalign(0x40, size);
|
2022-02-04 21:42:53 +01:00
|
|
|
if (!buffer) {
|
2022-01-16 01:04:43 +01:00
|
|
|
free(handle);
|
|
|
|
free(config);
|
2022-02-04 21:42:53 +01:00
|
|
|
return -3;
|
2022-01-16 01:04:43 +01:00
|
|
|
}
|
|
|
|
memset(buffer, 0, size);
|
|
|
|
|
2022-02-03 14:01:11 +01:00
|
|
|
config->buffer = buffer;
|
2022-01-16 01:04:43 +01:00
|
|
|
config->buffer_size = size;
|
|
|
|
|
|
|
|
if (UhsClientOpen(handle, config) != UHS_STATUS_OK) {
|
|
|
|
DEBUG_FUNCTION_LINE("UhsClient failed");
|
|
|
|
free(handle);
|
|
|
|
free(config);
|
|
|
|
free(buffer);
|
2022-02-04 21:42:53 +01:00
|
|
|
return -4;
|
2022-01-16 01:04:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
UhsInterfaceProfile profiles[10];
|
|
|
|
UhsInterfaceFilter filter = {
|
2022-02-02 19:57:14 +01:00
|
|
|
.match_params = MATCH_ANY};
|
2022-01-16 01:04:43 +01:00
|
|
|
|
2022-01-18 16:29:54 +01:00
|
|
|
UHSStatus result;
|
2022-01-16 01:04:43 +01:00
|
|
|
if ((result = UhsQueryInterfaces(handle, &filter, profiles, 10)) <= UHS_STATUS_OK) {
|
|
|
|
DEBUG_FUNCTION_LINE("UhsQueryInterfaces failed");
|
|
|
|
UhsClientClose(handle);
|
|
|
|
free(handle);
|
|
|
|
free(config);
|
|
|
|
free(buffer);
|
2022-02-04 21:42:53 +01:00
|
|
|
return -5;
|
2022-01-16 01:04:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto found = 0;
|
2022-01-18 16:29:54 +01:00
|
|
|
for (int i = 0; i < (int) result; i++) {
|
2022-01-16 01:04:43 +01:00
|
|
|
if (profiles[i].if_desc.bInterfaceClass == USBCLASS_STORAGE) {
|
|
|
|
DEBUG_FUNCTION_LINE("Found USBCLASS_STORAGE");
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UhsClientClose(handle);
|
|
|
|
free(handle);
|
|
|
|
free(config);
|
2022-02-04 21:42:53 +01:00
|
|
|
free(buffer);
|
2022-01-16 01:04:43 +01:00
|
|
|
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];
|
2022-02-03 14:01:11 +01:00
|
|
|
int tries = 0;
|
2022-01-16 01:04:43 +01:00
|
|
|
bool found = false;
|
|
|
|
|
2022-02-03 13:03:38 +01:00
|
|
|
while (tries < 1200) { // Wait up to 20 seconds, like the Wii U Menu
|
2022-01-16 01:04:43 +01:00
|
|
|
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) {
|
2022-01-18 14:17:15 +01:00
|
|
|
DEBUG_FUNCTION_LINE("USB Storage is connected but either it doesn't have a WFS partition or we ran into a timeout.");
|
2022-01-16 01:04:43 +01:00
|
|
|
InitEmptyExternalStorage();
|
|
|
|
}
|
|
|
|
|
|
|
|
nn::spm::Finalize();
|
|
|
|
}
|