mirror of
https://github.com/wiiu-env/SDHotSwapModule.git
synced 2025-06-13 00:58:32 +02:00
First commit
This commit is contained in:
52
source/exports.cpp
Normal file
52
source/exports.cpp
Normal 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
6
source/exports.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <sdutils/sdutils.h>
|
||||
|
||||
void callAttachCallbacks(SDUtilsAttachStatus status);
|
||||
|
||||
void cleanUpAttachCallbacks();
|
36
source/logger.c
Normal file
36
source/logger.c
Normal 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
43
source/logger.h
Normal 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
105
source/main.cpp
Normal 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
101
source/sdcard.cpp
Normal 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
27
source/sdcard.h
Normal 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();
|
Reference in New Issue
Block a user