libnx/nx/source/services/pcv.c
friedkeenan da4c060278 Add a bunch of GetServiceSession functions (#305)
* Add a bunch of GetServiceSession functions
2019-07-13 15:09:28 -04:00

235 lines
6.6 KiB
C

#include "types.h"
#include "result.h"
#include "arm/atomics.h"
#include "kernel/ipc.h"
#include "runtime/hosversion.h"
#include "services/pcv.h"
#include "services/sm.h"
static Service g_pcvSrv;
static u64 g_refCnt;
Result pcvInitialize(void) {
Result rc = 0;
atomicIncrement64(&g_refCnt);
if (serviceIsActive(&g_pcvSrv))
return 0;
rc = smGetService(&g_pcvSrv, "pcv");
if (R_FAILED(rc)) pcvExit();
return rc;
}
void pcvExit(void) {
if (atomicDecrement64(&g_refCnt) == 0) {
serviceClose(&g_pcvSrv);
}
}
Service* pcvGetServiceSession(void) {
return &g_pcvSrv;
}
Result pcvGetModuleId(PcvModuleId *module_id, PcvModule module) {
static const PcvModuleId s_moduleIdMap[PcvModule_Count] = {
PcvModuleId_CpuBus, PcvModuleId_GPU, PcvModuleId_I2S1, PcvModuleId_I2S2,
PcvModuleId_I2S3, PcvModuleId_PWM, PcvModuleId_I2C1, PcvModuleId_I2C2,
PcvModuleId_I2C3, PcvModuleId_I2C4, PcvModuleId_I2C5, PcvModuleId_I2C6,
PcvModuleId_SPI1, PcvModuleId_SPI2, PcvModuleId_SPI3, PcvModuleId_SPI4,
PcvModuleId_DISP1, PcvModuleId_DISP2, PcvModuleId_ISP, PcvModuleId_VI,
PcvModuleId_SDMMC1, PcvModuleId_SDMMC2, PcvModuleId_SDMMC3, PcvModuleId_SDMMC4,
PcvModuleId_OWR, PcvModuleId_CSITE, PcvModuleId_TSEC, PcvModuleId_MSELECT,
PcvModuleId_HDA2CODEC_2X, PcvModuleId_ACTMON, PcvModuleId_I2C_SLOW, PcvModuleId_SOR1,
PcvModuleId_SATA, PcvModuleId_HDA, PcvModuleId_XUSB_CORE_HOST, PcvModuleId_XUSB_FALCON,
PcvModuleId_XUSB_FS, PcvModuleId_XUSB_CORE_DEV, PcvModuleId_XUSB_SS_HOSTDEV, PcvModuleId_UARTA,
PcvModuleId_UARTB, PcvModuleId_UARTC, PcvModuleId_UARTD, PcvModuleId_HOST1X,
PcvModuleId_ENTROPY, PcvModuleId_SOC_THERM, PcvModuleId_VIC, PcvModuleId_NVENC,
PcvModuleId_NVJPG, PcvModuleId_NVDEC, PcvModuleId_QSPI, PcvModuleId_VI_I2C,
PcvModuleId_TSECB, PcvModuleId_APE, PcvModuleId_ACLK, PcvModuleId_UARTAPE,
PcvModuleId_EMC, PcvModuleId_PLLE0_0, PcvModuleId_PLLE0_1, PcvModuleId_DSI,
PcvModuleId_MAUD, PcvModuleId_DPAUX1, PcvModuleId_MIPI_CAL, PcvModuleId_UART_FST_MIPI_CAL,
PcvModuleId_OSC, PcvModuleId_SCLK, PcvModuleId_SOR_SAFE, PcvModuleId_XUSB_SS,
PcvModuleId_XUSB_HOST, PcvModuleId_XUSB_DEV, PcvModuleId_EXTPERIPH1, PcvModuleId_AHUB,
PcvModuleId_HDA2HDMICODEC, PcvModuleId_PLLP5, PcvModuleId_USBD, PcvModuleId_USB2,
PcvModuleId_PCIE, PcvModuleId_AFI, PcvModuleId_PCIEXCLK, PcvModuleId_PEX_USB_UPHY,
PcvModuleId_XUSB_PADCTL, PcvModuleId_APBDMA, PcvModuleId_USB2_TRK, PcvModuleId_PLLE0_2,
PcvModuleId_PLLE0_3, PcvModuleId_CEC, PcvModuleId_EXTPERIPH2,
};
if (module >= PcvModule_Count) {
return MAKERESULT(Module_Libnx, LibnxError_BadInput);
}
*module_id = s_moduleIdMap[module];
return 0;
}
Result pcvSetClockRate(PcvModule module, u32 hz) {
if(hosversionAtLeast(8,0,0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 module;
u32 hz;
} *raw;
raw = serviceIpcPrepareHeader(&g_pcvSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 2;
raw->module = module;
raw->hz = hz;
Result rc = serviceIpcDispatch(&g_pcvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_pcvSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result pcvGetClockRate(PcvModule module, u32 *out_hz) {
if(hosversionAtLeast(8,0,0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 module;
} *raw;
raw = serviceIpcPrepareHeader(&g_pcvSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 3;
raw->module = module;
Result rc = serviceIpcDispatch(&g_pcvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u32 hz;
} *resp;
serviceIpcParse(&g_pcvSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) {
*out_hz = resp->hz;
}
}
return rc;
}
Result pcvSetVoltageEnabled(bool state, u32 voltage) {
if(hosversionAtLeast(8,0,0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u8 state;
u32 voltage;
} *raw;
raw = serviceIpcPrepareHeader(&g_pcvSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 8;
raw->state = (u8)state;
raw->voltage = voltage;
Result rc = serviceIpcDispatch(&g_pcvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(&g_pcvSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
}
return rc;
}
Result pcvGetVoltageEnabled(bool *isEnabled, u32 voltage) {
if(hosversionAtLeast(8,0,0)) {
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
}
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 voltage;
} *raw;
raw = serviceIpcPrepareHeader(&g_pcvSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 9;
raw->voltage = voltage;
Result rc = serviceIpcDispatch(&g_pcvSrv);
if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
u8 isEnabled;
} *resp;
serviceIpcParse(&g_pcvSrv, &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if(R_SUCCEEDED(rc) && isEnabled) {
*isEnabled = (bool)resp->isEnabled;
}
}
return rc;
}