Miscellaneous APT fixes and cleanup, see details:
- APT parameter handling now follows official sw a bit more closely (with the APT thread acting as a filter which then relays the status to the main thread using a LightEvent) - RUNFLAG_APTREINIT (hax 2.x) handling code has been simplified and made (hopefully) more robust - Fixed sleep handling when the app is inactive (i.e. app is suspended) - APT debug callback now guarded by an #ifdef (LIBCTRU_APT_DEBUG) - Removed old Citra response cmdheader workaround - Other miscellaneous fixes I probably forgot to talk about
This commit is contained in:
parent
59b8fd8283
commit
7171a87d53
@ -22,6 +22,7 @@
|
|||||||
static int aptRefCount = 0;
|
static int aptRefCount = 0;
|
||||||
static Handle aptLockHandle;
|
static Handle aptLockHandle;
|
||||||
static Handle aptEvents[2];
|
static Handle aptEvents[2];
|
||||||
|
static LightEvent aptReceiveEvent;
|
||||||
static LightEvent aptSleepEvent;
|
static LightEvent aptSleepEvent;
|
||||||
static Thread aptEventHandlerThread;
|
static Thread aptEventHandlerThread;
|
||||||
static bool aptEventHandlerThreadQuit;
|
static bool aptEventHandlerThreadQuit;
|
||||||
@ -39,12 +40,13 @@ enum
|
|||||||
FLAG_WKUPBYCANCEL = BIT(5),
|
FLAG_WKUPBYCANCEL = BIT(5),
|
||||||
FLAG_WANTSTOSLEEP = BIT(6),
|
FLAG_WANTSTOSLEEP = BIT(6),
|
||||||
FLAG_SLEEPING = BIT(7),
|
FLAG_SLEEPING = BIT(7),
|
||||||
|
FLAG_SPURIOUS = BIT(30),
|
||||||
FLAG_EXITED = BIT(31),
|
FLAG_EXITED = BIT(31),
|
||||||
};
|
};
|
||||||
|
|
||||||
static u8 aptHomeButtonState;
|
static u8 aptHomeButtonState;
|
||||||
static u8 aptRecentHomeButtonState;
|
static u8 aptRecentHomeButtonState;
|
||||||
static u32 aptFlags = FLAG_ALLOWSLEEP;
|
static u32 aptFlags;
|
||||||
static bool aptHomeAllowed = true;
|
static bool aptHomeAllowed = true;
|
||||||
static u32 aptParameters[0x1000/4];
|
static u32 aptParameters[0x1000/4];
|
||||||
static u64 aptChainloadTid;
|
static u64 aptChainloadTid;
|
||||||
@ -64,10 +66,12 @@ typedef enum
|
|||||||
static void aptEventHandler(void *arg);
|
static void aptEventHandler(void *arg);
|
||||||
static APT_Command aptWaitForWakeUp(APT_Transition transition);
|
static APT_Command aptWaitForWakeUp(APT_Transition transition);
|
||||||
|
|
||||||
// The following function can be overriden in order to log APT signals and notifications for debugging purposes
|
// The following function can be overridden in order to log APT signals and notifications for debugging purposes
|
||||||
__attribute__((weak)) void _aptDebug(int a, int b)
|
#ifdef LIBCTRU_APT_DEBUG
|
||||||
{
|
__attribute__((weak)) void _aptDebug(int a, int b) { }
|
||||||
}
|
#else
|
||||||
|
#define _aptDebug(a,b) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void aptCallHook(APT_HookType hookType)
|
static void aptCallHook(APT_HookType hookType)
|
||||||
{
|
{
|
||||||
@ -133,7 +137,7 @@ Result aptSendCommand(u32* aptcmdbuf)
|
|||||||
res = svcSendSyncRequest(aptuHandle);
|
res = svcSendSyncRequest(aptuHandle);
|
||||||
if (R_SUCCEEDED(res))
|
if (R_SUCCEEDED(res))
|
||||||
{
|
{
|
||||||
memcpy(aptcmdbuf, cmdbuf, 4*16);//4*countPrmWords(cmdbuf[0])); // Workaround for Citra failing to emulate response cmdheaders
|
memcpy(aptcmdbuf, cmdbuf, 4*countPrmWords(cmdbuf[0]));
|
||||||
res = aptcmdbuf[1];
|
res = aptcmdbuf[1];
|
||||||
}
|
}
|
||||||
svcCloseHandle(aptuHandle);
|
svcCloseHandle(aptuHandle);
|
||||||
@ -142,20 +146,6 @@ Result aptSendCommand(u32* aptcmdbuf)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aptClearParamQueue(void)
|
|
||||||
{
|
|
||||||
// Check for parameters?
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
APT_Command cmd;
|
|
||||||
Result res = APT_GlanceParameter(envGetAptAppId(), aptParameters, sizeof(aptParameters), NULL, &cmd, NULL, NULL);
|
|
||||||
if (R_FAILED(res) || cmd==APTCMD_NONE) break;
|
|
||||||
_aptDebug(2, cmd);
|
|
||||||
svcClearEvent(aptEvents[1]);
|
|
||||||
APT_CancelParameter(APPID_NONE, envGetAptAppId(), NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void aptInitCaptureInfo(aptCaptureBufInfo* capinfo)
|
static void aptInitCaptureInfo(aptCaptureBufInfo* capinfo)
|
||||||
{
|
{
|
||||||
GSPGPU_CaptureInfo gspcapinfo;
|
GSPGPU_CaptureInfo gspcapinfo;
|
||||||
@ -203,11 +193,8 @@ Result aptInit(void)
|
|||||||
ret = APT_Initialize(envGetAptAppId(), attr, &aptEvents[0], &aptEvents[1]);
|
ret = APT_Initialize(envGetAptAppId(), attr, &aptEvents[0], &aptEvents[1]);
|
||||||
if (R_FAILED(ret)) goto _fail2;
|
if (R_FAILED(ret)) goto _fail2;
|
||||||
|
|
||||||
// Enable APT
|
// Initialize light events
|
||||||
ret = APT_Enable(attr);
|
LightEvent_Init(&aptReceiveEvent, RESET_STICKY);
|
||||||
if (R_FAILED(ret)) goto _fail3;
|
|
||||||
|
|
||||||
// Initialize APT sleep event
|
|
||||||
LightEvent_Init(&aptSleepEvent, RESET_ONESHOT);
|
LightEvent_Init(&aptSleepEvent, RESET_ONESHOT);
|
||||||
|
|
||||||
// Create APT event handler thread
|
// Create APT event handler thread
|
||||||
@ -215,28 +202,23 @@ Result aptInit(void)
|
|||||||
aptEventHandlerThread = threadCreate(aptEventHandler, 0x0, APT_HANDLER_STACKSIZE, 0x31, -2, true);
|
aptEventHandlerThread = threadCreate(aptEventHandler, 0x0, APT_HANDLER_STACKSIZE, 0x31, -2, true);
|
||||||
if (!aptEventHandlerThread) goto _fail3;
|
if (!aptEventHandlerThread) goto _fail3;
|
||||||
|
|
||||||
|
// Enable APT
|
||||||
|
aptFlags = FLAG_ALLOWSLEEP;
|
||||||
|
ret = APT_Enable(attr);
|
||||||
|
if (R_FAILED(ret)) goto _fail3;
|
||||||
|
|
||||||
// Get information about ourselves
|
// Get information about ourselves
|
||||||
APT_GetAppletInfo(envGetAptAppId(), &aptChainloadTid, &aptChainloadMediatype, NULL, NULL, NULL);
|
APT_GetAppletInfo(envGetAptAppId(), &aptChainloadTid, &aptChainloadMediatype, NULL, NULL, NULL);
|
||||||
|
|
||||||
// Special handling for aptReinit (aka hax)
|
|
||||||
APT_Transition transition = TR_ENABLE;
|
|
||||||
if (aptIsReinit())
|
|
||||||
{
|
|
||||||
transition = TR_JUMPTOMENU;
|
|
||||||
|
|
||||||
// Clear out any pending parameters
|
|
||||||
bool success = false;
|
|
||||||
do
|
|
||||||
ret = APT_CancelParameter(APPID_NONE, envGetAptAppId(), &success);
|
|
||||||
while (success);
|
|
||||||
|
|
||||||
// APT thinks the application is suspended, so we need to tell it to unsuspend us.
|
|
||||||
APT_PrepareToJumpToApplication(false);
|
|
||||||
APT_JumpToApplication(NULL, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for wakeup
|
// Wait for wakeup
|
||||||
aptWaitForWakeUp(transition);
|
aptWaitForWakeUp(TR_ENABLE);
|
||||||
|
|
||||||
|
// Special handling for aptReinit (aka hax 2.x):
|
||||||
|
// In certain cases when running under hax 2.x, we may receive a spurious
|
||||||
|
// second wakeup command. Therefore we must silently drop it in order to
|
||||||
|
// avoid keeping stale commands in APT's internal buffer.
|
||||||
|
if (aptIsReinit())
|
||||||
|
aptFlags |= FLAG_SPURIOUS;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_fail3:
|
_fail3:
|
||||||
@ -336,10 +318,7 @@ void aptExit(void)
|
|||||||
closeAptLock = false;
|
closeAptLock = false;
|
||||||
srvInit(); // Keep srv initialized
|
srvInit(); // Keep srv initialized
|
||||||
} else
|
} else
|
||||||
{
|
|
||||||
APT_Finalize(envGetAptAppId());
|
APT_Finalize(envGetAptAppId());
|
||||||
aptClearParamQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
aptEventHandlerThreadQuit = true;
|
aptEventHandlerThreadQuit = true;
|
||||||
svcSignalEvent(aptEvents[0]);
|
svcSignalEvent(aptEvents[0]);
|
||||||
@ -358,22 +337,59 @@ void aptEventHandler(void *arg)
|
|||||||
while (!aptEventHandlerThreadQuit)
|
while (!aptEventHandlerThreadQuit)
|
||||||
{
|
{
|
||||||
s32 id = 0;
|
s32 id = 0;
|
||||||
svcWaitSynchronizationN(&id, aptEvents, 1, 0, U64_MAX);
|
svcWaitSynchronizationN(&id, aptEvents, 2, 0, U64_MAX);
|
||||||
|
|
||||||
if (aptEventHandlerThreadQuit)
|
if (aptEventHandlerThreadQuit)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// If the receive event is still signaled, sleep for a bit and retry
|
||||||
|
if (LightEvent_TryWait(&aptReceiveEvent))
|
||||||
|
{
|
||||||
|
_aptDebug(222, 0);
|
||||||
|
svcSleepThread(10000000); // 10ms
|
||||||
|
svcSignalEvent(aptEvents[id]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// This is done by official sw, even though APT events are oneshot...
|
// This is done by official sw, even though APT events are oneshot...
|
||||||
svcClearEvent(aptEvents[id]);
|
svcClearEvent(aptEvents[id]);
|
||||||
|
|
||||||
if (id != 0)
|
// Relay receive events to our light event
|
||||||
|
if (id == 1)
|
||||||
|
{
|
||||||
|
NS_APPID sender;
|
||||||
|
APT_Command cmd;
|
||||||
|
Result res = APT_GlanceParameter(envGetAptAppId(), aptParameters, sizeof(aptParameters), &sender, &cmd, NULL, NULL);
|
||||||
|
if (R_FAILED(res))
|
||||||
|
continue; // Official sw panics here - we instead swallow the (non-)event.
|
||||||
|
|
||||||
|
_aptDebug(2, cmd); _aptDebug(22, sender);
|
||||||
|
|
||||||
|
// NOTE: Official software handles the following parameter types here:
|
||||||
|
// - APTCMD_MESSAGE (cancelled afterwards) (we handle it in aptReceiveParameter instead)
|
||||||
|
// - APTCMD_REQUEST (cancelled afterwards) (only sent to and handled by libapplets?)
|
||||||
|
// - APTCMD_DSP_SLEEP (*NOT* cancelled afterwards)
|
||||||
|
// - APTCMD_DSP_WAKEUP (*NOT* cancelled afterwards)
|
||||||
|
|
||||||
|
// We will instead only handle spurious APTCMD_WAKEUP_PAUSE parameters
|
||||||
|
// (see aptInit for more details on the hax 2.x spurious wakeup problem)
|
||||||
|
if (cmd == APTCMD_WAKEUP_PAUSE && (aptFlags & FLAG_SPURIOUS))
|
||||||
|
{
|
||||||
|
APT_CancelParameter(APPID_NONE, envGetAptAppId(), NULL);
|
||||||
|
aptFlags &= ~FLAG_SPURIOUS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LightEvent_Signal(&aptReceiveEvent);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
APT_Signal signal;
|
APT_Signal signal;
|
||||||
Result res = APT_InquireNotification(envGetAptAppId(), &signal);
|
Result res = APT_InquireNotification(envGetAptAppId(), &signal);
|
||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
_aptDebug(1, signal);
|
||||||
switch (signal)
|
switch (signal)
|
||||||
{
|
{
|
||||||
case APTSIGNAL_HOMEBUTTON:
|
case APTSIGNAL_HOMEBUTTON:
|
||||||
@ -383,15 +399,38 @@ void aptEventHandler(void *arg)
|
|||||||
if (!aptHomeButtonState) aptHomeButtonState = 2;
|
if (!aptHomeButtonState) aptHomeButtonState = 2;
|
||||||
break;
|
break;
|
||||||
case APTSIGNAL_SLEEP_QUERY:
|
case APTSIGNAL_SLEEP_QUERY:
|
||||||
APT_ReplySleepQuery(envGetAptAppId(), aptIsSleepAllowed() ? APTREPLY_ACCEPT : APTREPLY_REJECT);
|
{
|
||||||
|
APT_QueryReply reply;
|
||||||
|
if (aptFlags & (FLAG_ORDERTOCLOSE|FLAG_WKUPBYCANCEL))
|
||||||
|
// Reject sleep if we are expected to close
|
||||||
|
reply = APTREPLY_REJECT;
|
||||||
|
else if (aptFlags & FLAG_ACTIVE)
|
||||||
|
// Accept sleep based on user setting if we are active
|
||||||
|
reply = aptIsSleepAllowed() ? APTREPLY_ACCEPT : APTREPLY_REJECT;
|
||||||
|
else
|
||||||
|
// Accept sleep if we are inactive regardless of user setting
|
||||||
|
reply = APTREPLY_ACCEPT;
|
||||||
|
|
||||||
|
_aptDebug(10, aptFlags);
|
||||||
|
_aptDebug(11, reply);
|
||||||
|
APT_ReplySleepQuery(envGetAptAppId(), reply);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case APTSIGNAL_SLEEP_CANCEL:
|
case APTSIGNAL_SLEEP_CANCEL:
|
||||||
// Do something maybe?
|
if (aptFlags & FLAG_ACTIVE)
|
||||||
|
aptFlags &= ~FLAG_WANTSTOSLEEP;
|
||||||
break;
|
break;
|
||||||
case APTSIGNAL_SLEEP_ENTER:
|
case APTSIGNAL_SLEEP_ENTER:
|
||||||
aptFlags |= FLAG_WANTSTOSLEEP;
|
_aptDebug(10, aptFlags);
|
||||||
|
if (aptFlags & FLAG_ACTIVE)
|
||||||
|
aptFlags |= FLAG_WANTSTOSLEEP;
|
||||||
|
else
|
||||||
|
// Since we are not active, this must be handled here.
|
||||||
|
APT_ReplySleepNotificationComplete(envGetAptAppId());
|
||||||
break;
|
break;
|
||||||
case APTSIGNAL_SLEEP_WAKEUP:
|
case APTSIGNAL_SLEEP_WAKEUP:
|
||||||
|
if (!(aptFlags & FLAG_ACTIVE))
|
||||||
|
break;
|
||||||
if (aptFlags & FLAG_SLEEPING)
|
if (aptFlags & FLAG_SLEEPING)
|
||||||
LightEvent_Signal(&aptSleepEvent);
|
LightEvent_Signal(&aptSleepEvent);
|
||||||
else
|
else
|
||||||
@ -407,7 +446,16 @@ void aptEventHandler(void *arg)
|
|||||||
aptFlags &= ~FLAG_POWERBUTTON;
|
aptFlags &= ~FLAG_POWERBUTTON;
|
||||||
break;
|
break;
|
||||||
case APTSIGNAL_TRY_SLEEP:
|
case APTSIGNAL_TRY_SLEEP:
|
||||||
|
{
|
||||||
|
// Official software performs this APT_SleepSystem command here, although
|
||||||
|
// its purpose is unclear. For completeness' sake, we'll do it as well.
|
||||||
|
static const struct PtmWakeEvents s_sleepWakeEvents = {
|
||||||
|
.pdn_wake_events = 0,
|
||||||
|
.mcu_interupt_mask = BIT(6),
|
||||||
|
};
|
||||||
|
APT_SleepSystem(&s_sleepWakeEvents);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case APTSIGNAL_ORDERTOCLOSE:
|
case APTSIGNAL_ORDERTOCLOSE:
|
||||||
aptFlags |= FLAG_ORDERTOCLOSE;
|
aptFlags |= FLAG_ORDERTOCLOSE;
|
||||||
break;
|
break;
|
||||||
@ -423,8 +471,8 @@ static Result aptReceiveParameter(APT_Command* cmd, size_t* actualSize, Handle*
|
|||||||
size_t temp_actualSize;
|
size_t temp_actualSize;
|
||||||
if (!actualSize) actualSize = &temp_actualSize;
|
if (!actualSize) actualSize = &temp_actualSize;
|
||||||
|
|
||||||
svcWaitSynchronization(aptEvents[1], U64_MAX);
|
LightEvent_Wait(&aptReceiveEvent);
|
||||||
svcClearEvent(aptEvents[1]);
|
LightEvent_Clear(&aptReceiveEvent);
|
||||||
Result res = APT_ReceiveParameter(envGetAptAppId(), aptParameters, sizeof(aptParameters), &sender, cmd, actualSize, handle);
|
Result res = APT_ReceiveParameter(envGetAptAppId(), aptParameters, sizeof(aptParameters), &sender, cmd, actualSize, handle);
|
||||||
if (R_SUCCEEDED(res) && *cmd == APTCMD_MESSAGE && aptMessageFunc)
|
if (R_SUCCEEDED(res) && *cmd == APTCMD_MESSAGE && aptMessageFunc)
|
||||||
aptMessageFunc(aptMessageFuncData, sender, aptParameters, *actualSize);
|
aptMessageFunc(aptMessageFuncData, sender, aptParameters, *actualSize);
|
||||||
@ -524,7 +572,7 @@ static void aptProcessJumpToMenu(void)
|
|||||||
bool sleep = aptIsSleepAllowed();
|
bool sleep = aptIsSleepAllowed();
|
||||||
aptSetSleepAllowed(false);
|
aptSetSleepAllowed(false);
|
||||||
|
|
||||||
aptClearParamQueue();
|
aptFlags &= ~FLAG_SPURIOUS; // If we haven't received a spurious wakeup by now, we probably never will (see aptInit)
|
||||||
APT_PrepareToJumpToHomeMenu();
|
APT_PrepareToJumpToHomeMenu();
|
||||||
aptScreenTransfer(aptGetMenuAppID(), true);
|
aptScreenTransfer(aptGetMenuAppID(), true);
|
||||||
|
|
||||||
@ -563,6 +611,7 @@ bool aptMainLoop(void)
|
|||||||
aptRecentHomeButtonState = aptHomeButtonState;
|
aptRecentHomeButtonState = aptHomeButtonState;
|
||||||
aptHomeButtonState = 0;
|
aptHomeButtonState = 0;
|
||||||
APT_UnlockTransition(0x01);
|
APT_UnlockTransition(0x01);
|
||||||
|
APT_SleepIfShellClosed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,7 +660,7 @@ bool aptLaunchLibraryApplet(NS_APPID appId, void* buf, size_t bufsize, Handle ha
|
|||||||
bool sleep = aptIsSleepAllowed();
|
bool sleep = aptIsSleepAllowed();
|
||||||
|
|
||||||
aptSetSleepAllowed(false);
|
aptSetSleepAllowed(false);
|
||||||
aptClearParamQueue();
|
aptFlags &= ~FLAG_SPURIOUS; // If we haven't received a spurious wakeup by now, we probably never will (see aptInit)
|
||||||
APT_PrepareToStartLibraryApplet(appId);
|
APT_PrepareToStartLibraryApplet(appId);
|
||||||
aptSetSleepAllowed(sleep);
|
aptSetSleepAllowed(sleep);
|
||||||
|
|
||||||
@ -769,10 +818,7 @@ Result APT_InquireNotification(u32 appID, APT_Signal* signalType)
|
|||||||
|
|
||||||
Result ret = aptSendCommand(cmdbuf);
|
Result ret = aptSendCommand(cmdbuf);
|
||||||
if (R_SUCCEEDED(ret))
|
if (R_SUCCEEDED(ret))
|
||||||
{
|
|
||||||
_aptDebug(1, cmdbuf[2]);
|
|
||||||
*signalType=cmdbuf[2];
|
*signalType=cmdbuf[2];
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -929,7 +975,6 @@ Result APT_ReceiveParameter(NS_APPID appID, void* buffer, size_t bufferSize, NS_
|
|||||||
|
|
||||||
if (R_SUCCEEDED(ret))
|
if (R_SUCCEEDED(ret))
|
||||||
{
|
{
|
||||||
_aptDebug(2, cmdbuf[3]);
|
|
||||||
if (sender) *sender =cmdbuf[2];
|
if (sender) *sender =cmdbuf[2];
|
||||||
if (command) *command =cmdbuf[3];
|
if (command) *command =cmdbuf[3];
|
||||||
if (actualSize) *actualSize=cmdbuf[4];
|
if (actualSize) *actualSize=cmdbuf[4];
|
||||||
|
Loading…
Reference in New Issue
Block a user