#include "service_guard.h" #include #include "runtime/hosversion.h" #include "services/hid.h" #include "services/applet.h" #include "services/nfc.h" static Service g_nfpuSrv; static Service g_nfcuSrv; static Service g_nfpuInterface; static Service g_nfcuInterface; // This is the data passed by every application this was tested with static const NfpuInitConfig g_nfpuDefaultInitConfig = { .unk1 = 0x00000001000a0003, .reserved1 = {0}, .unk2 = 0x0000000300040003, .reserved2 = {0}, }; static Result _nfpuCreateInterface(Service* srv, Service* srv_out); static Result _nfpuInterfaceInitialize(Service* srv, u64 aruid, const NfpuInitConfig *config, u32 cmd_id); static Result _nfpuInterfaceFinalize(Service* srv, u32 cmd_id); static Result _nfpuCmdNoIO(Service* srv, u32 cmd_id); static Result _nfpuCmdInIdNoOut(Service* srv, HidControllerID id, u32 cmd_id); static Result _nfpuCmdInIdOutEvent(Service* srv, HidControllerID id, Event *out_event, u32 cmd_id); static Result _nfpuCmdInIdOutBuffer(Service* srv, HidControllerID id, void* buf, size_t buf_size, u32 cmd_id); NX_GENERATE_SERVICE_GUARD_PARAMS(nfpu, (const NfpuInitConfig *config), (config)); Result _nfpuInitialize(const NfpuInitConfig *config) { if (config == NULL) config = &g_nfpuDefaultInitConfig; // If this fails (for example because we're a sysmodule) aruid stays zero u64 aruid = 0; appletGetAppletResourceUserId(&aruid); // nfp:user Result rc = smGetService(&g_nfpuSrv, "nfp:user"); if (R_SUCCEEDED(rc)) rc = serviceConvertToDomain(&g_nfpuSrv); if (R_SUCCEEDED(rc)) rc = _nfpuCreateInterface(&g_nfpuSrv, &g_nfpuInterface); if (R_SUCCEEDED(rc)) rc = _nfpuInterfaceInitialize(&g_nfpuInterface, aruid, config, 0); // nfc:user if (R_SUCCEEDED(rc)) rc = smGetService(&g_nfcuSrv, "nfc:user"); if (R_SUCCEEDED(rc)) rc = serviceConvertToDomain(&g_nfcuSrv); if (R_SUCCEEDED(rc)) rc = _nfpuCreateInterface(&g_nfcuSrv, &g_nfcuInterface); if (R_SUCCEEDED(rc)) rc = _nfpuInterfaceInitialize(&g_nfcuInterface, aruid, config, hosversionBefore(4,0,0) ? 0 : 400); return rc; } void _nfpuCleanup(void) { _nfpuInterfaceFinalize(&g_nfpuInterface, 1); _nfpuInterfaceFinalize(&g_nfcuInterface, hosversionBefore(4,0,0) ? 1 : 401); serviceClose(&g_nfpuInterface); serviceClose(&g_nfcuInterface); serviceClose(&g_nfpuSrv); serviceClose(&g_nfcuSrv); } Service* nfpuGetServiceSession(void) { return &g_nfpuSrv; } Service* nfpuGetServiceSession_Interface(void) { return &g_nfpuInterface; } Service* nfcuGetServiceSession(void) { return &g_nfpuSrv; } Service* nfcuGetServiceSession_Interface(void) { return &g_nfpuInterface; } static Result _nfpuCreateInterface(Service* srv, Service* srv_out) { serviceAssumeDomain(srv); return serviceDispatch(srv, 0, .out_num_objects = 1, .out_objects = srv_out, ); } static Result _nfpuCmdGetHandle(Service* srv, Handle* handle_out, u32 cmd_id) { serviceAssumeDomain(srv); return serviceDispatch(srv, cmd_id, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, .out_handles = handle_out, ); } static Result _fpuCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) { Handle tmp_handle = INVALID_HANDLE; Result rc = 0; rc = _nfpuCmdGetHandle(srv, &tmp_handle, cmd_id); if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, autoclear); return rc; } static Result _nfpuCmdNoIO(Service* srv, u32 cmd_id) { serviceAssumeDomain(srv); return serviceDispatch(srv, cmd_id); } static Result _nfpuCmdInIdNoOut(Service* srv, HidControllerID id, u32 cmd_id) { serviceAssumeDomain(srv); u64 tmp = hidControllerIDToOfficial(id); return serviceDispatchIn(srv, cmd_id, tmp); } static Result _nfpuCmdInIdOutU32(Service* srv, HidControllerID id, u32 *out, u32 cmd_id) { serviceAssumeDomain(srv); u64 tmp = hidControllerIDToOfficial(id); return serviceDispatchInOut(srv, cmd_id, tmp, *out); } static Result _nfpuCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { serviceAssumeDomain(srv); return serviceDispatchOut(srv, cmd_id, *out); } static Result _nfpuCmdNoInOutU8(Service* srv, u8 *out, u32 cmd_id) { serviceAssumeDomain(srv); return serviceDispatchOut(srv, cmd_id, *out); } static Result _nfpuCmdNoInOutBool(Service* srv, bool *out, u32 cmd_id) { u8 tmp=0; Result rc = _nfpuCmdNoInOutU8(srv, &tmp, cmd_id); if (R_SUCCEEDED(rc) && out) *out = tmp!=0; return rc; } static Result _nfpuCmdInIdOutEvent(Service* srv, HidControllerID id, Event *out_event, u32 cmd_id) { Handle tmp_handle = INVALID_HANDLE; u64 tmp = hidControllerIDToOfficial(id); serviceAssumeDomain(srv); Result rc = serviceDispatchIn(srv, cmd_id, tmp, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, .out_handles = &tmp_handle, ); if (R_SUCCEEDED(rc)) eventLoadRemote(out_event, tmp_handle, false); return rc; } static Result _nfpuCmdInIdOutBuffer(Service* srv, HidControllerID id, void* buf, size_t buf_size, u32 cmd_id) { u64 tmp = hidControllerIDToOfficial(id); serviceAssumeDomain(srv); return serviceDispatchIn(srv, cmd_id, tmp, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, .buffers = { { buf, buf_size } }, ); } static Result _nfpuInterfaceInitialize(Service* srv, u64 aruid, const NfpuInitConfig *config, u32 cmd_id) { const struct { u64 aruid; u64 zero; } in = { aruid, 0 }; serviceAssumeDomain(srv); return serviceDispatchIn(srv, cmd_id, in, .buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In }, .buffers = { { config, sizeof(NfpuInitConfig) } }, .in_send_pid = true, ); } static Result _nfpuInterfaceFinalize(Service* srv, u32 cmd_id) { return _nfpuCmdNoIO(srv, cmd_id); } Result nfpuListDevices(s32 *count, HidControllerID *out, size_t num_elements) { // This is the maximum number of controllers that can be connected to a console at a time // Incidentally, this is the biggest value official software (SSBU) was observed using size_t max_controllers = 9; if (num_elements > max_controllers) num_elements = max_controllers; u64 buf[max_controllers]; memset(buf, 0, sizeof(buf)); serviceAssumeDomain(&g_nfpuInterface); Result rc = serviceDispatchOut(&g_nfpuInterface, 2, *count, .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out }, .buffers = { { buf, max_controllers*sizeof(u64) } }, ); if (R_SUCCEEDED(rc) && out) { for (size_t i=0; i