First commit

This commit is contained in:
Maschell
2022-03-04 00:59:38 +01:00
commit cd19e89db5
14 changed files with 720 additions and 0 deletions

52
source/exports.cpp Normal file
View File

@ -0,0 +1,52 @@
#include "exports.h"
#include <cstring>
#include <sdutils/sdutils.h>
#include <wums.h>
#define MAX_HANDLERS 16
static SDAttachHandlerFn sHandlers[MAX_HANDLERS] = {nullptr};
void callAttachCallbacks(SDUtilsAttachStatus status) {
int i;
for (i = 0; i < MAX_HANDLERS; ++i) {
if (sHandlers[i]) {
sHandlers[i](status);
}
}
}
void cleanUpAttachCallbacks() {
memset(sHandlers, 0, sizeof(sHandlers));
}
bool SDUtilsAddAttachHandler(SDAttachHandlerFn fn) {
int i;
for (i = 0; i < MAX_HANDLERS; ++i) {
if (sHandlers[i] == fn) {
return true;
}
if (!sHandlers[i]) {
sHandlers[i] = fn;
return true;
}
}
return false;
}
bool SDUtilsRemoveAttachHandler(SDAttachHandlerFn fn) {
int i;
for (i = 0; i < MAX_HANDLERS; ++i) {
if (sHandlers[i] == fn) {
sHandlers[i] = nullptr;
return true;
}
}
return false;
}
WUMS_EXPORT_FUNCTION(SDUtilsAddAttachHandler);
WUMS_EXPORT_FUNCTION(SDUtilsRemoveAttachHandler);

6
source/exports.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <sdutils/sdutils.h>
void callAttachCallbacks(SDUtilsAttachStatus status);
void cleanUpAttachCallbacks();

36
source/logger.c Normal file
View File

@ -0,0 +1,36 @@
#ifdef DEBUG
#include <stdint.h>
#include <whb/log_cafe.h>
#include <whb/log_module.h>
#include <whb/log_udp.h>
uint32_t moduleLogInit = false;
uint32_t cafeLogInit = false;
uint32_t udpLogInit = false;
#endif // DEBUG
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
}

43
source/logger.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <string.h>
#include <whb/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef DEBUG
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
do { \
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
do { \
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
} while (0)
#else
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
#endif
void initLogging();
void deinitLogging();
#ifdef __cplusplus
}
#endif

105
source/main.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "exports.h"
#include "logger.h"
#include "sdcard.h"
#include <condition_variable>
#include <coreinit/cache.h>
#include <coreinit/filesystem.h>
#include <coreinit/thread.h>
#include <mutex>
#include <sdutils/sdutils.h>
#include <thread>
#include <wums.h>
WUMS_MODULE_EXPORT_NAME("homebrew_sdhotswap");
WUMS_MODULE_SKIP_INIT_FINI();
// This NEEDS to be on the heap. Global DTOR are never called for modules
// but we need a fresh instance of this condition_variable on each app change.
std::condition_variable *cv = nullptr;
std::mutex *cv_m = nullptr;
std::thread *mountThread = nullptr;
bool sStopThread = false;
bool sIsSDInsertedAndMounted = false;
int mount_thread() {
std::unique_lock<std::mutex> lk(*cv_m);
// Wait until the main thread has checked the sd status once.
cv->wait(lk);
while (!sStopThread) {
auto newStatus = IsSDCardInserted();
if (newStatus != sIsSDInsertedAndMounted) {
if (newStatus) {
if (MountSDCard()) {
callAttachCallbacks(SDUTILS_ATTACH_MOUNTED);
sIsSDInsertedAndMounted = true;
}
} else {
if (UnmountSDCard()) {
callAttachCallbacks(SDUTILS_ATTACH_UNMOUNTED);
sIsSDInsertedAndMounted = false;
}
}
OSMemoryBarrier();
}
OSSleepTicks(OSMillisecondsToTicks(100));
}
return 0;
}
WUMS_APPLICATION_STARTS() {
initLogging();
sStopThread = false;
cv = new std::condition_variable;
cv_m = new std::mutex;
OSMemoryBarrier();
mountThread = new std::thread(mount_thread);
auto nativeHandle = (OSThread *) mountThread->native_handle();
OSSetThreadName(nativeHandle, "SDHotSwapModuleThread");
while (!OSSetThreadAffinity(nativeHandle, OS_THREAD_ATTRIB_AFFINITY_CPU2)) {
OSSleepTicks(OSMillisecondsToTicks(16));
}
auto check = InitialSDCheck();
if (check < 0) {
// On error stop thread.
sStopThread = true;
} else {
// Otherwise it retuns the current status.
sIsSDInsertedAndMounted = check == 1;
}
OSMemoryBarrier();
DEBUG_FUNCTION_LINE("Wake up the thread");
// Now we can wake up the thread!
cv->notify_all();
}
WUMS_APPLICATION_ENDS() {
sStopThread = true;
OSMemoryBarrier();
cv->notify_all();
if (mountThread != nullptr) {
mountThread->join();
delete mountThread;
mountThread = nullptr;
}
DeInitSDCheck();
delete cv;
delete cv_m;
cv = nullptr;
cv_m = nullptr;
OSMemoryBarrier();
deinitLogging();
}

101
source/sdcard.cpp Normal file
View File

@ -0,0 +1,101 @@
#include "exports.h"
#include "logger.h"
#include <coreinit/cache.h>
#include <coreinit/filesystem.h>
#include <mutex>
static FSClient sClient;
std::mutex *mutex;
bool sFSClientAdded = false;
int InitialSDCheck() {
mutex = new (std::nothrow) std::mutex;
if (!mutex) {
return -1;
}
FSStatus result = FSAddClient(&sClient, FS_ERROR_FLAG_ALL);
if (result != FS_STATUS_OK) {
return -2;
} else {
sFSClientAdded = true;
OSMemoryBarrier();
FSCmdBlock fsCmd;
FSInitCmdBlock(&fsCmd);
FSMountSource mountSource;
return FSGetMountSource(&sClient, &fsCmd, FS_MOUNT_SOURCE_SD, &mountSource, FS_ERROR_FLAG_ALL) == FS_STATUS_OK;
}
}
void DeInitSDCheck() {
if (mutex) {
delete mutex;
mutex = nullptr;
}
if (sFSClientAdded) {
FSDelClient(&sClient, FS_ERROR_FLAG_ALL);
memset(&sClient, 0, sizeof(sClient));
sFSClientAdded = false;
}
cleanUpAttachCallbacks();
OSMemoryBarrier();
}
int IsSDCardInserted() {
if (!sFSClientAdded || !mutex) {
return -1;
}
std::lock_guard<std::mutex> lk(*mutex);
FSCmdBlock fsCmd;
FSMountSource mountSource;
FSInitCmdBlock(&fsCmd);
memset(&mountSource, 0, sizeof(mountSource));
return FSGetMountSource(&sClient, &fsCmd, FS_MOUNT_SOURCE_SD, &mountSource, FS_ERROR_FLAG_ALL) == FS_STATUS_OK;
}
int MountSDCard() {
if (!sFSClientAdded || !mutex) {
return -1;
}
std::lock_guard<std::mutex> lk(*mutex);
FSCmdBlock fsCmd;
FSInitCmdBlock(&fsCmd);
FSMountSource mountSource;
char mountPath[0x80];
if (FSGetMountSource(&sClient, &fsCmd, FS_MOUNT_SOURCE_SD, &mountSource, FS_ERROR_FLAG_ALL) != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE("No SD Card found");
return 0;
}
FSStatus res;
if ((res = FSMount(&sClient, &fsCmd, &mountSource, mountPath, sizeof(mountPath), FS_ERROR_FLAG_ALL)) != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE("FSMount failed %d", res);
return 0;
}
DEBUG_FUNCTION_LINE("Mounted SD Card");
return 1;
}
int UnmountSDCard() {
if (!sFSClientAdded || !mutex) {
return -1;
}
std::lock_guard<std::mutex> lk(*mutex);
FSCmdBlock fsCmd;
FSInitCmdBlock(&fsCmd);
FSStatus res = FS_STATUS_OK;
while (res == FS_STATUS_OK) {
res = FSUnmount(&sClient, &fsCmd, "/vol/external01", FS_ERROR_FLAG_ALL);
if (res != FS_STATUS_OK && res != FS_STATUS_NOT_FOUND) {
return 0;
}
}
DEBUG_FUNCTION_LINE("Unmounted SD Card");
return 1;
}

27
source/sdcard.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
int InitialSDCheck();
void DeInitSDCheck();
/**
* @return < 0 on error.
* 0 when no FAT32 formatted sd card is inserted
* 1 when a FAT32 formatted sd card is inserted
*/
int IsSDCardInserted();
/**
* @return < 0 on error.
* 0 when mounting failed,
* 1 when mounting was successful.
*/
int MountSDCard();
/**
* @return < 0 on error.
* 0 when unmounting failed,
* 1 when unmounting was successful.
*/
int UnmountSDCard();