From 49e4e31fccaf29e8d6e42631f95e5c9d6d2c8023 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Fri, 26 Oct 2018 13:07:10 -0400 Subject: [PATCH] Added support for psm StateChangeEvent. Added psmGetBatteryVoltageState. Code style adjustments, use serviceIpc*, etc. --- nx/include/switch/services/psm.h | 19 ++- nx/source/services/psm.c | 240 +++++++++++++++++++++++++++---- 2 files changed, 231 insertions(+), 28 deletions(-) diff --git a/nx/include/switch/services/psm.h b/nx/include/switch/services/psm.h index ed45d775..942e98c0 100644 --- a/nx/include/switch/services/psm.h +++ b/nx/include/switch/services/psm.h @@ -1,7 +1,7 @@ /** * @file psm.h * @brief PSM service IPC wrapper. - * @author XorTroll + * @author XorTroll, endrift, and yellows8 * @copyright libnx Authors */ #pragma once @@ -18,3 +18,20 @@ void psmExit(void); Result psmGetBatteryChargePercentage(u32 *out); Result psmGetChargerType(ChargerType *out); +Result psmGetBatteryVoltageState(u32 *out); + +/** + * @brief Wrapper func which handles event setup. + * @note Uses the actual BindStateChangeEvent cmd internally. + * @note The event is not signalled on BatteryChargePercentage changes. + * @param[in] ChargerType Passed to SetChargerTypeChangeEventEnabled. + * @param[in] PowerSupply Passed to SetPowerSupplyChangeEventEnabled. + * @param[in] BatteryVoltage Passed to SetBatteryVoltageStateChangeEventEnabled. + */ +Result psmBindStateChangeEvent(bool ChargerType, bool PowerSupply, bool BatteryVoltage); + +/// Wait on the Event setup by psmBindStateChangeEvent. +Result psmWaitStateChangeEvent(u64 timeout); + +/// Cleanup version of psmBindStateChangeEvent. Called automatically by \ref psmExit and \ref psmBindStateChangeEvent, if already initialized. +Result psmUnbindStateChangeEvent(void); diff --git a/nx/source/services/psm.c b/nx/source/services/psm.c index f3d0a0c2..75df717f 100644 --- a/nx/source/services/psm.c +++ b/nx/source/services/psm.c @@ -3,14 +3,24 @@ #include "arm/atomics.h" #include "kernel/ipc.h" #include "kernel/detect.h" +#include "kernel/event.h" #include "services/psm.h" #include "services/sm.h" static Service g_psmSrv; +static Service g_psmSession; +static Event g_psmStateChangeEvent; +static bool g_psmStateChangeEventInitialized; static u64 g_refCnt; -Result psmInitialize(void) -{ +static Result _psmOpenSession(Service* out); +static Result _psmBindStateChangeEvent(Event* event_out); + +static Result _psmSetChargerTypeChangeEventEnabled(bool flag); +static Result _psmSetPowerSupplyChangeEventEnabled(bool flag); +static Result _psmSetBatteryVoltageStateChangeEventEnabled(bool flag); + +Result psmInitialize(void) { Result rc = 0; atomicIncrement64(&g_refCnt); @@ -18,19 +28,28 @@ Result psmInitialize(void) if (serviceIsActive(&g_psmSrv)) return 0; + g_psmStateChangeEventInitialized = 0; + rc = smGetService(&g_psmSrv, "psm"); + if (R_SUCCEEDED(rc)) { + rc = _psmOpenSession(&g_psmSession); + } + + if (R_FAILED(rc)) psmExit(); + return rc; } -void psmExit(void) -{ - if (atomicDecrement64(&g_refCnt) == 0) +void psmExit(void) { + if (atomicDecrement64(&g_refCnt) == 0) { + if (g_psmStateChangeEventInitialized) psmUnbindStateChangeEvent(); + serviceClose(&g_psmSession); serviceClose(&g_psmSrv); + } } -Result psmGetBatteryChargePercentage(u32 *out) -{ +static Result _psmGetOutU32(u64 cmd_id, u32 *out) { IpcCommand c; ipcInitialize(&c); @@ -39,35 +58,48 @@ Result psmGetBatteryChargePercentage(u32 *out) u64 cmd_id; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; - raw->cmd_id = 0; + raw->cmd_id = cmd_id; Result rc = serviceIpcDispatch(&g_psmSrv); if(R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); - + struct { u64 magic; u64 result; - u32 percentage; - } *resp = r.Raw; - + u32 out; + } *resp; + + serviceIpcParse(&g_psmSrv, &r, sizeof(*resp)); + resp = r.Raw; + rc = resp->result; - + if (R_SUCCEEDED(rc)) { - *out = resp->percentage; + *out = resp->out; } } return rc; } -Result psmGetChargerType(ChargerType *out) -{ +Result psmGetBatteryChargePercentage(u32 *out) { + return _psmGetOutU32(0, out); +} + +Result psmGetChargerType(ChargerType *out) { + return _psmGetOutU32(1, out); +} + +Result psmGetBatteryVoltageState(u32 *out) { + return _psmGetOutU32(12, out); +} + +static Result _psmOpenSession(Service* out) { IpcCommand c; ipcInitialize(&c); @@ -76,29 +108,183 @@ Result psmGetChargerType(ChargerType *out) u64 cmd_id; } *raw; - raw = ipcPrepareHeader(&c, sizeof(*raw)); + raw = serviceIpcPrepareHeader(&g_psmSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 7; + + Result rc = serviceIpcDispatch(&g_psmSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_psmSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) + serviceCreateSubservice(out, &g_psmSrv, &r, 0); + } + + return rc; +} + +Result psmBindStateChangeEvent(bool ChargerType, bool PowerSupply, bool BatteryVoltage) { + Result rc=0; + + if (g_psmStateChangeEventInitialized) { + rc = psmUnbindStateChangeEvent(); + if (R_FAILED(rc)) return rc; + } + + rc = _psmSetChargerTypeChangeEventEnabled(ChargerType); + if (R_FAILED(rc)) return rc; + + rc = _psmSetPowerSupplyChangeEventEnabled(PowerSupply); + if (R_FAILED(rc)) return rc; + + rc = _psmSetBatteryVoltageStateChangeEventEnabled(BatteryVoltage); + if (R_FAILED(rc)) return rc; + + rc = _psmBindStateChangeEvent(&g_psmStateChangeEvent); + + if (R_SUCCEEDED(rc)) g_psmStateChangeEventInitialized = 1; + + return rc; +} + +Result psmWaitStateChangeEvent(u64 timeout) { + Result rc = 0; + + rc = eventWait(&g_psmStateChangeEvent, timeout); + if (R_SUCCEEDED(rc)) rc = eventClear(&g_psmStateChangeEvent); + return rc; +} + +static Result _psmBindStateChangeEvent(Event *event_out) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_psmSession, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + + Result rc = serviceIpcDispatch(&g_psmSession); + + if(R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_psmSession, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + eventLoadRemote(event_out, r.Handles[0], false); + } + } + + return rc; +} + +Result psmUnbindStateChangeEvent(void) { + IpcCommand c; + ipcInitialize(&c); + + if (g_psmStateChangeEventInitialized) { + g_psmStateChangeEventInitialized = 0; + eventClose(&g_psmStateChangeEvent); + } + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = serviceIpcPrepareHeader(&g_psmSession, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 1; - Result rc = serviceIpcDispatch(&g_psmSrv); + Result rc = serviceIpcDispatch(&g_psmSession); if(R_SUCCEEDED(rc)) { IpcParsedCommand r; - ipcParse(&r); struct { u64 magic; u64 result; - u32 charger; - } *resp = r.Raw; + } *resp; + + serviceIpcParse(&g_psmSession, &r, sizeof(*resp)); + resp = r.Raw; rc = resp->result; - - if (R_SUCCEEDED(rc)) { - *out = resp->charger; - } } return rc; } + +static Result _psmSetEventEnabled(u64 cmd_id, bool flag) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u8 flag; + } *raw; + + raw = serviceIpcPrepareHeader(&g_psmSession, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->flag = (flag != 0); + + Result rc = serviceIpcDispatch(&g_psmSession); + + if(R_SUCCEEDED(rc)) { + IpcParsedCommand r; + + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_psmSession, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +static Result _psmSetChargerTypeChangeEventEnabled(bool flag) { + return _psmSetEventEnabled(2, flag); +} + +static Result _psmSetPowerSupplyChangeEventEnabled(bool flag) { + return _psmSetEventEnabled(3, flag); +} + +static Result _psmSetBatteryVoltageStateChangeEventEnabled(bool flag) { + return _psmSetEventEnabled(4, flag); +}