// TODO : find a better place to put this
#define RUNFLAG_APTWORKAROUND (BIT(0))
+#define RUNFLAG_APTREINIT (BIT(1))
typedef enum{
APPID_HOMEMENU = 0x101, // Home Menu
Result APT_GetLockHandle(Handle* handle, u16 flags, Handle* lockHandle);
Result APT_Initialize(Handle* handle, NS_APPID appId, Handle* eventHandle1, Handle* eventHandle2);
+Result APT_Finalize(Handle* handle, NS_APPID appId);
Result APT_HardwareResetAsync(Handle* handle);
Result APT_Enable(Handle* handle, u32 a);
Result APT_GetAppletManInfo(Handle* handle, u8 inval, u8 *outval8, u32 *outval32, NS_APPID *menu_appid, NS_APPID *active_appid);
Result APT_PrepareToJumpToHomeMenu(Handle* handle);
Result APT_JumpToHomeMenu(Handle* handle, u32 a, u32 b, u32 c);
+Result APT_PrepareToJumpToApplication(Handle* handle, u32 a);
+Result APT_JumpToApplication(Handle* handle, u32 a, u32 b, u32 c);
Result APT_IsRegistered(Handle* handle, NS_APPID appID, u8* out);
Result APT_InquireNotification(Handle* handle, u32 appID, u8* signalType);
Result APT_NotifyToWait(Handle* handle, NS_APPID appID);
static u32 *__apt_launchapplet_parambuf;
static u32 __apt_launchapplet_parambufsize;
+// The following function can be overriden in order to log APT signals and notifications for debugging purposes
+__attribute__((weak)) void _aptDebug(int a, int b)
+{
+}
+
static void aptAppStarted(void);
+static bool aptIsCrippled(void)
+{
+ return (__system_runflags & RUNFLAG_APTWORKAROUND) != 0;
+}
+
+static bool aptIsReinit(void)
+{
+ return (__system_runflags & RUNFLAG_APTREINIT) != 0;
+}
+
static Result __apt_initservicehandle()
{
Result ret=0;
NS_APPID menu_appid;
u32 tmp0 = 1, tmp1 = 0;
- if(__system_runflags&RUNFLAG_APTWORKAROUND)
+ if(aptIsCrippled())
{
svcClearEvent(aptStatusEvent);
aptSetStatus(APP_EXITING);
aptCloseSession();
}
+ // Set status to SUSPENDED.
+ svcClearEvent(aptStatusEvent);
+ aptSetStatus(APP_SUSPENDED);
+
// Prepare for return to menu
aptOpenSession();
APT_PrepareToJumpToHomeMenu(NULL);
aptCloseSession();
- // Set status to SUSPENDED.
- svcClearEvent(aptStatusEvent);
- aptSetStatus(APP_SUSPENDED);
-
// Save Vram
GSPGPU_SaveVramSysArea(NULL);
aptOpenSession();
ret = APT_InquireNotification(NULL, currentAppId, &type);
aptCloseSession();
+ if(ret!=0) return;
- if(ret!=0)return;
+ _aptDebug(1, type);
switch(type)
{
APT_ReceiveParameter(NULL, currentAppId, 0x1000, aptParameters, NULL, &type);
aptCloseSession();
+ _aptDebug(2, type);
+
switch(type)
{
case 0x1: // Application just started.
aptSetStatus(APP_APPLETCLOSED);
return true;
case 0xB: // Just returned from menu.
- GSPGPU_AcquireRight(NULL, 0x0);
- GSPGPU_RestoreVramSysArea(NULL);
- aptAppletUtility_Exit_RetToApp(0);
- aptSetStatus(APP_RUNNING);
+ if (aptStatusMutex)
+ {
+ GSPGPU_AcquireRight(NULL, 0x0);
+ GSPGPU_RestoreVramSysArea(NULL);
+ aptAppletUtility_Exit_RetToApp(0);
+ aptSetStatus(APP_RUNNING);
+ } else
+ aptAppStarted();
return true;
case 0xC: // Exiting application.
while(runThread)
{
s32 syncedID = 0;
- svcWaitSynchronizationN(&syncedID, aptEvents, 2, 0, U64_MAX);
+ svcWaitSynchronizationN(&syncedID, aptEvents, 3, 0, U64_MAX);
svcClearEvent(aptEvents[syncedID]);
-
switch(syncedID)
{
// Event 0 means we got a signal from NS (home button, power button etc).
case 0x1:
runThread = __handle_incoming_parameter();
break;
- // Event 2 means we should exit the thread (event will be added later).
+ // Event 2 means we should exit the thread.
case 0x2:
runThread = false;
break;
if (aptInitialised) return ret;
+ aptStatusMutex = 0;
+
// Initialize APT stuff, escape load screen.
ret = __apt_initservicehandle();
if(ret!=0)return ret;
svcCreateEvent(&aptStatusEvent, 0);
svcCreateEvent(&aptSleepSync, 0);
- if(!(__system_runflags&RUNFLAG_APTWORKAROUND))
+ if(!aptIsCrippled())
{
aptOpenSession();
if((ret=APT_Initialize(NULL, currentAppId, &aptEvents[0], &aptEvents[1])))return ret;
if((ret=APT_Enable(NULL, 0x0)))return ret;
aptCloseSession();
+ // create APT close event
+ svcCreateEvent(&aptEvents[2], 0);
+
+ // After a cycle of APT_Finalize+APT_Initialize APT thinks the
+ // application is suspended, so we need to tell it to unsuspend us.
+ if (aptIsReinit())
+ {
+ aptOpenSession();
+ APT_PrepareToJumpToApplication(NULL, 0x0);
+ aptCloseSession();
+
+ aptOpenSession();
+ APT_JumpToApplication(NULL, 0x0, 0x0, 0x0);
+ aptCloseSession();
+ }
+
aptOpenSession();
if((ret=APT_NotifyToWait(NULL, currentAppId)))return ret;
aptCloseSession();
-
+
// create APT event handler thread
svcCreateThread(&aptEventHandlerThread, aptEventHandler, 0x0,
(u32*)(&aptEventHandlerStack[APT_HANDLER_STACKSIZE/8]), 0x31, 0xfffffffe);
{
if (!aptInitialised) return;
- if(!(__system_runflags&RUNFLAG_APTWORKAROUND))aptAppletUtility_Exit_RetToApp(0);
+ if(!aptIsCrippled())aptAppletUtility_Exit_RetToApp(0);
// This is only executed when application-termination was triggered via the home-menu power-off screen.
if(aptGetStatusPower() == 1)
aptCloseSession();
}
- if(!(__system_runflags&RUNFLAG_APTWORKAROUND))
+ if(!aptIsCrippled())
{
- aptOpenSession();
- APT_PrepareToCloseApplication(NULL, 0x1);
- aptCloseSession();
+ bool isReinit = aptIsReinit();
+ if (aptGetStatus() == APP_EXITING)
+ {
+ aptOpenSession();
+ APT_PrepareToCloseApplication(NULL, 0x1);
+ aptCloseSession();
- aptOpenSession();
- APT_CloseApplication(NULL, 0x0, 0x0, 0x0);
- aptCloseSession();
+ aptOpenSession();
+ APT_CloseApplication(NULL, 0x0, 0x0, 0x0);
+ aptCloseSession();
+
+ if (isReinit)
+ {
+ extern void (*__system_retAddr)(void);
+ __system_retAddr = NULL;
+ }
+ } else if (isReinit)
+ {
+ aptOpenSession();
+ APT_Finalize(NULL, currentAppId);
+ aptCloseSession();
+ }
}
+
+ svcSignalEvent(aptEvents[2]);
+ svcWaitSynchronization(aptEventHandlerThread, U64_MAX);
+ svcCloseHandle(aptEventHandlerThread);
+ svcCloseHandle(aptEvents[2]);
svcCloseHandle(aptSleepSync);
{
while(1)
{
- //if(__system_runflags&RUNFLAG_APTWORKAROUND)__handle_notification();
+ //if(aptIsCrippled())__handle_notification();
switch(aptGetStatus())
{
aptSetStatus(APP_RUNNING);
- if(!(__system_runflags&RUNFLAG_APTWORKAROUND))
+ if(!aptIsCrippled())
{
memset(buf1, 0, 4);
return cmdbuf[1];
}
+Result APT_Finalize(Handle* handle, NS_APPID appId)
+{
+ if(!handle)handle=&aptuHandle;
+ u32* cmdbuf=getThreadCommandBuffer();
+ cmdbuf[0]=0x40040; //request header code
+ cmdbuf[1]=appId;
+
+ Result ret=0;
+ if((ret=svcSendSyncRequest(*handle)))return ret;
+ return cmdbuf[1];
+}
+
Result APT_HardwareResetAsync(Handle* handle)
{
if(!handle)handle=&aptuHandle;
return cmdbuf[1];
}
+Result APT_PrepareToJumpToApplication(Handle* handle, u32 a)
+{
+ if(!handle)handle=&aptuHandle;
+ u32* cmdbuf=getThreadCommandBuffer();
+ cmdbuf[0]=0x230040; //request header code
+ cmdbuf[1]=a;
+
+ Result ret=0;
+ if((ret=svcSendSyncRequest(*handle)))return ret;
+
+ return cmdbuf[1];
+}
+
+Result APT_JumpToApplication(Handle* handle, u32 a, u32 b, u32 c)
+{
+ if(!handle)handle=&aptuHandle;
+ u32* cmdbuf=getThreadCommandBuffer();
+ cmdbuf[0]=0x240044; //request header code
+ cmdbuf[1]=a;
+ cmdbuf[2]=b;
+ cmdbuf[3]=c;
+ cmdbuf[4]=(b<<14)|2;
+
+ Result ret=0;
+ if((ret=svcSendSyncRequest(*handle)))return ret;
+
+ return cmdbuf[1];
+}
+
Result APT_NotifyToWait(Handle* handle, NS_APPID appID)
{
if(!handle)handle=&aptuHandle;