Refactor DSP<->APT interaction, see details:
- DSP wrapper is now in charge of handling sleep/awake/cancel events - Added DSP hook mechanism (similar to APT hook) - The DSP component now gets automatically unloaded/reloaded as needed - NDSP now uses DSP hook instead of APT hook to manage lifetime - Moved sleep/wakeup component management logic into NDSP - APT now calls into DSP wrapper in order to arbitrate access to the DSP - Launching libapplets no longer relinquishes DSP rights - this means music can now be played in the background during libapplet activity
This commit is contained in:
parent
b559d93eda
commit
b93e7f19bf
@ -13,12 +13,23 @@ typedef enum
|
||||
DSP_INTERRUPT_PIPE = 2 ///< Pipe interrupt.
|
||||
} DSP_InterruptType;
|
||||
|
||||
/// DSP pipe directions.
|
||||
/// DSP hook types.
|
||||
typedef enum
|
||||
{
|
||||
DSP_PIPE_INPUT = 0, ///< DSP to ARM
|
||||
DSP_PIPE_OUTPUT = 1 ///< ARM to DSP
|
||||
} DSP_PipeDirection;
|
||||
DSPHOOK_ONSLEEP = 0, ///< DSP is going to sleep.
|
||||
DSPHOOK_ONWAKEUP = 1, ///< DSP is waking up.
|
||||
DSPHOOK_ONCANCEL = 2, ///< DSP was sleeping and the app was cancelled.
|
||||
} DSP_HookType;
|
||||
|
||||
/// DSP hook function.
|
||||
typedef void (* dspHookFn)(DSP_HookType hook);
|
||||
|
||||
/// DSP hook cookie.
|
||||
typedef struct tag_dspHookCookie
|
||||
{
|
||||
struct tag_dspHookCookie* next; ///< Next cookie.
|
||||
dspHookFn callback; ///< Hook callback.
|
||||
} dspHookCookie;
|
||||
|
||||
/**
|
||||
* @brief Initializes the dsp service.
|
||||
@ -35,6 +46,22 @@ Result dspInit(void);
|
||||
*/
|
||||
void dspExit(void);
|
||||
|
||||
/// Returns true if a component is loaded, false otherwise.
|
||||
bool dspIsComponentLoaded(void);
|
||||
|
||||
/**
|
||||
* @brief Sets up a DSP status hook.
|
||||
* @param cookie Hook cookie to use.
|
||||
* @param callback Function to call when DSP's status changes.
|
||||
*/
|
||||
void dspHook(dspHookCookie* cookie, dspHookFn callback);
|
||||
|
||||
/**
|
||||
* @brief Removes a DSP status hook.
|
||||
* @param cookie Hook cookie to remove.
|
||||
*/
|
||||
void dspUnhook(dspHookCookie* cookie);
|
||||
|
||||
/**
|
||||
* @brief Checks if a headphone is inserted.
|
||||
* @param is_inserted Pointer to output the insertion status to.
|
||||
|
@ -9,7 +9,7 @@
|
||||
u16 ndspFrameId, ndspBufferCurId, ndspBufferId;
|
||||
void* ndspVars[16][2];
|
||||
|
||||
static bool bComponentLoaded = false, bDspReady = false, bSleeping = false, bActuallySleeping = false, bNeedsSync = false;
|
||||
static bool bDspReady = false, bSleeping = false, bActuallySleeping = false, bNeedsSync = false;
|
||||
static u32 droppedFrames, frameCount;
|
||||
|
||||
static const void* componentBin;
|
||||
@ -17,7 +17,7 @@ static u32 componentSize;
|
||||
static u16 componentProgMask, componentDataMask;
|
||||
static bool componentFree;
|
||||
|
||||
static aptHookCookie aptCookie;
|
||||
static dspHookCookie ndspHookCookie;
|
||||
|
||||
static Handle irqEvent, dspSem;
|
||||
static LightEvent sleepEvent;
|
||||
@ -28,12 +28,6 @@ static u8 dspVar5Backup[0x1080];
|
||||
static volatile bool ndspThreadRun;
|
||||
static Thread ndspThread;
|
||||
|
||||
static Result ndspLoadComponent(void)
|
||||
{
|
||||
if (!componentBin) return 1;
|
||||
return DSP_LoadComponent(componentBin, componentSize, componentProgMask, componentDataMask, &bComponentLoaded);
|
||||
}
|
||||
|
||||
static inline void ndspWaitForIrq(void)
|
||||
{
|
||||
LightLock_Lock(&ndspMutex);
|
||||
@ -209,9 +203,6 @@ static Result ndspInitialize(bool resume)
|
||||
{
|
||||
Result rc;
|
||||
|
||||
rc = ndspLoadComponent();
|
||||
if (R_FAILED(rc)) return rc;
|
||||
|
||||
rc = svcCreateEvent(&irqEvent, RESET_STICKY);
|
||||
if (R_FAILED(rc)) goto _fail1;
|
||||
|
||||
@ -266,7 +257,6 @@ _fail3:
|
||||
_fail2:
|
||||
svcCloseHandle(irqEvent);
|
||||
_fail1:
|
||||
DSP_UnloadComponent();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -292,20 +282,20 @@ static void ndspFinalize(bool suspend)
|
||||
DSP_RegisterInterruptEvents(0, 2, 2);
|
||||
svcCloseHandle(irqEvent);
|
||||
svcCloseHandle(dspSem);
|
||||
DSP_UnloadComponent();
|
||||
bComponentLoaded = false;
|
||||
|
||||
bDspReady = false;
|
||||
LightLock_Unlock(&ndspMutex);
|
||||
}
|
||||
|
||||
static void ndspAptHook(APT_HookType hook, void* param)
|
||||
static void ndspHookCallback(DSP_HookType hook)
|
||||
{
|
||||
switch (hook)
|
||||
{
|
||||
case APTHOOK_ONRESTORE:
|
||||
case APTHOOK_ONWAKEUP:
|
||||
case DSPHOOK_ONWAKEUP:
|
||||
bSleeping = false;
|
||||
ndspInitialize(true);
|
||||
Result res = ndspInitialize(true);
|
||||
if (R_FAILED(res))
|
||||
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
||||
if (bActuallySleeping)
|
||||
{
|
||||
bActuallySleeping = false;
|
||||
@ -313,8 +303,7 @@ static void ndspAptHook(APT_HookType hook, void* param)
|
||||
}
|
||||
break;
|
||||
|
||||
case APTHOOK_ONSUSPEND:
|
||||
case APTHOOK_ONSLEEP:
|
||||
case DSPHOOK_ONSLEEP:
|
||||
bSleeping = true;
|
||||
ndspFinalize(true);
|
||||
break;
|
||||
@ -481,6 +470,9 @@ Result ndspInit(void)
|
||||
rc = dspInit();
|
||||
if (R_FAILED(rc)) goto _fail1;
|
||||
|
||||
rc = DSP_LoadComponent(componentBin, componentSize, componentProgMask, componentDataMask, NULL);
|
||||
if (R_FAILED(rc)) goto _fail2;
|
||||
|
||||
rc = ndspInitialize(false);
|
||||
if (R_FAILED(rc)) goto _fail2;
|
||||
|
||||
@ -489,7 +481,7 @@ Result ndspInit(void)
|
||||
ndspThread = threadCreate(ndspThreadMain, 0x0, NDSP_THREAD_STACK_SIZE, 0x18, -2, true);
|
||||
if (!ndspThread) goto _fail3;
|
||||
|
||||
aptHook(&aptCookie, ndspAptHook, NULL);
|
||||
dspHook(&ndspHookCookie, ndspHookCallback);
|
||||
return 0;
|
||||
|
||||
_fail3:
|
||||
@ -518,7 +510,7 @@ void ndspExit(void)
|
||||
LightEvent_Signal(&sleepEvent);
|
||||
}
|
||||
threadJoin(ndspThread, U64_MAX);
|
||||
aptUnhook(&aptCookie);
|
||||
dspUnhook(&ndspHookCookie);
|
||||
if (!bSleeping)
|
||||
ndspFinalize(false);
|
||||
bSleeping = false;
|
||||
|
@ -55,6 +55,7 @@ enum
|
||||
FLAG_CANCELLED = BIT(10),
|
||||
|
||||
// Miscellaneous
|
||||
FLAG_DSPWAKEUP = BIT(29),
|
||||
FLAG_CHAINLOAD = BIT(30),
|
||||
FLAG_SPURIOUS = BIT(31),
|
||||
};
|
||||
@ -87,6 +88,11 @@ __attribute__((weak)) void _aptDebug(int a, int b) { }
|
||||
#define _aptDebug(a,b) ((void)0)
|
||||
#endif
|
||||
|
||||
// APT<->DSP interaction functions (stubbed when not using DSP)
|
||||
__attribute__((weak)) bool aptDspSleep(void) { return false; }
|
||||
__attribute__((weak)) void aptDspWakeup(void) { }
|
||||
__attribute__((weak)) void aptDspCancel(void) { }
|
||||
|
||||
static void aptCallHook(APT_HookType hookType)
|
||||
{
|
||||
aptHookCookie* c;
|
||||
@ -448,16 +454,34 @@ void aptEventHandler(void *arg)
|
||||
// - 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))
|
||||
// We will handle the following:
|
||||
switch (cmd)
|
||||
{
|
||||
APT_CancelParameter(APPID_NONE, envGetAptAppId(), NULL);
|
||||
aptFlags &= ~FLAG_SPURIOUS;
|
||||
continue;
|
||||
case APTCMD_DSP_SLEEP:
|
||||
// Handle DSP sleep requests
|
||||
aptDspSleep();
|
||||
break;
|
||||
case APTCMD_DSP_WAKEUP:
|
||||
// Handle DSP wakeup requests
|
||||
aptFlags &= ~FLAG_DSPWAKEUP;
|
||||
aptDspWakeup();
|
||||
break;
|
||||
case APTCMD_WAKEUP_PAUSE:
|
||||
// Handle spurious APTCMD_WAKEUP_PAUSE parameters
|
||||
// (see aptInit for more details on the hax 2.x spurious wakeup problem)
|
||||
if (aptFlags & FLAG_SPURIOUS)
|
||||
{
|
||||
APT_CancelParameter(APPID_NONE, envGetAptAppId(), NULL);
|
||||
aptFlags &= ~FLAG_SPURIOUS;
|
||||
break;
|
||||
}
|
||||
// Fallthrough otherwise
|
||||
default:
|
||||
// Others not accounted for -> pass it on to aptReceiveParameter
|
||||
LightEvent_Signal(&aptReceiveEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
LightEvent_Signal(&aptReceiveEvent);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -505,6 +529,8 @@ void aptEventHandler(void *arg)
|
||||
break;
|
||||
case APTSIGNAL_SLEEP_ENTER:
|
||||
_aptDebug(10, aptFlags);
|
||||
if (aptDspSleep())
|
||||
aptFlags |= FLAG_DSPWAKEUP;
|
||||
if (aptIsActive())
|
||||
aptFlags |= FLAG_SHOULDSLEEP;
|
||||
else
|
||||
@ -512,6 +538,11 @@ void aptEventHandler(void *arg)
|
||||
APT_ReplySleepNotificationComplete(envGetAptAppId());
|
||||
break;
|
||||
case APTSIGNAL_SLEEP_WAKEUP:
|
||||
if (aptFlags & FLAG_DSPWAKEUP)
|
||||
{
|
||||
aptFlags &= ~FLAG_DSPWAKEUP;
|
||||
aptDspWakeup();
|
||||
}
|
||||
if (!aptIsActive())
|
||||
break;
|
||||
if (aptFlags & FLAG_SLEEPING)
|
||||
@ -589,8 +620,16 @@ APT_Command aptWaitForWakeUp(APT_Transition transition)
|
||||
aptCallHook(APTHOOK_ONRESTORE);
|
||||
}
|
||||
|
||||
if (cmd == APTCMD_WAKEUP_CANCEL)
|
||||
aptFlags |= FLAG_CANCELLED;
|
||||
if (cmd == APTCMD_WAKEUP_CANCEL || cmd == APTCMD_WAKEUP_CANCELALL)
|
||||
{
|
||||
aptDspCancel();
|
||||
if (cmd == APTCMD_WAKEUP_CANCEL) // for some reason, not for CANCELALL... is this a bug in official sw?
|
||||
aptFlags |= FLAG_CANCELLED;
|
||||
} else if (cmd != APTCMD_WAKEUP_LAUNCHAPP)
|
||||
{
|
||||
aptFlags &= ~FLAG_DSPWAKEUP;
|
||||
aptDspWakeup();
|
||||
}
|
||||
|
||||
if (cmd != APTCMD_WAKEUP_JUMPTOHOME)
|
||||
{
|
||||
@ -732,6 +771,7 @@ void aptJumpToHomeMenu(void)
|
||||
|
||||
GSPGPU_SaveVramSysArea();
|
||||
aptScreenTransfer(aptGetMenuAppID(), true);
|
||||
aptDspSleep();
|
||||
GSPGPU_ReleaseRight();
|
||||
|
||||
APT_JumpToHomeMenu(NULL, 0, 0);
|
||||
|
@ -9,6 +9,20 @@
|
||||
static Handle dspHandle;
|
||||
static int dspRefCount;
|
||||
|
||||
static dspHookCookie dspFirstHook;
|
||||
static bool dspComponentLoaded, dspSleeping;
|
||||
|
||||
static const void* dspSavedCompBin;
|
||||
static u32 dspSavedCompSize;
|
||||
static u16 dspSavedCompProgMask, dspSavedCompDataMask;
|
||||
|
||||
static void dspCallHook(DSP_HookType hookType)
|
||||
{
|
||||
dspHookCookie* c;
|
||||
for (c = &dspFirstHook; c && c->callback; c = c->next)
|
||||
c->callback(hookType);
|
||||
}
|
||||
|
||||
Result dspInit(void)
|
||||
{
|
||||
Result ret = 0;
|
||||
@ -16,18 +30,91 @@ Result dspInit(void)
|
||||
if (AtomicPostIncrement(&dspRefCount)) return 0;
|
||||
|
||||
ret = srvGetServiceHandle(&dspHandle, "dsp::DSP");
|
||||
if (R_SUCCEEDED(ret)) DSP_UnloadComponent();
|
||||
else AtomicDecrement(&dspRefCount);
|
||||
if (R_FAILED(ret))
|
||||
{
|
||||
AtomicDecrement(&dspRefCount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
// Force unload component (if exists)
|
||||
dspComponentLoaded = true;
|
||||
DSP_UnloadComponent();
|
||||
|
||||
dspSleeping = false;
|
||||
dspSavedCompBin = NULL;
|
||||
dspSavedCompSize = 0;
|
||||
dspSavedCompProgMask = 0;
|
||||
dspSavedCompDataMask = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dspExit(void)
|
||||
{
|
||||
if (AtomicDecrement(&dspRefCount)) return;
|
||||
DSP_UnloadComponent();
|
||||
svcCloseHandle(dspHandle);
|
||||
}
|
||||
|
||||
bool dspIsComponentLoaded(void)
|
||||
{
|
||||
return dspComponentLoaded;
|
||||
}
|
||||
|
||||
void dspHook(dspHookCookie* cookie, dspHookFn callback)
|
||||
{
|
||||
if (!callback) return;
|
||||
|
||||
dspHookCookie* hook = &dspFirstHook;
|
||||
*cookie = *hook; // Structure copy.
|
||||
hook->next = cookie;
|
||||
hook->callback = callback;
|
||||
}
|
||||
|
||||
void dspUnhook(dspHookCookie* cookie)
|
||||
{
|
||||
dspHookCookie* hook;
|
||||
for (hook = &dspFirstHook; hook; hook = hook->next)
|
||||
{
|
||||
if (hook->next == cookie)
|
||||
{
|
||||
*hook = *cookie; // Structure copy.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool aptDspSleep(void)
|
||||
{
|
||||
if (!dspComponentLoaded || dspSleeping)
|
||||
return false;
|
||||
|
||||
dspCallHook(DSPHOOK_ONSLEEP);
|
||||
DSP_UnloadComponent();
|
||||
dspSleeping = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void aptDspWakeup(void)
|
||||
{
|
||||
if (!dspSleeping)
|
||||
return;
|
||||
|
||||
Result ret = DSP_LoadComponent(dspSavedCompBin, dspSavedCompSize, dspSavedCompProgMask, dspSavedCompDataMask, NULL);
|
||||
if (R_FAILED(ret))
|
||||
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
|
||||
|
||||
dspCallHook(DSPHOOK_ONWAKEUP);
|
||||
dspSleeping = false;
|
||||
}
|
||||
|
||||
void aptDspCancel(void)
|
||||
{
|
||||
if (!dspSleeping)
|
||||
return;
|
||||
|
||||
dspCallHook(DSPHOOK_ONCANCEL);
|
||||
}
|
||||
|
||||
Result DSP_GetHeadphoneStatus(bool* is_inserted)
|
||||
{
|
||||
Result ret = 0;
|
||||
@ -96,6 +183,17 @@ Result DSP_GetSemaphoreHandle(Handle* semaphore)
|
||||
|
||||
Result DSP_LoadComponent(const void* component, u32 size, u16 prog_mask, u16 data_mask, bool* is_loaded)
|
||||
{
|
||||
if (dspComponentLoaded)
|
||||
{
|
||||
if (is_loaded) *is_loaded = dspComponentLoaded;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dspSavedCompBin = component;
|
||||
dspSavedCompSize = size;
|
||||
dspSavedCompProgMask = prog_mask;
|
||||
dspSavedCompDataMask = data_mask;
|
||||
|
||||
Result ret = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x11,3,2);
|
||||
@ -105,12 +203,18 @@ Result DSP_LoadComponent(const void* component, u32 size, u16 prog_mask, u16 dat
|
||||
cmdbuf[4] = IPC_Desc_Buffer(size,IPC_BUFFER_R);
|
||||
cmdbuf[5] = (u32) component;
|
||||
if (R_FAILED(ret = svcSendSyncRequest(dspHandle))) return ret;
|
||||
*is_loaded = cmdbuf[2] & 0xFF;
|
||||
dspComponentLoaded = cmdbuf[2] & 0xFF;
|
||||
if (is_loaded) *is_loaded = dspComponentLoaded;
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result DSP_UnloadComponent(void)
|
||||
{
|
||||
if (!dspComponentLoaded)
|
||||
return 0;
|
||||
|
||||
dspComponentLoaded = false;
|
||||
|
||||
Result ret = 0;
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(0x12,0,0);
|
||||
|
Loading…
Reference in New Issue
Block a user