/** * @file set.h * @brief Settings services IPC wrapper. * @author plutoo * @author yellows8 * @copyright libnx Authors */ #include #include "types.h" #include "result.h" #include "arm/atomics.h" #include "kernel/ipc.h" #include "runtime/hosversion.h" #include "services/set.h" #include "services/sm.h" #include "services/applet.h" static Service g_setSrv; static Service g_setsysSrv; static u64 g_refCnt; static u64 g_refCntSys; static bool g_setLanguageCodesInitialized; static u64 g_setLanguageCodes[0x40]; static s32 g_setLanguageCodesTotal; static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode); Result setInitialize(void) { atomicIncrement64(&g_refCnt); if (serviceIsActive(&g_setSrv)) return 0; g_setLanguageCodesInitialized = 0; return smGetService(&g_setSrv, "set"); } void setExit(void) { if (atomicDecrement64(&g_refCnt) == 0) { serviceClose(&g_setSrv); } } Service* setGetServiceSession(void) { return &g_setSrv; } Result setsysInitialize(void) { atomicIncrement64(&g_refCntSys); if (serviceIsActive(&g_setsysSrv)) return MAKERESULT(Module_Libnx, LibnxError_AlreadyInitialized); return smGetService(&g_setsysSrv, "set:sys"); } void setsysExit(void) { if (atomicDecrement64(&g_refCntSys) == 0) { serviceClose(&g_setsysSrv); } } Service* setsysGetSessionService(void) { return &g_setsysSrv; } static Result setInitializeLanguageCodesCache(void) { if (g_setLanguageCodesInitialized) return 0; Result rc = 0; rc = setGetAvailableLanguageCodes(&g_setLanguageCodesTotal, g_setLanguageCodes, sizeof(g_setLanguageCodes)/sizeof(u64)); if (R_FAILED(rc)) return rc; if (g_setLanguageCodesTotal < 0) g_setLanguageCodesTotal = 0; g_setLanguageCodesInitialized = 1; return rc; } Result setMakeLanguage(u64 LanguageCode, s32 *Language) { Result rc = setInitializeLanguageCodesCache(); if (R_FAILED(rc)) return rc; s32 i; rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); for (i=0; i= g_setLanguageCodesTotal) { if (hosversionBefore(4,0,0)) return MAKERESULT(Module_Libnx, LibnxError_BadInput); return _setMakeLanguageCode(Language, LanguageCode); } *LanguageCode = g_setLanguageCodes[Language]; return rc; } Result setGetSystemLanguage(u64 *LanguageCode) { //This is disabled because the returned LanguageCode can differ from the system language, for example ja instead of {English}. /*Result rc = appletGetDesiredLanguage(LanguageCode); if (R_SUCCEEDED(rc)) return rc;*/ return setGetLanguageCode(LanguageCode); } Result setGetLanguageCode(u64 *LanguageCode) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 0; Result rc = serviceIpcDispatch(&g_setSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u64 LanguageCode; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode; } return rc; } Result setGetAvailableLanguageCodes(s32 *total_entries, u64 *LanguageCodes, size_t max_entries) { IpcCommand c; ipcInitialize(&c); Result rc=0; bool new_cmd = hosversionAtLeast(4,0,0); if (!new_cmd) {//On system-version <4.0.0 the sysmodule will close the session if max_entries is too large. s32 tmptotal = 0; rc = setGetAvailableLanguageCodeCount(&tmptotal); if (R_FAILED(rc)) return rc; if (max_entries > (size_t)tmptotal) max_entries = (size_t)tmptotal; } size_t bufsize = max_entries*sizeof(u64); if (!new_cmd) { ipcAddRecvStatic(&c, LanguageCodes, bufsize, 0); } else { ipcAddRecvBuffer(&c, LanguageCodes, bufsize, 0); } struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = new_cmd ? 5 : 1; rc = serviceIpcDispatch(&g_setSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; s32 total_entries; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && total_entries) *total_entries = resp->total_entries; } return rc; } static Result _setMakeLanguageCode(s32 Language, u64 *LanguageCode) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; s32 Language; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 2; raw->Language = Language; Result rc = serviceIpcDispatch(&g_setSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u64 LanguageCode; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && LanguageCode) *LanguageCode = resp->LanguageCode; } return rc; } Result setGetAvailableLanguageCodeCount(s32 *total) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = hosversionAtLeast(4,0,0) ? 6 : 3; Result rc = serviceIpcDispatch(&g_setSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; s32 total; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && total) { *total = resp->total; if (*total < 0) *total = 0; } } return rc; } Result setGetRegionCode(SetRegion *out) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 4; Result rc = serviceIpcDispatch(&g_setSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; s32 RegionCode; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && out) *out = resp->RegionCode; } return rc; } Result setsysGetColorSetId(ColorSetId *out) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 23; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u32 color_set; } *resp = r.Raw; *out = resp->color_set; rc = resp->result; } return rc; } Result setsysSetColorSetId(ColorSetId id) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; s32 id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 24; raw->id = id; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result setsysGetSettingsItemValue(const char *name, const char *item_key, void *value_out, size_t value_out_size) { char send_name[SET_MAX_NAME_SIZE]; char send_item_key[SET_MAX_NAME_SIZE]; memset(send_name, 0, SET_MAX_NAME_SIZE); memset(send_item_key, 0, SET_MAX_NAME_SIZE); strncpy(send_name, name, SET_MAX_NAME_SIZE-1); strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1); IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0); ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0); ipcAddRecvBuffer(&c, value_out, value_out_size, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 38; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result setsysGetSettingsItemValueSize(const char *name, const char *item_key, u64 *size_out) { char send_name[SET_MAX_NAME_SIZE]; char send_item_key[SET_MAX_NAME_SIZE]; memset(send_name, 0, SET_MAX_NAME_SIZE); memset(send_item_key, 0, SET_MAX_NAME_SIZE); strncpy(send_name, name, SET_MAX_NAME_SIZE-1); strncpy(send_item_key, item_key, SET_MAX_NAME_SIZE-1); IpcCommand c; ipcInitialize(&c); ipcAddSendStatic(&c, send_name, SET_MAX_NAME_SIZE, 0); ipcAddSendStatic(&c, send_item_key, SET_MAX_NAME_SIZE, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 37; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u64 size; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && size_out) *size_out = resp->size; } return rc; } Result setsysGetSerialNumber(char *serial) { IpcCommand c; ipcInitialize(&c); if (serial) memset(serial, 0, 0x19); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 68; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; char serial[0x18]; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc) && serial) memcpy(serial, resp->serial, 0x18); } return rc; } Result setsysGetFlag(SetSysFlag flag, bool *out) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = flag; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 flag; } *resp = r.Raw; *out = resp->flag; rc = resp->result; } return rc; } Result setsysSetFlag(SetSysFlag flag, bool enable) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; u8 flag; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = flag + 1; raw->flag = enable; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u8 flag; } *resp = r.Raw; rc = resp->result; } return rc; } static Result _setsysGetFirmwareVersionImpl(SetSysFirmwareVersion *out, u32 cmd_id) { IpcCommand c; ipcInitialize(&c); ipcAddRecvStatic(&c, out, sizeof(*out), 0); struct { u64 magic; u64 cmd_id; } *raw; raw = serviceIpcPrepareHeader(&g_setsysSrv, &c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = cmd_id; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; struct { u64 magic; u64 result; } *resp; serviceIpcParse(&g_setsysSrv, &r, sizeof(*resp)); resp = r.Raw; rc = resp->result; } return rc; } Result setsysGetFirmwareVersion(SetSysFirmwareVersion *out) { /* GetFirmwareVersion2 does exactly what GetFirmwareVersion does, except it doesn't zero the revision field. */ if (hosversionAtLeast(3,0,0)) { return _setsysGetFirmwareVersionImpl(out, 4); } else { return _setsysGetFirmwareVersionImpl(out, 3); } } Result setsysBindFatalDirtyFlagEvent(Event *out) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 93; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { eventLoadRemote(out, r.Handles[0], false); } } return rc; } Result setsysGetFatalDirtyFlags(u64 *flags_0, u64 *flags_1) { IpcCommand c; ipcInitialize(&c); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 94; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; u64 flags_0; u64 flags_1; } *resp = r.Raw; rc = resp->result; if (R_SUCCEEDED(rc)) { *flags_0 = resp->flags_0; *flags_1 = resp->flags_1; } } return rc; } Result setsysGetDeviceNickname(char* nickname) { IpcCommand c; ipcInitialize(&c); ipcAddRecvBuffer(&c, nickname, SET_MAX_NICKNAME_SIZE, BufferType_Normal); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 77; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; } Result setsysSetDeviceNickname(const char* nickname) { char send_nickname[SET_MAX_NICKNAME_SIZE] = {0}; strncpy(send_nickname, nickname, SET_MAX_NICKNAME_SIZE-1); IpcCommand c; ipcInitialize(&c); ipcAddSendBuffer(&c, send_nickname, SET_MAX_NICKNAME_SIZE, 0); struct { u64 magic; u64 cmd_id; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 78; Result rc = serviceIpcDispatch(&g_setsysSrv); if (R_SUCCEEDED(rc)) { IpcParsedCommand r; ipcParse(&r); struct { u64 magic; u64 result; } *resp = r.Raw; rc = resp->result; } return rc; }