From 1dda414f31aa1c64512e881a0fe08b77694e9653 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 29 Dec 2017 16:15:17 -0500 Subject: [PATCH] Implemented apm. --- nx/include/switch.h | 1 + nx/include/switch/services/apm.h | 7 ++ nx/source/services/apm.c | 144 +++++++++++++++++++++++++++++++ nx/source/services/applet.c | 13 +++ 4 files changed, 165 insertions(+) create mode 100644 nx/include/switch/services/apm.h create mode 100644 nx/source/services/apm.c diff --git a/nx/include/switch.h b/nx/include/switch.h index 3e0301ef..deab6a51 100644 --- a/nx/include/switch.h +++ b/nx/include/switch.h @@ -26,6 +26,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/nx/include/switch/services/apm.h b/nx/include/switch/services/apm.h new file mode 100644 index 00000000..b8182daa --- /dev/null +++ b/nx/include/switch/services/apm.h @@ -0,0 +1,7 @@ +/// These are used internally by applet. + +Result apmInitialize(void); +void apmExit(void); + +Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration); +Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration); diff --git a/nx/source/services/apm.c b/nx/source/services/apm.c new file mode 100644 index 00000000..178abfcb --- /dev/null +++ b/nx/source/services/apm.c @@ -0,0 +1,144 @@ +#include +#include + +static Handle g_apmServiceSession = INVALID_HANDLE; +static Handle g_apmISession = INVALID_HANDLE; + +static Result _apmGetSession(Handle sessionhandle, Handle* handle_out, u64 cmd_id); + +Result apmInitialize(void) { + if (g_apmServiceSession != INVALID_HANDLE) return 0; + + Result rc = 0; + + rc = smGetService(&g_apmServiceSession, "apm:p"); + if (R_FAILED(rc)) rc = smGetService(&g_apmServiceSession, "apm"); + + if (R_SUCCEEDED(rc)) rc = _apmGetSession(g_apmServiceSession, &g_apmISession, 0);//OpenSession. Official sw doesn't open this until using commands which need it, when it wasn't already opened. + + if (R_FAILED(rc)) apmExit(); + + return rc; +} + +void apmExit(void) +{ + if (g_apmServiceSession == INVALID_HANDLE) return; + + if (g_apmServiceSession != INVALID_HANDLE) { + svcCloseHandle(g_apmServiceSession); + g_apmServiceSession = INVALID_HANDLE; + } + + if (g_apmISession != INVALID_HANDLE) { + svcCloseHandle(g_apmISession); + g_apmISession = INVALID_HANDLE; + } +} + +static Result _apmGetSession(Handle sessionhandle, Handle* handle_out, u64 cmd_id) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + + Result rc = ipcDispatch(sessionhandle); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + *handle_out = r.Handles[0]; + } + } + + return rc; +} + +Result apmSetPerformanceConfiguration(u32 PerformanceMode, u32 PerformanceConfiguration) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 PerformanceMode; + u32 PerformanceConfiguration; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + raw->PerformanceMode = PerformanceMode; + raw->PerformanceConfiguration = PerformanceConfiguration; + + Result rc = ipcDispatch(g_apmISession); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result apmGetPerformanceConfiguration(u32 PerformanceMode, u32 *PerformanceConfiguration) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 PerformanceMode; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 1; + raw->PerformanceMode = PerformanceMode; + + Result rc = ipcDispatch(g_apmISession); + + if (R_SUCCEEDED(rc)) { + IpcCommandResponse r; + ipcParseResponse(&r); + + struct { + u64 magic; + u64 result; + u32 PerformanceConfiguration; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc) && PerformanceConfiguration) *PerformanceConfiguration = resp->PerformanceConfiguration; + } + + return rc; +} + diff --git a/nx/source/services/applet.c b/nx/source/services/applet.c index 4bb40140..3e07a53d 100644 --- a/nx/source/services/applet.c +++ b/nx/source/services/applet.c @@ -4,6 +4,7 @@ __attribute__((weak)) u32 __nx_applet_type = APPLET_TYPE_Default; __attribute__((weak)) bool __nx_applet_auto_notifyrunning = true; __attribute__((weak)) u8 __nx_applet_AppletAttribute[0x80]; +__attribute__((weak)) u32 __nx_applet_PerformanceConfiguration[2] = {/*0x92220008*//*0x20004*//*0x92220007*/0, 0}; static Handle g_appletServiceSession = INVALID_HANDLE; static Handle g_appletProxySession = INVALID_HANDLE; @@ -57,6 +58,7 @@ Result appletInitialize(void) { Result rc = 0; Handle prochandle = CUR_PROCESS_HANDLE; s32 tmpindex=0; + u32 i; u32 msg=0; if (__nx_applet_type==APPLET_TYPE_None) return 0; @@ -153,6 +155,15 @@ Result appletInitialize(void) { if (R_SUCCEEDED(rc)) rc = _appletSetOperationModeChangedNotification(1); if (R_SUCCEEDED(rc)) rc = _appletSetPerformanceModeChangedNotification(1); + if (R_SUCCEEDED(rc)) rc = apmInitialize(); + + if (R_SUCCEEDED(rc)) {//Official apps aren't known to use apmSetPerformanceConfiguration with mode=1. + for (i=0; i<2; i++) {//This is broken with the regular "apm" service. + if (__nx_applet_PerformanceConfiguration[i]) rc = apmSetPerformanceConfiguration(i, __nx_applet_PerformanceConfiguration[i]); + if (R_FAILED(rc)) break; + } + } + if (R_FAILED(rc)) appletExit(); return rc; @@ -162,6 +173,8 @@ void appletExit(void) { if (g_appletServiceSession == INVALID_HANDLE) return; + apmExit(); + if (g_appletMessageEventHandle != INVALID_HANDLE) { svcCloseHandle(g_appletMessageEventHandle); g_appletMessageEventHandle = INVALID_HANDLE;