#include "services/pctl.h" #include "arm/atomics.h" #include "runtime/hosversion.h" static Service g_pctlSrv; static Service g_pctlSession; static u64 g_refCnt; static Result _pctlCreateService(Service* out, u64 cmd_id); static Result _pctlNoIO(u64 cmd_id); Result pctlInitialize(void) { Result rc=0; bool sysverflag = hosversionBefore(4,0,0); atomicIncrement64(&g_refCnt); if (serviceIsActive(&g_pctlSrv)) return 0; rc = smGetService(&g_pctlSrv, "pctl:a"); if (R_FAILED(rc)) rc = smGetService(&g_pctlSrv, "pctl:s"); if (R_FAILED(rc)) rc = smGetService(&g_pctlSrv, "pctl:r"); if (R_FAILED(rc)) rc = smGetService(&g_pctlSrv, "pctl"); if (R_SUCCEEDED(rc)) rc = serviceConvertToDomain(&g_pctlSrv); if (R_SUCCEEDED(rc)) rc = _pctlCreateService(&g_pctlSession, sysverflag ? 0 : 1); if (R_SUCCEEDED(rc) && !sysverflag) rc = _pctlNoIO(1); if (R_FAILED(rc)) pctlExit(); return rc; } void pctlExit(void) { if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_pctlSession); serviceClose(&g_pctlSrv); } } static Result _pctlCreateService(Service* out, u64 cmd_id) { IpcCommand c; ipcInitialize(&c); ipcSendPid(&c); struct { u64 magic; u64 cmd_id; u64 pid_reserved; } *raw; raw = serviceIpcPrepareHeader(&g_pctlSrv, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; raw->pid_reserved = 0; Result rc = serviceIpcDispatch(&g_pctlSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; struct { u64 magic; u64 result; } *resp; serviceIpcParse(&g_pctlSrv, &r, sizeof(*resp)); resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) serviceCreateSubservice(out, &g_pctlSrv, &r, 0); } return rc; } static Result _pctlNoIO(u64 cmd_id) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = serviceIpcPrepareHeader(&g_pctlSession, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; Result rc = serviceIpcDispatch(&g_pctlSession); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; struct { u64 magic; u64 result; } *resp; serviceIpcParse(&g_pctlSession, &r, sizeof(*resp)); resp = r.Raw; rc = resp->result; } return rc; } static Result _pctlNoInputOutBool(u64 cmd_id, bool *flag) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = serviceIpcPrepareHeader(&g_pctlSession, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; Result rc = serviceIpcDispatch(&g_pctlSession); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; struct { u64 magic; u64 result; u8 out; } PACKED *resp; serviceIpcParse(&g_pctlSession, &r, sizeof(*resp)); resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && flag) *flag = resp->out!=0; } return rc; } Result pctlConfirmStereoVisionPermission(void) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _pctlNoIO(1013); } Result pctlIsRestrictionEnabled(bool *flag) { return _pctlNoInputOutBool(1031, flag); } Result pctlResetConfirmedStereoVisionPermission(void) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _pctlNoIO(1064); } Result pctlIsStereoVisionPermitted(bool *flag) { if (hosversionBefore(5,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); return _pctlNoInputOutBool(1065, flag); }