Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions nx/include/switch/services/psm.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,81 @@
#include "../sf/service.h"
#include "../kernel/event.h"

/// ChargerType
typedef enum {
PsmChargerType_Unconnected = 0, ///< No charger
PsmChargerType_EnoughPower = 1, ///< Full supported power
PsmChargerType_LowPower = 2, ///< Lower power supported USB-PD mode
PsmChargerType_NotSupported = 3, ///< No common supported USB-PD modes
} PsmChargerType;

/// Vdd50State
typedef enum {
PsmVdd50State_Unknown = 0,
PsmVdd50State_Vdd50AOffVdd50BOff = 1,
PsmVdd50State_Vdd50AOnVdd50BOff = 2,
PsmVdd50State_Vdd50AOffVdd50BOn = 3,
} PsmVdd50State;

/// BatteryVoltageState
typedef enum {
PsmBatteryVoltageState_NeedsShutdown = 0, ///< Power state should transition to shutdown
PsmBatteryVoltageState_NeedsSleep = 1, ///< Power state should transition to sleep
PsmBatteryVoltageState_NoPerformanceBoost = 2, ///< Performance boost modes cannot be entered
PsmBatteryVoltageState_Normal = 3, ///< Everything is normal
} PsmBatteryVoltageState;

/// BatteryChargeInfoFieldsOld [1.0.0-16.1.0]
typedef struct {
u32 input_current_limit;
u32 boost_mode_current_limit;
u32 fast_charge_current_limit;
u32 charge_voltage_limit;
PsmChargerType charger_type;
u8 hi_z_mode;
bool battery_charging;
u8 pad[2];
PsmVdd50State vdd50_state;
u32 temperature_celcius;
u32 battery_charge_percentage;
u32 battery_charge_milli_voltage;
u32 battery_age_percentage;
u32 usb_power_role;
u32 usb_charger_type;
u32 charger_input_voltage_limit;
u32 charger_input_current_limit;
bool fast_battery_charging;
bool controller_power_supply;
bool otg_request;
u8 reserved;
} PsmBatteryChargeInfoFieldsOld;

/// BatteryChargeInfoFields [17.0.0+]
typedef struct {
u32 input_current_limit;
u32 boost_mode_current_limit;
u32 fast_charge_current_limit;
u32 charge_voltage_limit;
PsmChargerType charger_type;
u8 hi_z_mode;
bool battery_charging;
u8 pad[2];
PsmVdd50State vdd50_state;
u32 temperature_celcius;
u32 battery_charge_percentage;
u32 battery_charge_milli_voltage;
u32 battery_age_percentage;
u32 usb_power_role;
u32 usb_charger_type;
u32 charger_input_voltage_limit;
u32 charger_input_current_limit;
bool fast_battery_charging;
bool controller_power_supply;
bool otg_request;
u8 reserved;
u8 unk_x40[0x14];
} PsmBatteryChargeInfoFields;

/// IPsmSession
typedef struct {
Service s;
Expand All @@ -38,13 +99,109 @@ void psmExit(void);
/// Gets the Service object for the actual psm service session.
Service* psmGetServiceSession(void);

/**
* @brief GetBatteryChargePercentage
* @param[out] out Battery charge percentage.
*/
Result psmGetBatteryChargePercentage(u32 *out);

/**
* @brief GetChargerType
* @param[out] out \ref PsmChargerType
*/
Result psmGetChargerType(PsmChargerType *out);

/**
* @brief EnableBatteryCharging
*/
Result psmEnableBatteryCharging(void);

/**
* @brief DisableBatteryCharging
*/
Result psmDisableBatteryCharging(void);

/**
* @brief IsBatteryChargingEnabled
* @param[out] out Output flag.
*/
Result psmIsBatteryChargingEnabled(bool *out);

/**
* @brief AcquireControllerPowerSupply
*/
Result psmAcquireControllerPowerSupply(void);

/**
* @brief ReleaseControllerPowerSupply
*/
Result psmReleaseControllerPowerSupply(void);

/**
* @brief EnableEnoughPowerChargeEmulation
*/
Result psmEnableEnoughPowerChargeEmulation(void);

/**
* @brief DisableEnoughPowerChargeEmulation
*/
Result psmDisableEnoughPowerChargeEmulation(void);

/**
* @brief EnableFastBatteryCharging
*/
Result psmEnableFastBatteryCharging(void);

/**
* @brief DisableFastBatteryCharging
*/
Result psmDisableFastBatteryCharging(void);

/**
* @brief GetBatteryVoltageState
* @param[out] out \ref PsmBatteryVoltageState
*/
Result psmGetBatteryVoltageState(PsmBatteryVoltageState *out);

/**
* @brief GetRawBatteryChargePercentage
* @param[out] out Raw battery charge percentage.
*/
Result psmGetRawBatteryChargePercentage(double *out);

/**
* @brief IsEnoughPowerSupplied
* @param[out] out Output flag.
*/
Result psmIsEnoughPowerSupplied(bool *out);

/**
* @brief GetBatteryAgePercentage
* @param[out] out Battery age percentage.
*/
Result psmGetBatteryAgePercentage(double *out);

/**
* @brief GetBatteryChargeInfoEvent
* @param[out] out_event Event object.
* @param[in] autoclear Event autoclear.
*/
Result psmGetBatteryChargeInfoEvent(Event* out_event, bool autoclear);

/**
* @brief GetBatteryChargeInfoFields
* @param[out] out_fields \ref PsmBatteryChargeInfoFields
*/
Result psmGetBatteryChargeInfoFields(PsmBatteryChargeInfoFields *out_fields);

/**
* @brief GetBatteryChargeCalibratedEvent
* @note Only available on [3.0.0+].
* @param[out] out_event Event object.
* @param[in] autoclear Event autoclear.
*/
Result psmGetBatteryChargeCalibratedEvent(Event* out_event, bool autoclear);

/**
* @brief Wrapper func which opens a PsmSession and handles event setup.
* @note Uses the actual BindStateChangeEvent cmd internally.
Expand Down
63 changes: 63 additions & 0 deletions nx/source/services/psm.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#define NX_SERVICE_ASSUME_NON_DOMAIN
#include <string.h>
#include "service_guard.h"
#include "runtime/hosversion.h"
#include "services/psm.h"

static Service g_psmSrv;
Expand Down Expand Up @@ -75,6 +77,42 @@ Result psmGetChargerType(PsmChargerType *out) {
return _psmCmdNoInOutU32(&g_psmSrv, out, 1);
}

Result psmEnableBatteryCharging(void) {
return _psmCmdNoIO(&g_psmSrv, 2);
}

Result psmDisableBatteryCharging(void) {
return _psmCmdNoIO(&g_psmSrv, 3);
}

Result psmIsBatteryChargingEnabled(bool *out) {
return _psmCmdNoInOutBool(&g_psmSrv, out, 4);
}

Result psmAcquireControllerPowerSupply(void) {
return _psmCmdNoIO(&g_psmSrv, 5);
}

Result psmReleaseControllerPowerSupply(void) {
return _psmCmdNoIO(&g_psmSrv, 6);
}

Result psmEnableEnoughPowerChargeEmulation(void) {
return _psmCmdNoIO(&g_psmSrv, 8);
}

Result psmDisableEnoughPowerChargeEmulation(void) {
return _psmCmdNoIO(&g_psmSrv, 9);
}

Result psmEnableFastBatteryCharging(void) {
return _psmCmdNoIO(&g_psmSrv, 10);
}

Result psmDisableFastBatteryCharging(void) {
return _psmCmdNoIO(&g_psmSrv, 11);
}

Result psmGetBatteryVoltageState(PsmBatteryVoltageState *out) {
u32 state;
Result rc = _psmCmdNoInOutU32(&g_psmSrv, &state, 12);
Expand All @@ -94,6 +132,31 @@ Result psmGetBatteryAgePercentage(double *out) {
return _psmCmdNoInOutDouble(&g_psmSrv, out, 15);
}

Result psmGetBatteryChargeInfoEvent(Event* out_event, bool autoclear) {
return _psmCmdGetEvent(&g_psmSrv, out_event, autoclear, 16);
}

Result psmGetBatteryChargeInfoFields(PsmBatteryChargeInfoFields *out_fields) {
if (hosversionBefore(17,0,0)) {
PsmBatteryChargeInfoFieldsOld fields;
Result rc = serviceDispatchOut(&g_psmSrv, 17, fields);
if (R_SUCCEEDED(rc)) {
memset(out_fields, 0, sizeof(*out_fields));
memcpy(out_fields, &fields, sizeof(fields));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a memset for out_fields.

}
return rc;
}

return serviceDispatchOut(&g_psmSrv, 17, *out_fields);
}

Result psmGetBatteryChargeCalibratedEvent(Event* out_event, bool autoclear) {
if (hosversionBefore(3,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);

return _psmCmdGetEvent(&g_psmSrv, out_event, autoclear, 18);
}

static Result _psmOpenSession(Service* srv_out) {
return serviceDispatch(&g_psmSrv, 7,
.out_num_objects = 1,
Expand Down