From 676f71e2d1e8b600b7c00bae9f1621926a57cf69 Mon Sep 17 00:00:00 2001 From: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> Date: Sat, 26 Dec 2020 03:23:42 +0100 Subject: [PATCH] wiiu: merge fixes and other polishing --- Makefile | 8 +- src/audio/oal/oal_utils.h | 4 + src/audio/sampman_oal.cpp | 6 +- src/core/CdStreamPosix.cpp | 61 ++++++++++- src/core/FileLoader.cpp | 6 +- src/core/config.h | 6 +- src/core/re3.cpp | 6 +- src/skel/crossplatform.cpp | 2 +- src/skel/wiiu/wiiu.cpp | 200 +++++++++++++------------------------ 9 files changed, 157 insertions(+), 142 deletions(-) diff --git a/Makefile b/Makefile index 87a8fef0..3901e57e 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,13 @@ SOURCES := src \ src/audio \ src/audio/oal \ src/audio/eax \ + src/buildings \ + src/collision \ src/control \ src/core \ src/entities \ + src/extras \ + src/fakerw \ src/math \ src/modelinfo \ src/objects \ @@ -39,9 +43,7 @@ SOURCES := src \ src/skel/wiiu/debug \ src/text \ src/vehicles \ - src/weapons \ - src/extras \ - src/fakerw + src/weapons DATA := data INCLUDES := $(SOURCES) \ vendor/librw \ diff --git a/src/audio/oal/oal_utils.h b/src/audio/oal/oal_utils.h index f0fa090a..c6d3f070 100644 --- a/src/audio/oal/oal_utils.h +++ b/src/audio/oal/oal_utils.h @@ -11,7 +11,9 @@ void EFX_Set(ALuint effect, const EAXLISTENERPROPERTIES *props); void EAX3_SetReverbMix(ALuint filter, float mix); void SetEffectsLevel(ALuint uiFilter, float level); +#ifndef __WIIU__ namespace re3_openal { +#endif extern LPALGENEFFECTS alGenEffects; extern LPALDELETEEFFECTS alDeleteEffects; @@ -47,8 +49,10 @@ extern LPALGETFILTERIV alGetFilteriv; extern LPALGETFILTERF alGetFilterf; extern LPALGETFILTERFV alGetFilterfv; +#ifndef __WIIU__ } using namespace re3_openal; +#endif #endif diff --git a/src/audio/sampman_oal.cpp b/src/audio/sampman_oal.cpp index e11a0c25..74ff7a40 100644 --- a/src/audio/sampman_oal.cpp +++ b/src/audio/sampman_oal.cpp @@ -47,6 +47,8 @@ #include #include #include +#elif defined __WIIU__ +extern "C" char *_getcwd (char *__buf, size_t __size); #else #define _getcwd getcwd #endif @@ -501,6 +503,8 @@ _ResolveLink(char const *path, char *out) psl->Release(); } + return false; +#elif defined __WIIU__ return false; #else struct stat sb; @@ -542,7 +546,7 @@ _FindMP3s(void) int total_ms; WIN32_FIND_DATA fd; - if (getcwd(_mp3DirectoryPath, MAX_PATH) == NULL) { + if (_getcwd(_mp3DirectoryPath, MAX_PATH) == NULL) { perror("getcwd: "); return; } diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 5f88955e..9aaba0ae 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -42,7 +42,7 @@ static int wiiu_thread_create(OSThread *thread, const void *attr, void *(*start_ { OSThread *handle = (OSThread *)memalign(16, sizeof(OSThread)); unsigned int stackSize = 0x8000; - void *stackTop = memalign(16, stackSize) + stackSize; + void *stackTop = (uint8*) memalign(16, stackSize) + stackSize; if (!OSCreateThread(handle, (OSThreadEntryPointFn)start_routine, @@ -85,7 +85,11 @@ struct CdReadInfo pthread_t pChannelThread; sem_t *pStartSemaphore; #endif +#ifdef __WIIU__ + OSSemaphore pDoneSemaphore; +#else sem_t *pDoneSemaphore; // used for CdStreamSync +#endif int32 hFile; }; @@ -103,10 +107,10 @@ OSSemaphore gCdStreamSema; #else pthread_t _gCdStreamThread; sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set) +#endif int8 gCdStreamThreadStatus; // 0: created 1:priority set up 2:abort now Queue gChannelRequestQ; bool _gbCdStreamOverlapped; -#endif CdReadInfo *gpReadInfo; @@ -127,6 +131,9 @@ CdStreamInitThread(void) gChannelRequestQ.tail = 0; gChannelRequestQ.size = gNumChannels + 1; ASSERT(gChannelRequestQ.items != nil ); +#ifdef __WIIU__ + OSInitSemaphore(&gCdStreamSema, 0); +#else gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1); @@ -135,12 +142,16 @@ CdStreamInitThread(void) ASSERT(0); return; } +#endif #endif if ( gNumChannels > 0 ) { for ( int32 i = 0; i < gNumChannels; i++ ) { +#ifdef __WIIU__ + OSInitSemaphore(&gpReadInfo[i].pDoneSemaphore, 0); +#else sprintf(semName,"/semaphore_done%d",i); gpReadInfo[i].pDoneSemaphore = sem_open(semName, O_CREAT, 0644, 1); @@ -150,6 +161,7 @@ CdStreamInitThread(void) ASSERT(0); return; } +#endif #ifdef ONE_THREAD_PER_CHANNEL sprintf(semName,"/semaphore_start%d",i); gpReadInfo[i].pStartSemaphore = sem_open(semName, O_CREAT, 0644, 1); @@ -178,6 +190,9 @@ CdStreamInitThread(void) #ifndef ONE_THREAD_PER_CHANNEL debug("Using one streaming thread for all channels\n"); gCdStreamThreadStatus = 0; +#ifdef __WIIU__ + wiiu_thread_create(&_gCdStreamThread, NULL, CdStreamThread, nil); +#else status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil); if (status == -1) @@ -186,6 +201,7 @@ CdStreamInitThread(void) ASSERT(0); return; } +#endif #else debug("Using separate streaming threads for each channel\n"); #endif @@ -194,6 +210,7 @@ CdStreamInitThread(void) void CdStreamInit(int32 numChannels) { +#ifndef __WIIU__ struct statvfs fsInfo; if((statvfs("models/gta3.img", &fsInfo)) < 0) @@ -216,6 +233,11 @@ CdStreamInit(int32 numChannels) } */ void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize); + +#else + // statvfs doesn't work properly on wiiu + void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE); +#endif ASSERT( pBuffer != nil ); gNumImages = 0; @@ -266,8 +288,14 @@ CdStreamShutdown(void) // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL gCdStreamThreadStatus = 2; +#ifdef __WIIU__ + OSSignalSemaphore(&gCdStreamSema); + // softlocks + // OSJoinThread(&_gCdStreamThread, NULL); +#else sem_post(gCdStreamSema); pthread_join(_gCdStreamThread, nil); +#endif #else for ( int32 i = 0; i < gNumChannels; i++ ) { gpReadInfo[i].nThreadStatus = 2; @@ -311,8 +339,12 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) #ifndef ONE_THREAD_PER_CHANNEL AddToQueue(&gChannelRequestQ, channel); +#ifdef __WIIU__ + OSSignalSemaphore(&gCdStreamSema); +#else if ( sem_post(gCdStreamSema) != 0 ) printf("Signal Sema Error\n"); +#endif #else if ( sem_post(pChannel->pStartSemaphore) != 0 ) printf("Signal Sema Error\n"); @@ -380,9 +412,15 @@ CdStreamSync(int32 channel) pChannel->nSectorsToRead = 0; if (pChannel->bReading) { pChannel->bLocked = true; +#ifdef __WIIU__ + OSCancelThread(&_gCdStreamThread); + while (pChannel->bLocked) + OSWaitSemaphore(&pChannel->pDoneSemaphore); +#else pthread_kill(_gCdStreamThread, SIGUSR1); while (pChannel->bLocked) sem_wait(pChannel->pDoneSemaphore); +#endif } #endif pChannel->bReading = false; @@ -394,7 +432,11 @@ CdStreamSync(int32 channel) { pChannel->bLocked = true; while (pChannel->bLocked) +#ifdef __WIIU__ + OSWaitSemaphore(&pChannel->pDoneSemaphore); +#else sem_wait(pChannel->pDoneSemaphore); +#endif } pChannel->bReading = false; @@ -445,7 +487,11 @@ void *CdStreamThread(void *param) #ifndef ONE_THREAD_PER_CHANNEL while (gCdStreamThreadStatus != 2) { +#ifdef __WIIU__ + OSWaitSemaphore(&gCdStreamSema); +#else sem_wait(gCdStreamSema); +#endif int32 channel = GetFirstInQueue(&gChannelRequestQ); #else int channel = *((int*)param); @@ -498,12 +544,17 @@ void *CdStreamThread(void *param) if ( pChannel->bLocked ) { pChannel->bLocked = 0; +#ifdef __WIIU__ + OSSignalSemaphore(&pChannel->pDoneSemaphore); +#else sem_post(pChannel->pDoneSemaphore); +#endif } pChannel->bReading = false; } char semName[20]; #ifndef ONE_THREAD_PER_CHANNEL +#ifndef __WIIU__ for ( int32 i = 0; i < gNumChannels; i++ ) { sem_close(gpReadInfo[i].pDoneSemaphore); @@ -512,6 +563,7 @@ void *CdStreamThread(void *param) } sem_close(gCdStreamSema); sem_unlink("/semaphore_cd_stream"); +#endif free(gChannelRequestQ.items); #else sem_close(gpReadInfo[channel].pStartSemaphore); @@ -525,8 +577,13 @@ void *CdStreamThread(void *param) if (gpReadInfo) free(gpReadInfo); gpReadInfo = nil; +#ifdef __WIIU__ + //OSExitThread(0); + return 0; +#else pthread_exit(nil); #endif +#endif } bool diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index c5eb0338..e60ff809 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -213,7 +213,11 @@ CFileLoader::LoadCollisionFile(const char *filename) fd = CFileMgr::OpenFile(filename, "rb"); while(CFileMgr::Read(fd, (char*)&header, sizeof(header))){ - assert(strncmp(header.ident, "COLL", 4) == 0); +#ifdef BIGENDIAN + assert(header.ident == 'COLL'); +#else + assert(header.ident == 'LLOC'); +#endif #ifdef BIGENDIAN header.size = BSWAP32(header.size); #endif diff --git a/src/core/config.h b/src/core/config.h index e5a97049..eee4d748 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -269,7 +269,7 @@ enum Config { #if !defined(RW_GL3) && defined(_WIN32) #define XINPUT #endif -#if !defined(_WIN32) && !defined(__SWITCH__) +#if !defined(_WIN32) && !defined(__SWITCH__) && !defined(__WIIU__) #define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list. #endif #define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m @@ -305,7 +305,9 @@ enum Config { # define GRAPHICS_MENU_OPTIONS // otherwise Display settings will be scrollable # define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU # define CUTSCENE_BORDERS_SWITCH -# define MULTISAMPLING // adds MSAA option +# ifndef __WIIU__ // not supported in gx2 librw +# define MULTISAMPLING // adds MSAA option +# endif # define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC # endif #endif diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 82c084b1..127c3503 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -41,14 +41,14 @@ #include #endif +#ifdef __WIIU__ #include #include #endif -#include - #ifdef RWLIBS - +extern "C" int vsprintf(char* const _Buffer, char const* const _Format, va_list _ArgList); +#endif #ifdef USE_PS2_RAND unsigned long long myrand_seed = 1; diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp index de940921..7364e6a1 100644 --- a/src/skel/crossplatform.cpp +++ b/src/skel/crossplatform.cpp @@ -38,7 +38,7 @@ HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) { // Case-sensitivity and backslashes... // Will be freed at the bottom - char *realFolder = casepath(folder); + char *realFolder = casepath(folder, false); if (realFolder) { folder = realFolder; } diff --git a/src/skel/wiiu/wiiu.cpp b/src/skel/wiiu/wiiu.cpp index 91a99406..76a40ac2 100644 --- a/src/skel/wiiu/wiiu.cpp +++ b/src/skel/wiiu/wiiu.cpp @@ -34,6 +34,7 @@ #include "Sprite2d.h" #include "AnimViewer.h" #include "Font.h" +#include "MemoryMgr.h" #include #include @@ -74,7 +75,7 @@ void _psCreateFolder(const char *path) char fullpath[PATH_MAX]; realpath(path, fullpath); - if (lstat(fullpath, &info) != 0) { + if (stat(fullpath, &info) != 0) { if (errno == ENOENT || (errno != EACCES && !S_ISDIR(info.st_mode))) { mkdir(fullpath, 0755); } @@ -168,7 +169,11 @@ psMouseSetPos(RwV2d *pos) RwMemoryFunctions* psGetMemoryFunctions(void) { +#ifdef USE_CUSTOM_ALLOCATOR + return &memFuncs; +#else return nil; +#endif } /* @@ -196,8 +201,6 @@ psNativeTextureSupport(void) RwBool psInitialize(void) { - WHBLogPrintf("psInitialize"); - PsGlobal.lastMousePos.x = PsGlobal.lastMousePos.y = 0.0f; RsGlobal.ps = &PsGlobal; @@ -208,7 +211,6 @@ psInitialize(void) PsGlobal.joy1id = -1; PsGlobal.joy2id = -1; - WHBLogPrintf("Initializing CFileMgr"); CFileMgr::Initialise(); #ifdef PS2_MENU @@ -261,36 +263,31 @@ psInitialize(void) TheMemoryCard.Init(); #else - WHBLogPrintf("Setting save dir"); C_PcSave::SetSaveDirectory(_psGetUserFilesFolder()); - WHBLogPrintf("Initializing language"); InitialiseLanguage(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif #endif - WHBLogPrintf("gGameState = GS_START_UP"); gGameState = GS_START_UP; TRACE("gGameState = GS_START_UP"); + _dwOperatingSystemVersion = OS_WINXP; + #ifndef PS2_MENU -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif #endif - // TODO: Is there a way to get free ram on wiiu? - _dwMemAvailPhys = 1024*1024*170; //systemInfo.freeram; - _dwOperatingSystemVersion = OS_WINXP; // To fool other classes - - // debug("Physical memory size %u\n", systemInfo.totalram); - // debug("Available physical memory %u\n", systemInfo.freeram); + // memory required to have all vehicles loaded + _dwMemAvailPhys = 1024*1024*170; TheText.Unload(); @@ -414,18 +411,15 @@ psSelectDevice() RwVideoMode vm; RwInt32 subSysNum; RwInt32 AutoRenderer = 0; - - WHBLogPrintf("psSelectDevice"); RwBool modeFound = FALSE; if ( !useDefault ) { - WHBLogPrintf("Not using default"); + GnumSubSystems = RwEngineGetNumSubSystems(); if ( !GnumSubSystems ) { - WHBLogPrintf("no subsystems"); return FALSE; } @@ -438,7 +432,6 @@ psSelectDevice() RwEngineGetSubSystemInfo(&GsubSysInfo[subSysNum], subSysNum); } - WHBLogPrintf("RwEngineGetCurrentSubSystem"); /* Get the default selection */ GcurSel = RwEngineGetCurrentSubSystem(); #ifdef IMPROVED_VIDEOMODE @@ -450,7 +443,6 @@ psSelectDevice() /* Set the driver to use the correct sub system */ if (!RwEngineSetSubSystem(GcurSel)) { - WHBLogPrintf("cannot set subsystem %d", GcurSel); return FALSE; } @@ -575,7 +567,6 @@ psSelectDevice() * dimensions to match */ if (!RwEngineSetVideoMode(GcurSelVM)) { - WHBLogPrintf("Cannot set video mode"); return FALSE; } /* @@ -630,24 +621,9 @@ long _InputInitialiseMouse() void psPostRWinit(void) { - RwVideoMode vm; - RwEngineGetVideoModeInfo(&vm, GcurSelVM); - - // TODO: wiiu - - // glfwSetKeyCallback(PSGLOBAL(window), keypressCB); - // glfwSetWindowSizeCallback(PSGLOBAL(window), resizeCB); - // glfwSetScrollCallback(PSGLOBAL(window), scrollCB); - // glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB); - // glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB); - // glfwSetJoystickCallback(joysChangeCB); - _InputInitialiseJoys(); _InputInitialiseMouse(); - // if(!(vm.flags & rwVIDEOMODEEXCLUSIVE)) - // glfwSetWindowSize(PSGLOBAL(window), RsGlobal.maximumWidth, RsGlobal.maximumHeight); - // Make sure all keys are released CPad::GetPad(0)->Clear(true); CPad::GetPad(1)->Clear(true); @@ -693,7 +669,7 @@ RwBool _psSetVideoMode(RwInt32 subSystem, RwInt32 videoMode) void InitialiseLanguage() { - // TODO: wiiu get system language + // TODO: wiiu get system language // Mandatory for Linux(Unix? Posix?) to set lang. to environment lang. setlocale(LC_ALL, ""); @@ -875,9 +851,12 @@ main(int argc, char *argv[]) RwV2d pos; RwInt32 i; - WHBProcInit(); +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); +#endif + + WHBProcInit(); WHBInitCrashHandler(); - WHBMountSdCard(); WHBLogUdpInit(); @@ -899,7 +878,6 @@ main(int argc, char *argv[]) return FALSE; } - WHBLogPrintf("RE3 Wii U initialized"); // for(i=1; iGetLeftMouseJustDown()) // ++gGameState; // else if (CPad::GetPad(0)->GetEnterJustDown()) @@ -1087,12 +1051,11 @@ main(int argc, char *argv[]) // else if (CPad::GetPad(0)->GetTabJustDown()) // ++gGameState; - break; - } + break; + } - case GS_INIT_INTRO_MPEG: + case GS_INIT_INTRO_MPEG: { - WHBLogPrintf("GS_INIT_INTRO_MPEG"); //#ifndef NO_MOVIES // CloseClip(); // CoUninitialize(); @@ -1103,18 +1066,17 @@ main(int argc, char *argv[]) // else // PlayMovieInWindow(cmdShow, "movies\\GTAtitles.mpg"); - gGameState = GS_INTRO_MPEG; - TRACE("gGameState = GS_INTRO_MPEG;"); - break; - } + gGameState = GS_INTRO_MPEG; + TRACE("gGameState = GS_INTRO_MPEG;"); + break; + } - case GS_INTRO_MPEG: + case GS_INTRO_MPEG: { - WHBLogPrintf("GS_INTRO_MPEG"); // CPad::UpdatePads(); // // if (startupDeactivate || ControlsManager.GetJoyButtonJustDown() != 0) - ++gGameState; + ++gGameState; // else if (CPad::GetPad(0)->GetLeftMouseJustDown()) // ++gGameState; // else if (CPad::GetPad(0)->GetEnterJustDown()) @@ -1126,12 +1088,11 @@ main(int argc, char *argv[]) // else if (CPad::GetPad(0)->GetTabJustDown()) // ++gGameState; - break; - } + break; + } case GS_INIT_ONCE: { - WHBLogPrintf("GS_INIT_ONCE"); //CoUninitialize(); #ifdef PS2_MENU @@ -1143,10 +1104,8 @@ main(int argc, char *argv[]) printf("Into TheGame!!!\n"); #else - WHBLogPrintf("loadsc0"); LoadingScreen(nil, nil, "loadsc0"); #endif - WHBLogPrintf("InitialiseOnceAfterRW"); if ( !CGame::InitialiseOnceAfterRW() ) RsGlobal.quit = TRUE; @@ -1162,20 +1121,12 @@ main(int argc, char *argv[]) #ifndef PS2_MENU case GS_INIT_FRONTEND: { - WHBLogPrintf("GS_INIT_FRONTEND"); LoadingScreen(nil, nil, "loadsc0"); FrontEndMenuManager.m_bGameNotLoaded = true; CMenuManager::m_bStartUpFrontEndRequested = true; - // TODO: wiiu - // if ( defaultFullscreenRes ) - // { - // defaultFullscreenRes = FALSE; - // FrontEndMenuManager.m_nPrefsVideoMode = GcurSelVM; - // FrontEndMenuManager.m_nDisplayVideoMode = GcurSelVM; - // } gGameState = GS_FRONTEND; TRACE("gGameState = GS_FRONTEND;"); @@ -1213,7 +1164,6 @@ main(int argc, char *argv[]) case GS_INIT_PLAYING_GAME: { - WHBLogPrintf("GS_INIT_PLAYING_GAME"); #ifdef PS2_MENU CGame::Initialise("DATA\\GTA3.DAT"); @@ -1248,7 +1198,6 @@ main(int argc, char *argv[]) case GS_PLAYING_GAME: { - WHBLogPrintf("GS_PLAYING_GAME"); float ms = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond(); if ( RwInitialised ) { @@ -1257,19 +1206,6 @@ main(int argc, char *argv[]) } break; } -#ifndef MASTER - case GS_ANIMVIEWER: - { - WHBLogPrintf("GS_ANIMVIEWER"); - float ms = (float)CTimer::GetCurrentTimeInCycles() / (float)CTimer::GetCyclesPerMillisecond(); - if (RwInitialised) - { - if (!CMenuManager::m_PrefsFrameLimiter || (1000.0f / (float)RsGlobal.maxFPS) < ms) - RsEventHandler(rsANIMVIEWER, (void*)TRUE); - } - break; - } -#endif } } else @@ -1344,9 +1280,12 @@ main(int argc, char *argv[]) if ( gGameState == GS_PLAYING_GAME ) CGame::ShutDown(); #ifndef MASTER - else if ( gGameState == GS_ANIMVIEWER ) + if ( gbModelViewer ) CAnimViewer::Shutdown(); + else #endif + if ( gGameState == GS_PLAYING_GAME ) + CGame::ShutDown(); CTimer::Stop(); @@ -1371,9 +1310,12 @@ main(int argc, char *argv[]) if ( gGameState == GS_PLAYING_GAME ) CGame::ShutDown(); #ifndef MASTER - else if ( gGameState == GS_ANIMVIEWER ) + if ( gbModelViewer ) CAnimViewer::Shutdown(); + else #endif + if ( gGameState == GS_PLAYING_GAME ) + CGame::ShutDown(); DMAudio.Terminate(); @@ -1390,8 +1332,8 @@ main(int argc, char *argv[]) */ RsEventHandler(rsTERMINATE, nil); - WHBUnmountSdCard(); - WHBProcShutdown(); + WHBUnmountSdCard(); + WHBProcShutdown(); return 0; }