summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/hid/emulated_controller.cpp4
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/nfp/nfp.cpp187
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp224
-rw-r--r--src/core/hle/service/nfp/nfp_device.h12
-rw-r--r--src/core/hle/service/nfp/nfp_interface.cpp (renamed from src/core/hle/service/nfp/nfp_user.cpp)495
-rw-r--r--src/core/hle/service/nfp/nfp_interface.h (renamed from src/core/hle/service/nfp/nfp_user.h)36
-rw-r--r--src/core/hle/service/nfp/nfp_types.h54
-rw-r--r--src/dedicated_room/yuzu_room.cpp16
-rw-r--r--src/video_core/engines/fermi_2d.cpp16
-rw-r--r--src/video_core/engines/maxwell_3d.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp139
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h48
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp36
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h6
16 files changed, 1135 insertions, 154 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4e677f287..8817a99c9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -570,10 +570,10 @@ add_library(core STATIC
570 hle/service/nfp/nfp.h 570 hle/service/nfp/nfp.h
571 hle/service/nfp/nfp_device.cpp 571 hle/service/nfp/nfp_device.cpp
572 hle/service/nfp/nfp_device.h 572 hle/service/nfp/nfp_device.h
573 hle/service/nfp/nfp_interface.cpp
574 hle/service/nfp/nfp_interface.h
573 hle/service/nfp/nfp_result.h 575 hle/service/nfp/nfp_result.h
574 hle/service/nfp/nfp_types.h 576 hle/service/nfp/nfp_types.h
575 hle/service/nfp/nfp_user.cpp
576 hle/service/nfp/nfp_user.h
577 hle/service/ngct/ngct.cpp 577 hle/service/ngct/ngct.cpp
578 hle/service/ngct/ngct.h 578 hle/service/ngct/ngct.h
579 hle/service/nifm/nifm.cpp 579 hle/service/nifm/nifm.cpp
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index a29c9a6f8..a70f8807c 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -280,6 +280,10 @@ void EmulatedController::LoadVirtualGamepadParams() {
280 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); 280 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
281 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); 281 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
282 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); 282 virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
283 virtual_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
284 virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
285 virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
286 virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
283} 287}
284 288
285void EmulatedController::ReloadInput() { 289void EmulatedController::ReloadInput() {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a17c46121..e59de844c 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1807,7 +1807,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestCon
1807} 1807}
1808 1808
1809void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { 1809void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
1810 LOG_WARNING(Service_AM, "(STUBBED) called"); 1810 LOG_DEBUG(Service_AM, "(STUBBED) called");
1811 1811
1812 IPC::ResponseBuilder rb{ctx, 2}; 1812 IPC::ResponseBuilder rb{ctx, 2};
1813 rb.Push(AM::ResultNoDataInChannel); 1813 rb.Push(AM::ResultNoDataInChannel);
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index e262dc2f2..2714f4bea 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -4,11 +4,138 @@
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/hle/service/ipc_helpers.h" 5#include "core/hle/service/ipc_helpers.h"
6#include "core/hle/service/nfp/nfp.h" 6#include "core/hle/service/nfp/nfp.h"
7#include "core/hle/service/nfp/nfp_user.h" 7#include "core/hle/service/nfp/nfp_interface.h"
8#include "core/hle/service/server_manager.h" 8#include "core/hle/service/server_manager.h"
9 9
10namespace Service::NFP { 10namespace Service::NFP {
11 11
12class IUser final : public Interface {
13public:
14 explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &IUser::Initialize, "Initialize"},
18 {1, &IUser::Finalize, "Finalize"},
19 {2, &IUser::ListDevices, "ListDevices"},
20 {3, &IUser::StartDetection, "StartDetection"},
21 {4, &IUser::StopDetection, "StopDetection"},
22 {5, &IUser::Mount, "Mount"},
23 {6, &IUser::Unmount, "Unmount"},
24 {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
25 {8, &IUser::GetApplicationArea, "GetApplicationArea"},
26 {9, &IUser::SetApplicationArea, "SetApplicationArea"},
27 {10, &IUser::Flush, "Flush"},
28 {11, &IUser::Restore, "Restore"},
29 {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
30 {13, &IUser::GetTagInfo, "GetTagInfo"},
31 {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
32 {15, &IUser::GetCommonInfo, "GetCommonInfo"},
33 {16, &IUser::GetModelInfo, "GetModelInfo"},
34 {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
35 {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
36 {19, &IUser::GetState, "GetState"},
37 {20, &IUser::GetDeviceState, "GetDeviceState"},
38 {21, &IUser::GetNpadId, "GetNpadId"},
39 {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
40 {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
41 {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
42 };
43 // clang-format on
44
45 RegisterHandlers(functions);
46 }
47};
48
49class ISystem final : public Interface {
50public:
51 explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
52 // clang-format off
53 static const FunctionInfo functions[] = {
54 {0, &ISystem::InitializeSystem, "InitializeSystem"},
55 {1, &ISystem::FinalizeSystem, "FinalizeSystem"},
56 {2, &ISystem::ListDevices, "ListDevices"},
57 {3, &ISystem::StartDetection, "StartDetection"},
58 {4, &ISystem::StopDetection, "StopDetection"},
59 {5, &ISystem::Mount, "Mount"},
60 {6, &ISystem::Unmount, "Unmount"},
61 {10, &ISystem::Flush, "Flush"},
62 {11, &ISystem::Restore, "Restore"},
63 {12, &ISystem::CreateApplicationArea, "CreateApplicationArea"},
64 {13, &ISystem::GetTagInfo, "GetTagInfo"},
65 {14, &ISystem::GetRegisterInfo, "GetRegisterInfo"},
66 {15, &ISystem::GetCommonInfo, "GetCommonInfo"},
67 {16, &ISystem::GetModelInfo, "GetModelInfo"},
68 {17, &ISystem::AttachActivateEvent, "AttachActivateEvent"},
69 {18, &ISystem::AttachDeactivateEvent, "AttachDeactivateEvent"},
70 {19, &ISystem::GetState, "GetState"},
71 {20, &ISystem::GetDeviceState, "GetDeviceState"},
72 {21, &ISystem::GetNpadId, "GetNpadId"},
73 {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
74 {100, &ISystem::Format, "Format"},
75 {101, &ISystem::GetAdminInfo, "GetAdminInfo"},
76 {102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
77 {103, &ISystem::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"},
78 {104, &ISystem::DeleteRegisterInfo, "DeleteRegisterInfo"},
79 {105, &ISystem::DeleteApplicationArea, "DeleteApplicationArea"},
80 {106, &ISystem::ExistsApplicationArea, "ExistsApplicationArea"},
81 };
82 // clang-format on
83
84 RegisterHandlers(functions);
85 }
86};
87
88class IDebug final : public Interface {
89public:
90 explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
91 // clang-format off
92 static const FunctionInfo functions[] = {
93 {0, &IDebug::InitializeDebug, "InitializeDebug"},
94 {1, &IDebug::FinalizeDebug, "FinalizeDebug"},
95 {2, &IDebug::ListDevices, "ListDevices"},
96 {3, &IDebug::StartDetection, "StartDetection"},
97 {4, &IDebug::StopDetection, "StopDetection"},
98 {5, &IDebug::Mount, "Mount"},
99 {6, &IDebug::Unmount, "Unmount"},
100 {7, &IDebug::OpenApplicationArea, "OpenApplicationArea"},
101 {8, &IDebug::GetApplicationArea, "GetApplicationArea"},
102 {9, &IDebug::SetApplicationArea, "SetApplicationArea"},
103 {10, &IDebug::Flush, "Flush"},
104 {11, &IDebug::Restore, "Restore"},
105 {12, &IDebug::CreateApplicationArea, "CreateApplicationArea"},
106 {13, &IDebug::GetTagInfo, "GetTagInfo"},
107 {14, &IDebug::GetRegisterInfo, "GetRegisterInfo"},
108 {15, &IDebug::GetCommonInfo, "GetCommonInfo"},
109 {16, &IDebug::GetModelInfo, "GetModelInfo"},
110 {17, &IDebug::AttachActivateEvent, "AttachActivateEvent"},
111 {18, &IDebug::AttachDeactivateEvent, "AttachDeactivateEvent"},
112 {19, &IDebug::GetState, "GetState"},
113 {20, &IDebug::GetDeviceState, "GetDeviceState"},
114 {21, &IDebug::GetNpadId, "GetNpadId"},
115 {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"},
116 {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
117 {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"},
118 {100, &IDebug::Format, "Format"},
119 {101, &IDebug::GetAdminInfo, "GetAdminInfo"},
120 {102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
121 {103, &IDebug::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"},
122 {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"},
123 {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"},
124 {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"},
125 {200, &IDebug::GetAll, "GetAll"},
126 {201, &IDebug::SetAll, "SetAll"},
127 {202, &IDebug::FlushDebug, "FlushDebug"},
128 {203, &IDebug::BreakTag, "BreakTag"},
129 {204, nullptr, "ReadBackupData"},
130 {205, nullptr, "WriteBackupData"},
131 {206, nullptr, "WriteNtf"},
132 };
133 // clang-format on
134
135 RegisterHandlers(functions);
136 }
137};
138
12class IUserManager final : public ServiceFramework<IUserManager> { 139class IUserManager final : public ServiceFramework<IUserManager> {
13public: 140public:
14 explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} { 141 explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} {
@@ -37,10 +164,68 @@ private:
37 std::shared_ptr<IUser> user_interface; 164 std::shared_ptr<IUser> user_interface;
38}; 165};
39 166
167class ISystemManager final : public ServiceFramework<ISystemManager> {
168public:
169 explicit ISystemManager(Core::System& system_) : ServiceFramework{system_, "nfp:sys"} {
170 // clang-format off
171 static const FunctionInfo functions[] = {
172 {0, &ISystemManager::CreateSystemInterface, "CreateSystemInterface"},
173 };
174 // clang-format on
175
176 RegisterHandlers(functions);
177 }
178
179private:
180 void CreateSystemInterface(HLERequestContext& ctx) {
181 LOG_DEBUG(Service_NFP, "called");
182
183 if (system_interface == nullptr) {
184 system_interface = std::make_shared<ISystem>(system);
185 }
186
187 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
188 rb.Push(ResultSuccess);
189 rb.PushIpcInterface<ISystem>(system_interface);
190 }
191
192 std::shared_ptr<ISystem> system_interface;
193};
194
195class IDebugManager final : public ServiceFramework<IDebugManager> {
196public:
197 explicit IDebugManager(Core::System& system_) : ServiceFramework{system_, "nfp:dbg"} {
198 // clang-format off
199 static const FunctionInfo functions[] = {
200 {0, &IDebugManager::CreateDebugInterface, "CreateDebugInterface"},
201 };
202 // clang-format on
203
204 RegisterHandlers(functions);
205 }
206
207private:
208 void CreateDebugInterface(HLERequestContext& ctx) {
209 LOG_DEBUG(Service_NFP, "called");
210
211 if (system_interface == nullptr) {
212 system_interface = std::make_shared<IDebug>(system);
213 }
214
215 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
216 rb.Push(ResultSuccess);
217 rb.PushIpcInterface<IDebug>(system_interface);
218 }
219
220 std::shared_ptr<IDebug> system_interface;
221};
222
40void LoopProcess(Core::System& system) { 223void LoopProcess(Core::System& system) {
41 auto server_manager = std::make_unique<ServerManager>(system); 224 auto server_manager = std::make_unique<ServerManager>(system);
42 225
43 server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system)); 226 server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system));
227 server_manager->RegisterNamedService("nfp:sys", std::make_shared<ISystemManager>(system));
228 server_manager->RegisterNamedService("nfp:dbg", std::make_shared<IDebugManager>(system));
44 ServerManager::RunServer(std::move(server_manager)); 229 ServerManager::RunServer(std::move(server_manager));
45} 230}
46 231
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
index 607e70968..3f9af53c8 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfp/nfp_device.cpp
@@ -29,7 +29,6 @@
29#include "core/hle/service/nfp/amiibo_crypto.h" 29#include "core/hle/service/nfp/amiibo_crypto.h"
30#include "core/hle/service/nfp/nfp_device.h" 30#include "core/hle/service/nfp/nfp_device.h"
31#include "core/hle/service/nfp/nfp_result.h" 31#include "core/hle/service/nfp/nfp_result.h"
32#include "core/hle/service/nfp/nfp_user.h"
33#include "core/hle/service/time/time_manager.h" 32#include "core/hle/service/time/time_manager.h"
34#include "core/hle/service/time/time_zone_content_manager.h" 33#include "core/hle/service/time/time_zone_content_manager.h"
35#include "core/hle/service/time/time_zone_types.h" 34#include "core/hle/service/time/time_zone_types.h"
@@ -241,6 +240,42 @@ Result NfpDevice::Flush() {
241 240
242 tag_data.write_counter++; 241 tag_data.write_counter++;
243 242
243 FlushWithBreak(BreakType::Normal);
244
245 is_data_moddified = false;
246
247 return ResultSuccess;
248}
249
250Result NfpDevice::FlushDebug() {
251 if (device_state != DeviceState::TagMounted) {
252 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
253 if (device_state == DeviceState::TagRemoved) {
254 return TagRemoved;
255 }
256 return WrongDeviceState;
257 }
258
259 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
260 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
261 return WrongDeviceState;
262 }
263
264 tag_data.write_counter++;
265
266 FlushWithBreak(BreakType::Normal);
267
268 is_data_moddified = false;
269
270 return ResultSuccess;
271}
272
273Result NfpDevice::FlushWithBreak(BreakType break_type) {
274 if (break_type != BreakType::Normal) {
275 LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
276 return WrongDeviceState;
277 }
278
244 std::vector<u8> data(sizeof(EncryptedNTAG215File)); 279 std::vector<u8> data(sizeof(EncryptedNTAG215File));
245 if (is_plain_amiibo) { 280 if (is_plain_amiibo) {
246 memcpy(data.data(), &tag_data, sizeof(tag_data)); 281 memcpy(data.data(), &tag_data, sizeof(tag_data));
@@ -258,8 +293,6 @@ Result NfpDevice::Flush() {
258 return WriteAmiiboFailed; 293 return WriteAmiiboFailed;
259 } 294 }
260 295
261 is_data_moddified = false;
262
263 return ResultSuccess; 296 return ResultSuccess;
264} 297}
265 298
@@ -417,6 +450,38 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
417 return ResultSuccess; 450 return ResultSuccess;
418} 451}
419 452
453Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const {
454 if (device_state != DeviceState::TagMounted) {
455 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
456 if (device_state == DeviceState::TagRemoved) {
457 return TagRemoved;
458 }
459 return WrongDeviceState;
460 }
461
462 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
463 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
464 return WrongDeviceState;
465 }
466
467 if (tag_data.settings.settings.amiibo_initialized == 0) {
468 return RegistrationIsNotInitialized;
469 }
470
471 Service::Mii::MiiManager manager;
472 const auto& settings = tag_data.settings;
473
474 // TODO: Validate and complete this data
475 register_info = {
476 .mii_store_data = {},
477 .creation_date = settings.init_date.GetWriteDate(),
478 .amiibo_name = GetAmiiboName(settings),
479 .font_region = settings.settings.font_region,
480 };
481
482 return ResultSuccess;
483}
484
420Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { 485Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
421 if (device_state != DeviceState::TagMounted) { 486 if (device_state != DeviceState::TagMounted) {
422 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 487 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
@@ -807,6 +872,159 @@ Result NfpDevice::DeleteApplicationArea() {
807 return Flush(); 872 return Flush();
808} 873}
809 874
875Result NfpDevice::ExistApplicationArea(bool& has_application_area) {
876 if (device_state != DeviceState::TagMounted) {
877 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
878 if (device_state == DeviceState::TagRemoved) {
879 return TagRemoved;
880 }
881 return WrongDeviceState;
882 }
883
884 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
885 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
886 return WrongDeviceState;
887 }
888
889 has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
890
891 return ResultSuccess;
892}
893
894Result NfpDevice::GetAll(NfpData& data) const {
895 if (device_state != DeviceState::TagMounted) {
896 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
897 if (device_state == DeviceState::TagRemoved) {
898 return TagRemoved;
899 }
900 return WrongDeviceState;
901 }
902
903 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
904 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
905 return WrongDeviceState;
906 }
907
908 CommonInfo common_info{};
909 Service::Mii::MiiManager manager;
910 const u64 application_id = tag_data.application_id;
911
912 GetCommonInfo(common_info);
913
914 data = {
915 .magic = tag_data.constant_value,
916 .write_counter = tag_data.write_counter,
917 .settings_crc = tag_data.settings.crc,
918 .common_info = common_info,
919 .mii_char_info = tag_data.owner_mii,
920 .mii_store_data_extension = tag_data.mii_extension,
921 .creation_date = tag_data.settings.init_date.GetWriteDate(),
922 .amiibo_name = tag_data.settings.amiibo_name,
923 .amiibo_name_null_terminated = 0,
924 .settings = tag_data.settings.settings,
925 .unknown1 = tag_data.unknown,
926 .register_info_crc = tag_data.register_info_crc,
927 .unknown2 = tag_data.unknown2,
928 .application_id = application_id,
929 .access_id = tag_data.application_area_id,
930 .settings_crc_counter = tag_data.settings.crc_counter,
931 .font_region = tag_data.settings.settings.font_region,
932 .tag_type = PackedTagType::Type2,
933 .console_type =
934 static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf),
935 .application_id_byte = tag_data.application_id_byte,
936 .application_area = tag_data.application_area,
937 };
938
939 return ResultSuccess;
940}
941
942Result NfpDevice::SetAll(const NfpData& data) {
943 if (device_state != DeviceState::TagMounted) {
944 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
945 if (device_state == DeviceState::TagRemoved) {
946 return TagRemoved;
947 }
948 return WrongDeviceState;
949 }
950
951 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
952 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
953 return WrongDeviceState;
954 }
955
956 tag_data.constant_value = data.magic;
957 tag_data.write_counter = data.write_counter;
958 tag_data.settings.crc = data.settings_crc;
959 tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date);
960 tag_data.write_counter = data.common_info.write_counter;
961 tag_data.amiibo_version = data.common_info.version;
962 tag_data.owner_mii = data.mii_char_info;
963 tag_data.mii_extension = data.mii_store_data_extension;
964 tag_data.settings.init_date.SetWriteDate(data.creation_date);
965 tag_data.settings.amiibo_name = data.amiibo_name;
966 tag_data.settings.settings = data.settings;
967 tag_data.unknown = data.unknown1;
968 tag_data.register_info_crc = data.register_info_crc;
969 tag_data.unknown2 = data.unknown2;
970 tag_data.application_id = data.application_id;
971 tag_data.application_area_id = data.access_id;
972 tag_data.settings.crc_counter = data.settings_crc_counter;
973 tag_data.settings.settings.font_region.Assign(data.font_region);
974 tag_data.application_id_byte = data.application_id_byte;
975 tag_data.application_area = data.application_area;
976
977 return ResultSuccess;
978}
979
980Result NfpDevice::BreakTag(BreakType break_type) {
981 if (device_state != DeviceState::TagMounted) {
982 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
983 if (device_state == DeviceState::TagRemoved) {
984 return TagRemoved;
985 }
986 return WrongDeviceState;
987 }
988
989 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
990 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
991 return WrongDeviceState;
992 }
993
994 // TODO: Complete this implementation
995
996 return FlushWithBreak(break_type);
997}
998
999Result NfpDevice::ReadBackupData() {
1000 // Not implemented
1001 return ResultSuccess;
1002}
1003
1004Result NfpDevice::WriteBackupData() {
1005 // Not implemented
1006 return ResultSuccess;
1007}
1008
1009Result NfpDevice::WriteNtf() {
1010 if (device_state != DeviceState::TagMounted) {
1011 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
1012 if (device_state == DeviceState::TagRemoved) {
1013 return TagRemoved;
1014 }
1015 return WrongDeviceState;
1016 }
1017
1018 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
1019 LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
1020 return WrongDeviceState;
1021 }
1022
1023 // Not implemented
1024
1025 return ResultSuccess;
1026}
1027
810u64 NfpDevice::GetHandle() const { 1028u64 NfpDevice::GetHandle() const {
811 // Generate a handle based of the npad id 1029 // Generate a handle based of the npad id
812 return static_cast<u64>(npad_id); 1030 return static_cast<u64>(npad_id);
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
index 7f963730d..bab05538a 100644
--- a/src/core/hle/service/nfp/nfp_device.h
+++ b/src/core/hle/service/nfp/nfp_device.h
@@ -41,12 +41,16 @@ public:
41 Result StopDetection(); 41 Result StopDetection();
42 Result Mount(MountTarget mount_target); 42 Result Mount(MountTarget mount_target);
43 Result Unmount(); 43 Result Unmount();
44
44 Result Flush(); 45 Result Flush();
46 Result FlushDebug();
47 Result FlushWithBreak(BreakType break_type);
45 48
46 Result GetTagInfo(TagInfo& tag_info) const; 49 Result GetTagInfo(TagInfo& tag_info) const;
47 Result GetCommonInfo(CommonInfo& common_info) const; 50 Result GetCommonInfo(CommonInfo& common_info) const;
48 Result GetModelInfo(ModelInfo& model_info) const; 51 Result GetModelInfo(ModelInfo& model_info) const;
49 Result GetRegisterInfo(RegisterInfo& register_info) const; 52 Result GetRegisterInfo(RegisterInfo& register_info) const;
53 Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const;
50 Result GetAdminInfo(AdminInfo& admin_info) const; 54 Result GetAdminInfo(AdminInfo& admin_info) const;
51 55
52 Result DeleteRegisterInfo(); 56 Result DeleteRegisterInfo();
@@ -61,6 +65,14 @@ public:
61 Result CreateApplicationArea(u32 access_id, std::span<const u8> data); 65 Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
62 Result RecreateApplicationArea(u32 access_id, std::span<const u8> data); 66 Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
63 Result DeleteApplicationArea(); 67 Result DeleteApplicationArea();
68 Result ExistApplicationArea(bool& has_application_area);
69
70 Result GetAll(NfpData& data) const;
71 Result SetAll(const NfpData& data);
72 Result BreakTag(BreakType break_type);
73 Result ReadBackupData();
74 Result WriteBackupData();
75 Result WriteNtf();
64 76
65 u64 GetHandle() const; 77 u64 GetHandle() const;
66 u32 GetApplicationAreaSize() const; 78 u32 GetApplicationAreaSize() const;
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 4e8534113..2ed8bb1ba 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -7,42 +7,13 @@
7#include "core/hle/kernel/k_event.h" 7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nfp/nfp_device.h" 9#include "core/hle/service/nfp/nfp_device.h"
10#include "core/hle/service/nfp/nfp_interface.h"
10#include "core/hle/service/nfp/nfp_result.h" 11#include "core/hle/service/nfp/nfp_result.h"
11#include "core/hle/service/nfp/nfp_user.h"
12 12
13namespace Service::NFP { 13namespace Service::NFP {
14 14
15IUser::IUser(Core::System& system_) 15Interface::Interface(Core::System& system_, const char* name)
16 : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name} { 16 : ServiceFramework{system_, name}, service_context{system_, service_name} {
17 static const FunctionInfo functions[] = {
18 {0, &IUser::Initialize, "Initialize"},
19 {1, &IUser::Finalize, "Finalize"},
20 {2, &IUser::ListDevices, "ListDevices"},
21 {3, &IUser::StartDetection, "StartDetection"},
22 {4, &IUser::StopDetection, "StopDetection"},
23 {5, &IUser::Mount, "Mount"},
24 {6, &IUser::Unmount, "Unmount"},
25 {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
26 {8, &IUser::GetApplicationArea, "GetApplicationArea"},
27 {9, &IUser::SetApplicationArea, "SetApplicationArea"},
28 {10, &IUser::Flush, "Flush"},
29 {11, &IUser::Restore, "Restore"},
30 {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
31 {13, &IUser::GetTagInfo, "GetTagInfo"},
32 {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
33 {15, &IUser::GetCommonInfo, "GetCommonInfo"},
34 {16, &IUser::GetModelInfo, "GetModelInfo"},
35 {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
36 {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
37 {19, &IUser::GetState, "GetState"},
38 {20, &IUser::GetDeviceState, "GetDeviceState"},
39 {21, &IUser::GetNpadId, "GetNpadId"},
40 {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
41 {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
42 {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
43 };
44 RegisterHandlers(functions);
45
46 availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); 17 availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
47 18
48 for (u32 device_index = 0; device_index < 10; device_index++) { 19 for (u32 device_index = 0; device_index < 10; device_index++) {
@@ -52,11 +23,37 @@ IUser::IUser(Core::System& system_)
52 } 23 }
53} 24}
54 25
55IUser ::~IUser() { 26Interface::~Interface() {
56 availability_change_event->Close(); 27 availability_change_event->Close();
57} 28}
58 29
59void IUser::Initialize(HLERequestContext& ctx) { 30void Interface::Initialize(HLERequestContext& ctx) {
31 LOG_INFO(Service_NFP, "called");
32
33 state = State::Initialized;
34
35 for (auto& device : devices) {
36 device->Initialize();
37 }
38
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(ResultSuccess);
41}
42
43void Interface::InitializeSystem(HLERequestContext& ctx) {
44 LOG_INFO(Service_NFP, "called");
45
46 state = State::Initialized;
47
48 for (auto& device : devices) {
49 device->Initialize();
50 }
51
52 IPC::ResponseBuilder rb{ctx, 2};
53 rb.Push(ResultSuccess);
54}
55
56void Interface::InitializeDebug(HLERequestContext& ctx) {
60 LOG_INFO(Service_NFP, "called"); 57 LOG_INFO(Service_NFP, "called");
61 58
62 state = State::Initialized; 59 state = State::Initialized;
@@ -69,7 +66,7 @@ void IUser::Initialize(HLERequestContext& ctx) {
69 rb.Push(ResultSuccess); 66 rb.Push(ResultSuccess);
70} 67}
71 68
72void IUser::Finalize(HLERequestContext& ctx) { 69void Interface::Finalize(HLERequestContext& ctx) {
73 LOG_INFO(Service_NFP, "called"); 70 LOG_INFO(Service_NFP, "called");
74 71
75 state = State::NonInitialized; 72 state = State::NonInitialized;
@@ -82,7 +79,33 @@ void IUser::Finalize(HLERequestContext& ctx) {
82 rb.Push(ResultSuccess); 79 rb.Push(ResultSuccess);
83} 80}
84 81
85void IUser::ListDevices(HLERequestContext& ctx) { 82void Interface::FinalizeSystem(HLERequestContext& ctx) {
83 LOG_INFO(Service_NFP, "called");
84
85 state = State::NonInitialized;
86
87 for (auto& device : devices) {
88 device->Finalize();
89 }
90
91 IPC::ResponseBuilder rb{ctx, 2};
92 rb.Push(ResultSuccess);
93}
94
95void Interface::FinalizeDebug(HLERequestContext& ctx) {
96 LOG_INFO(Service_NFP, "called");
97
98 state = State::NonInitialized;
99
100 for (auto& device : devices) {
101 device->Finalize();
102 }
103
104 IPC::ResponseBuilder rb{ctx, 2};
105 rb.Push(ResultSuccess);
106}
107
108void Interface::ListDevices(HLERequestContext& ctx) {
86 LOG_DEBUG(Service_NFP, "called"); 109 LOG_DEBUG(Service_NFP, "called");
87 110
88 if (state == State::NonInitialized) { 111 if (state == State::NonInitialized) {
@@ -128,7 +151,7 @@ void IUser::ListDevices(HLERequestContext& ctx) {
128 rb.Push(static_cast<s32>(nfp_devices.size())); 151 rb.Push(static_cast<s32>(nfp_devices.size()));
129} 152}
130 153
131void IUser::StartDetection(HLERequestContext& ctx) { 154void Interface::StartDetection(HLERequestContext& ctx) {
132 IPC::RequestParser rp{ctx}; 155 IPC::RequestParser rp{ctx};
133 const auto device_handle{rp.Pop<u64>()}; 156 const auto device_handle{rp.Pop<u64>()};
134 const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; 157 const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
@@ -153,7 +176,7 @@ void IUser::StartDetection(HLERequestContext& ctx) {
153 rb.Push(result); 176 rb.Push(result);
154} 177}
155 178
156void IUser::StopDetection(HLERequestContext& ctx) { 179void Interface::StopDetection(HLERequestContext& ctx) {
157 IPC::RequestParser rp{ctx}; 180 IPC::RequestParser rp{ctx};
158 const auto device_handle{rp.Pop<u64>()}; 181 const auto device_handle{rp.Pop<u64>()};
159 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 182 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -177,7 +200,7 @@ void IUser::StopDetection(HLERequestContext& ctx) {
177 rb.Push(result); 200 rb.Push(result);
178} 201}
179 202
180void IUser::Mount(HLERequestContext& ctx) { 203void Interface::Mount(HLERequestContext& ctx) {
181 IPC::RequestParser rp{ctx}; 204 IPC::RequestParser rp{ctx};
182 const auto device_handle{rp.Pop<u64>()}; 205 const auto device_handle{rp.Pop<u64>()};
183 const auto model_type{rp.PopEnum<ModelType>()}; 206 const auto model_type{rp.PopEnum<ModelType>()};
@@ -204,7 +227,7 @@ void IUser::Mount(HLERequestContext& ctx) {
204 rb.Push(result); 227 rb.Push(result);
205} 228}
206 229
207void IUser::Unmount(HLERequestContext& ctx) { 230void Interface::Unmount(HLERequestContext& ctx) {
208 IPC::RequestParser rp{ctx}; 231 IPC::RequestParser rp{ctx};
209 const auto device_handle{rp.Pop<u64>()}; 232 const auto device_handle{rp.Pop<u64>()};
210 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 233 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -228,7 +251,7 @@ void IUser::Unmount(HLERequestContext& ctx) {
228 rb.Push(result); 251 rb.Push(result);
229} 252}
230 253
231void IUser::OpenApplicationArea(HLERequestContext& ctx) { 254void Interface::OpenApplicationArea(HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 255 IPC::RequestParser rp{ctx};
233 const auto device_handle{rp.Pop<u64>()}; 256 const auto device_handle{rp.Pop<u64>()};
234 const auto access_id{rp.Pop<u32>()}; 257 const auto access_id{rp.Pop<u32>()};
@@ -253,7 +276,7 @@ void IUser::OpenApplicationArea(HLERequestContext& ctx) {
253 rb.Push(result); 276 rb.Push(result);
254} 277}
255 278
256void IUser::GetApplicationArea(HLERequestContext& ctx) { 279void Interface::GetApplicationArea(HLERequestContext& ctx) {
257 IPC::RequestParser rp{ctx}; 280 IPC::RequestParser rp{ctx};
258 const auto device_handle{rp.Pop<u64>()}; 281 const auto device_handle{rp.Pop<u64>()};
259 const auto data_size = ctx.GetWriteBufferSize(); 282 const auto data_size = ctx.GetWriteBufferSize();
@@ -287,7 +310,7 @@ void IUser::GetApplicationArea(HLERequestContext& ctx) {
287 rb.Push(static_cast<u32>(data_size)); 310 rb.Push(static_cast<u32>(data_size));
288} 311}
289 312
290void IUser::SetApplicationArea(HLERequestContext& ctx) { 313void Interface::SetApplicationArea(HLERequestContext& ctx) {
291 IPC::RequestParser rp{ctx}; 314 IPC::RequestParser rp{ctx};
292 const auto device_handle{rp.Pop<u64>()}; 315 const auto device_handle{rp.Pop<u64>()};
293 const auto data{ctx.ReadBuffer()}; 316 const auto data{ctx.ReadBuffer()};
@@ -318,7 +341,7 @@ void IUser::SetApplicationArea(HLERequestContext& ctx) {
318 rb.Push(result); 341 rb.Push(result);
319} 342}
320 343
321void IUser::Flush(HLERequestContext& ctx) { 344void Interface::Flush(HLERequestContext& ctx) {
322 IPC::RequestParser rp{ctx}; 345 IPC::RequestParser rp{ctx};
323 const auto device_handle{rp.Pop<u64>()}; 346 const auto device_handle{rp.Pop<u64>()};
324 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 347 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -342,7 +365,7 @@ void IUser::Flush(HLERequestContext& ctx) {
342 rb.Push(result); 365 rb.Push(result);
343} 366}
344 367
345void IUser::Restore(HLERequestContext& ctx) { 368void Interface::Restore(HLERequestContext& ctx) {
346 IPC::RequestParser rp{ctx}; 369 IPC::RequestParser rp{ctx};
347 const auto device_handle{rp.Pop<u64>()}; 370 const auto device_handle{rp.Pop<u64>()};
348 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); 371 LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
@@ -366,7 +389,7 @@ void IUser::Restore(HLERequestContext& ctx) {
366 rb.Push(result); 389 rb.Push(result);
367} 390}
368 391
369void IUser::CreateApplicationArea(HLERequestContext& ctx) { 392void Interface::CreateApplicationArea(HLERequestContext& ctx) {
370 IPC::RequestParser rp{ctx}; 393 IPC::RequestParser rp{ctx};
371 const auto device_handle{rp.Pop<u64>()}; 394 const auto device_handle{rp.Pop<u64>()};
372 const auto access_id{rp.Pop<u32>()}; 395 const auto access_id{rp.Pop<u32>()};
@@ -399,7 +422,7 @@ void IUser::CreateApplicationArea(HLERequestContext& ctx) {
399 rb.Push(result); 422 rb.Push(result);
400} 423}
401 424
402void IUser::GetTagInfo(HLERequestContext& ctx) { 425void Interface::GetTagInfo(HLERequestContext& ctx) {
403 IPC::RequestParser rp{ctx}; 426 IPC::RequestParser rp{ctx};
404 const auto device_handle{rp.Pop<u64>()}; 427 const auto device_handle{rp.Pop<u64>()};
405 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 428 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -425,7 +448,7 @@ void IUser::GetTagInfo(HLERequestContext& ctx) {
425 rb.Push(result); 448 rb.Push(result);
426} 449}
427 450
428void IUser::GetRegisterInfo(HLERequestContext& ctx) { 451void Interface::GetRegisterInfo(HLERequestContext& ctx) {
429 IPC::RequestParser rp{ctx}; 452 IPC::RequestParser rp{ctx};
430 const auto device_handle{rp.Pop<u64>()}; 453 const auto device_handle{rp.Pop<u64>()};
431 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 454 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -451,7 +474,7 @@ void IUser::GetRegisterInfo(HLERequestContext& ctx) {
451 rb.Push(result); 474 rb.Push(result);
452} 475}
453 476
454void IUser::GetCommonInfo(HLERequestContext& ctx) { 477void Interface::GetCommonInfo(HLERequestContext& ctx) {
455 IPC::RequestParser rp{ctx}; 478 IPC::RequestParser rp{ctx};
456 const auto device_handle{rp.Pop<u64>()}; 479 const auto device_handle{rp.Pop<u64>()};
457 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 480 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -477,7 +500,7 @@ void IUser::GetCommonInfo(HLERequestContext& ctx) {
477 rb.Push(result); 500 rb.Push(result);
478} 501}
479 502
480void IUser::GetModelInfo(HLERequestContext& ctx) { 503void Interface::GetModelInfo(HLERequestContext& ctx) {
481 IPC::RequestParser rp{ctx}; 504 IPC::RequestParser rp{ctx};
482 const auto device_handle{rp.Pop<u64>()}; 505 const auto device_handle{rp.Pop<u64>()};
483 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 506 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
@@ -503,7 +526,7 @@ void IUser::GetModelInfo(HLERequestContext& ctx) {
503 rb.Push(result); 526 rb.Push(result);
504} 527}
505 528
506void IUser::AttachActivateEvent(HLERequestContext& ctx) { 529void Interface::AttachActivateEvent(HLERequestContext& ctx) {
507 IPC::RequestParser rp{ctx}; 530 IPC::RequestParser rp{ctx};
508 const auto device_handle{rp.Pop<u64>()}; 531 const auto device_handle{rp.Pop<u64>()};
509 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 532 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
@@ -527,7 +550,7 @@ void IUser::AttachActivateEvent(HLERequestContext& ctx) {
527 rb.PushCopyObjects(device.value()->GetActivateEvent()); 550 rb.PushCopyObjects(device.value()->GetActivateEvent());
528} 551}
529 552
530void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { 553void Interface::AttachDeactivateEvent(HLERequestContext& ctx) {
531 IPC::RequestParser rp{ctx}; 554 IPC::RequestParser rp{ctx};
532 const auto device_handle{rp.Pop<u64>()}; 555 const auto device_handle{rp.Pop<u64>()};
533 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 556 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
@@ -551,7 +574,7 @@ void IUser::AttachDeactivateEvent(HLERequestContext& ctx) {
551 rb.PushCopyObjects(device.value()->GetDeactivateEvent()); 574 rb.PushCopyObjects(device.value()->GetDeactivateEvent());
552} 575}
553 576
554void IUser::GetState(HLERequestContext& ctx) { 577void Interface::GetState(HLERequestContext& ctx) {
555 LOG_DEBUG(Service_NFP, "called"); 578 LOG_DEBUG(Service_NFP, "called");
556 579
557 IPC::ResponseBuilder rb{ctx, 3}; 580 IPC::ResponseBuilder rb{ctx, 3};
@@ -559,7 +582,7 @@ void IUser::GetState(HLERequestContext& ctx) {
559 rb.PushEnum(state); 582 rb.PushEnum(state);
560} 583}
561 584
562void IUser::GetDeviceState(HLERequestContext& ctx) { 585void Interface::GetDeviceState(HLERequestContext& ctx) {
563 IPC::RequestParser rp{ctx}; 586 IPC::RequestParser rp{ctx};
564 const auto device_handle{rp.Pop<u64>()}; 587 const auto device_handle{rp.Pop<u64>()};
565 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 588 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
@@ -577,7 +600,7 @@ void IUser::GetDeviceState(HLERequestContext& ctx) {
577 rb.PushEnum(device.value()->GetCurrentState()); 600 rb.PushEnum(device.value()->GetCurrentState());
578} 601}
579 602
580void IUser::GetNpadId(HLERequestContext& ctx) { 603void Interface::GetNpadId(HLERequestContext& ctx) {
581 IPC::RequestParser rp{ctx}; 604 IPC::RequestParser rp{ctx};
582 const auto device_handle{rp.Pop<u64>()}; 605 const auto device_handle{rp.Pop<u64>()};
583 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 606 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
@@ -601,7 +624,7 @@ void IUser::GetNpadId(HLERequestContext& ctx) {
601 rb.PushEnum(device.value()->GetNpadId()); 624 rb.PushEnum(device.value()->GetNpadId());
602} 625}
603 626
604void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { 627void Interface::GetApplicationAreaSize(HLERequestContext& ctx) {
605 IPC::RequestParser rp{ctx}; 628 IPC::RequestParser rp{ctx};
606 const auto device_handle{rp.Pop<u64>()}; 629 const auto device_handle{rp.Pop<u64>()};
607 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); 630 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
@@ -619,7 +642,7 @@ void IUser::GetApplicationAreaSize(HLERequestContext& ctx) {
619 rb.Push(device.value()->GetApplicationAreaSize()); 642 rb.Push(device.value()->GetApplicationAreaSize());
620} 643}
621 644
622void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { 645void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
623 LOG_INFO(Service_NFP, "called"); 646 LOG_INFO(Service_NFP, "called");
624 647
625 if (state == State::NonInitialized) { 648 if (state == State::NonInitialized) {
@@ -633,7 +656,7 @@ void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
633 rb.PushCopyObjects(availability_change_event->GetReadableEvent()); 656 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
634} 657}
635 658
636void IUser::RecreateApplicationArea(HLERequestContext& ctx) { 659void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
637 IPC::RequestParser rp{ctx}; 660 IPC::RequestParser rp{ctx};
638 const auto device_handle{rp.Pop<u64>()}; 661 const auto device_handle{rp.Pop<u64>()};
639 const auto access_id{rp.Pop<u32>()}; 662 const auto access_id{rp.Pop<u32>()};
@@ -660,7 +683,361 @@ void IUser::RecreateApplicationArea(HLERequestContext& ctx) {
660 rb.Push(result); 683 rb.Push(result);
661} 684}
662 685
663std::optional<std::shared_ptr<NfpDevice>> IUser::GetNfpDevice(u64 handle) { 686void Interface::Format(HLERequestContext& ctx) {
687 IPC::RequestParser rp{ctx};
688 const auto device_handle{rp.Pop<u64>()};
689 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
690
691 if (state == State::NonInitialized) {
692 IPC::ResponseBuilder rb{ctx, 2};
693 rb.Push(NfcDisabled);
694 return;
695 }
696
697 auto device = GetNfpDevice(device_handle);
698
699 if (!device.has_value()) {
700 IPC::ResponseBuilder rb{ctx, 2};
701 rb.Push(DeviceNotFound);
702 return;
703 }
704
705 const auto result = device.value()->Format();
706 IPC::ResponseBuilder rb{ctx, 2};
707 rb.Push(result);
708}
709
710void Interface::GetAdminInfo(HLERequestContext& ctx) {
711 IPC::RequestParser rp{ctx};
712 const auto device_handle{rp.Pop<u64>()};
713 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
714
715 if (state == State::NonInitialized) {
716 IPC::ResponseBuilder rb{ctx, 2};
717 rb.Push(NfcDisabled);
718 return;
719 }
720
721 auto device = GetNfpDevice(device_handle);
722
723 if (!device.has_value()) {
724 IPC::ResponseBuilder rb{ctx, 2};
725 rb.Push(DeviceNotFound);
726 return;
727 }
728
729 AdminInfo admin_info{};
730 const auto result = device.value()->GetAdminInfo(admin_info);
731 ctx.WriteBuffer(admin_info);
732 IPC::ResponseBuilder rb{ctx, 2};
733 rb.Push(result);
734}
735
736void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) {
737 IPC::RequestParser rp{ctx};
738 const auto device_handle{rp.Pop<u64>()};
739 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
740
741 if (state == State::NonInitialized) {
742 IPC::ResponseBuilder rb{ctx, 2};
743 rb.Push(NfcDisabled);
744 return;
745 }
746
747 auto device = GetNfpDevice(device_handle);
748
749 if (!device.has_value()) {
750 IPC::ResponseBuilder rb{ctx, 2};
751 rb.Push(DeviceNotFound);
752 return;
753 }
754
755 RegisterInfoPrivate register_info{};
756 const auto result = device.value()->GetRegisterInfoPrivate(register_info);
757 ctx.WriteBuffer(register_info);
758 IPC::ResponseBuilder rb{ctx, 2};
759 rb.Push(result);
760}
761
762void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) {
763 IPC::RequestParser rp{ctx};
764 const auto device_handle{rp.Pop<u64>()};
765 const auto buffer{ctx.ReadBuffer()};
766 LOG_DEBUG(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle,
767 buffer.size());
768
769 if (state == State::NonInitialized) {
770 IPC::ResponseBuilder rb{ctx, 2};
771 rb.Push(NfcDisabled);
772 return;
773 }
774
775 auto device = GetNfpDevice(device_handle);
776
777 if (!device.has_value()) {
778 IPC::ResponseBuilder rb{ctx, 2};
779 rb.Push(DeviceNotFound);
780 return;
781 }
782
783 const auto result = device.value()->SetRegisterInfoPrivate({});
784 IPC::ResponseBuilder rb{ctx, 2};
785 rb.Push(result);
786}
787
788void Interface::DeleteRegisterInfo(HLERequestContext& ctx) {
789 IPC::RequestParser rp{ctx};
790 const auto device_handle{rp.Pop<u64>()};
791 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
792
793 if (state == State::NonInitialized) {
794 IPC::ResponseBuilder rb{ctx, 2};
795 rb.Push(NfcDisabled);
796 return;
797 }
798
799 auto device = GetNfpDevice(device_handle);
800
801 if (!device.has_value()) {
802 IPC::ResponseBuilder rb{ctx, 2};
803 rb.Push(DeviceNotFound);
804 return;
805 }
806
807 const auto result = device.value()->DeleteRegisterInfo();
808 IPC::ResponseBuilder rb{ctx, 2};
809 rb.Push(result);
810}
811
812void Interface::DeleteApplicationArea(HLERequestContext& ctx) {
813 IPC::RequestParser rp{ctx};
814 const auto device_handle{rp.Pop<u64>()};
815 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
816
817 if (state == State::NonInitialized) {
818 IPC::ResponseBuilder rb{ctx, 2};
819 rb.Push(NfcDisabled);
820 return;
821 }
822
823 auto device = GetNfpDevice(device_handle);
824
825 if (!device.has_value()) {
826 IPC::ResponseBuilder rb{ctx, 2};
827 rb.Push(DeviceNotFound);
828 return;
829 }
830
831 const auto result = device.value()->DeleteApplicationArea();
832 IPC::ResponseBuilder rb{ctx, 2};
833 rb.Push(result);
834}
835
836void Interface::ExistsApplicationArea(HLERequestContext& ctx) {
837 IPC::RequestParser rp{ctx};
838 const auto device_handle{rp.Pop<u64>()};
839 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
840
841 if (state == State::NonInitialized) {
842 IPC::ResponseBuilder rb{ctx, 2};
843 rb.Push(NfcDisabled);
844 return;
845 }
846
847 auto device = GetNfpDevice(device_handle);
848
849 if (!device.has_value()) {
850 IPC::ResponseBuilder rb{ctx, 2};
851 rb.Push(DeviceNotFound);
852 return;
853 }
854
855 bool has_application_area = false;
856 const auto result = device.value()->ExistApplicationArea(has_application_area);
857 IPC::ResponseBuilder rb{ctx, 3};
858 rb.Push(result);
859 rb.Push(has_application_area);
860}
861
862void Interface::GetAll(HLERequestContext& ctx) {
863 IPC::RequestParser rp{ctx};
864 const auto device_handle{rp.Pop<u64>()};
865 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
866
867 if (state == State::NonInitialized) {
868 IPC::ResponseBuilder rb{ctx, 2};
869 rb.Push(NfcDisabled);
870 return;
871 }
872
873 auto device = GetNfpDevice(device_handle);
874
875 if (!device.has_value()) {
876 IPC::ResponseBuilder rb{ctx, 2};
877 rb.Push(DeviceNotFound);
878 return;
879 }
880
881 NfpData data{};
882 const auto result = device.value()->GetAll(data);
883
884 ctx.WriteBuffer(data);
885
886 IPC::ResponseBuilder rb{ctx, 2};
887 rb.Push(result);
888}
889
890void Interface::SetAll(HLERequestContext& ctx) {
891 IPC::RequestParser rp{ctx};
892 const auto device_handle{rp.Pop<u64>()};
893 const auto nfp_data{ctx.ReadBuffer()};
894
895 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
896
897 if (state == State::NonInitialized) {
898 IPC::ResponseBuilder rb{ctx, 2};
899 rb.Push(NfcDisabled);
900 return;
901 }
902
903 auto device = GetNfpDevice(device_handle);
904
905 if (!device.has_value()) {
906 IPC::ResponseBuilder rb{ctx, 2};
907 rb.Push(DeviceNotFound);
908 return;
909 }
910
911 NfpData data{};
912 memcpy(&data, nfp_data.data(), sizeof(NfpData));
913
914 const auto result = device.value()->SetAll(data);
915 IPC::ResponseBuilder rb{ctx, 2};
916 rb.Push(result);
917}
918
919void Interface::FlushDebug(HLERequestContext& ctx) {
920 IPC::RequestParser rp{ctx};
921 const auto device_handle{rp.Pop<u64>()};
922 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
923
924 if (state == State::NonInitialized) {
925 IPC::ResponseBuilder rb{ctx, 2};
926 rb.Push(NfcDisabled);
927 return;
928 }
929
930 auto device = GetNfpDevice(device_handle);
931
932 if (!device.has_value()) {
933 IPC::ResponseBuilder rb{ctx, 2};
934 rb.Push(DeviceNotFound);
935 return;
936 }
937
938 const auto result = device.value()->FlushDebug();
939 IPC::ResponseBuilder rb{ctx, 2};
940 rb.Push(result);
941}
942
943void Interface::BreakTag(HLERequestContext& ctx) {
944 IPC::RequestParser rp{ctx};
945 const auto device_handle{rp.Pop<u64>()};
946 const auto break_type{rp.PopEnum<BreakType>()};
947 LOG_DEBUG(Service_NFP, "called, device_handle={}, break_type={}", device_handle, break_type);
948
949 if (state == State::NonInitialized) {
950 IPC::ResponseBuilder rb{ctx, 2};
951 rb.Push(NfcDisabled);
952 return;
953 }
954
955 auto device = GetNfpDevice(device_handle);
956
957 if (!device.has_value()) {
958 IPC::ResponseBuilder rb{ctx, 2};
959 rb.Push(DeviceNotFound);
960 return;
961 }
962
963 const auto result = device.value()->BreakTag(break_type);
964 IPC::ResponseBuilder rb{ctx, 2};
965 rb.Push(result);
966}
967
968void Interface::ReadBackupData(HLERequestContext& ctx) {
969 IPC::RequestParser rp{ctx};
970 const auto device_handle{rp.Pop<u64>()};
971 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
972
973 if (state == State::NonInitialized) {
974 IPC::ResponseBuilder rb{ctx, 2};
975 rb.Push(NfcDisabled);
976 return;
977 }
978
979 auto device = GetNfpDevice(device_handle);
980
981 if (!device.has_value()) {
982 IPC::ResponseBuilder rb{ctx, 2};
983 rb.Push(DeviceNotFound);
984 return;
985 }
986
987 const auto result = device.value()->ReadBackupData();
988 IPC::ResponseBuilder rb{ctx, 2};
989 rb.Push(result);
990}
991
992void Interface::WriteBackupData(HLERequestContext& ctx) {
993 IPC::RequestParser rp{ctx};
994 const auto device_handle{rp.Pop<u64>()};
995 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
996
997 if (state == State::NonInitialized) {
998 IPC::ResponseBuilder rb{ctx, 2};
999 rb.Push(NfcDisabled);
1000 return;
1001 }
1002
1003 auto device = GetNfpDevice(device_handle);
1004
1005 if (!device.has_value()) {
1006 IPC::ResponseBuilder rb{ctx, 2};
1007 rb.Push(DeviceNotFound);
1008 return;
1009 }
1010
1011 const auto result = device.value()->WriteBackupData();
1012 IPC::ResponseBuilder rb{ctx, 2};
1013 rb.Push(result);
1014}
1015
1016void Interface::WriteNtf(HLERequestContext& ctx) {
1017 IPC::RequestParser rp{ctx};
1018 const auto device_handle{rp.Pop<u64>()};
1019 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
1020
1021 if (state == State::NonInitialized) {
1022 IPC::ResponseBuilder rb{ctx, 2};
1023 rb.Push(NfcDisabled);
1024 return;
1025 }
1026
1027 auto device = GetNfpDevice(device_handle);
1028
1029 if (!device.has_value()) {
1030 IPC::ResponseBuilder rb{ctx, 2};
1031 rb.Push(DeviceNotFound);
1032 return;
1033 }
1034
1035 const auto result = device.value()->WriteNtf();
1036 IPC::ResponseBuilder rb{ctx, 2};
1037 rb.Push(result);
1038}
1039
1040std::optional<std::shared_ptr<NfpDevice>> Interface::GetNfpDevice(u64 handle) {
664 for (auto& device : devices) { 1041 for (auto& device : devices) {
665 if (device->GetHandle() == handle) { 1042 if (device->GetHandle() == handle) {
666 return device; 1043 return device;
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_interface.h
index 1f3ff2ea8..616c94b06 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_interface.h
@@ -13,19 +13,17 @@
13namespace Service::NFP { 13namespace Service::NFP {
14class NfpDevice; 14class NfpDevice;
15 15
16class IUser final : public ServiceFramework<IUser> { 16class Interface : public ServiceFramework<Interface> {
17public: 17public:
18 explicit IUser(Core::System& system_); 18 explicit Interface(Core::System& system_, const char* name);
19 ~IUser(); 19 ~Interface() override;
20
21private:
22 enum class State : u32 {
23 NonInitialized,
24 Initialized,
25 };
26 20
27 void Initialize(HLERequestContext& ctx); 21 void Initialize(HLERequestContext& ctx);
22 void InitializeSystem(HLERequestContext& ctx);
23 void InitializeDebug(HLERequestContext& ctx);
28 void Finalize(HLERequestContext& ctx); 24 void Finalize(HLERequestContext& ctx);
25 void FinalizeSystem(HLERequestContext& ctx);
26 void FinalizeDebug(HLERequestContext& ctx);
29 void ListDevices(HLERequestContext& ctx); 27 void ListDevices(HLERequestContext& ctx);
30 void StartDetection(HLERequestContext& ctx); 28 void StartDetection(HLERequestContext& ctx);
31 void StopDetection(HLERequestContext& ctx); 29 void StopDetection(HLERequestContext& ctx);
@@ -49,6 +47,26 @@ private:
49 void GetApplicationAreaSize(HLERequestContext& ctx); 47 void GetApplicationAreaSize(HLERequestContext& ctx);
50 void AttachAvailabilityChangeEvent(HLERequestContext& ctx); 48 void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
51 void RecreateApplicationArea(HLERequestContext& ctx); 49 void RecreateApplicationArea(HLERequestContext& ctx);
50 void Format(HLERequestContext& ctx);
51 void GetAdminInfo(HLERequestContext& ctx);
52 void GetRegisterInfoPrivate(HLERequestContext& ctx);
53 void SetRegisterInfoPrivate(HLERequestContext& ctx);
54 void DeleteRegisterInfo(HLERequestContext& ctx);
55 void DeleteApplicationArea(HLERequestContext& ctx);
56 void ExistsApplicationArea(HLERequestContext& ctx);
57 void GetAll(HLERequestContext& ctx);
58 void SetAll(HLERequestContext& ctx);
59 void FlushDebug(HLERequestContext& ctx);
60 void BreakTag(HLERequestContext& ctx);
61 void ReadBackupData(HLERequestContext& ctx);
62 void WriteBackupData(HLERequestContext& ctx);
63 void WriteNtf(HLERequestContext& ctx);
64
65private:
66 enum class State : u32 {
67 NonInitialized,
68 Initialized,
69 };
52 70
53 std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle); 71 std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle);
54 72
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 70c878552..1ef047cee 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -109,6 +109,12 @@ enum class AppAreaVersion : u8 {
109 NotSet = 0xFF, 109 NotSet = 0xFF,
110}; 110};
111 111
112enum class BreakType : u32 {
113 Normal,
114 Unknown1,
115 Unknown2,
116};
117
112enum class CabinetMode : u8 { 118enum class CabinetMode : u8 {
113 StartNicknameAndOwnerSettings, 119 StartNicknameAndOwnerSettings,
114 StartGameDataEraser, 120 StartGameDataEraser,
@@ -181,6 +187,12 @@ struct AmiiboDate {
181 }; 187 };
182 } 188 }
183 189
190 void SetWriteDate(const WriteDate& write_date) {
191 SetYear(write_date.year);
192 SetMonth(write_date.month);
193 SetDay(write_date.day);
194 }
195
184 void SetYear(u16 year) { 196 void SetYear(u16 year) {
185 const u16 year_converted = static_cast<u16>((year - 2000) << 9); 197 const u16 year_converted = static_cast<u16>((year - 2000) << 9);
186 raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); 198 raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted);
@@ -354,6 +366,15 @@ struct RegisterInfo {
354}; 366};
355static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); 367static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
356 368
369struct RegisterInfoPrivate {
370 Service::Mii::MiiStoreData mii_store_data;
371 WriteDate creation_date;
372 AmiiboName amiibo_name;
373 u8 font_region;
374 INSERT_PADDING_BYTES(0x8E);
375};
376static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
377
357struct AdminInfo { 378struct AdminInfo {
358 u64 application_id; 379 u64 application_id;
359 u32 application_area_id; 380 u32 application_area_id;
@@ -366,6 +387,39 @@ struct AdminInfo {
366}; 387};
367static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); 388static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size");
368 389
390#pragma pack(1)
391// This is nn::nfp::NfpData
392struct NfpData {
393 u8 magic;
394 INSERT_PADDING_BYTES(0x1);
395 u8 write_counter;
396 INSERT_PADDING_BYTES(0x1);
397 u32 settings_crc;
398 INSERT_PADDING_BYTES(0x38);
399 CommonInfo common_info;
400 Service::Mii::Ver3StoreData mii_char_info;
401 Service::Mii::NfpStoreDataExtension mii_store_data_extension;
402 WriteDate creation_date;
403 std::array<u16_be, amiibo_name_length> amiibo_name;
404 u16 amiibo_name_null_terminated;
405 Settings settings;
406 u8 unknown1;
407 u32 register_info_crc;
408 std::array<u32, 5> unknown2;
409 INSERT_PADDING_BYTES(0x64);
410 u64 application_id;
411 u32 access_id;
412 u16 settings_crc_counter;
413 u8 font_region;
414 PackedTagType tag_type;
415 AppAreaVersion console_type;
416 u8 application_id_byte;
417 INSERT_PADDING_BYTES(0x2E);
418 ApplicationArea application_area;
419};
420static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
421#pragma pack()
422
369struct SectorKey { 423struct SectorKey {
370 MifareCmd command; 424 MifareCmd command;
371 u8 unknown; // Usually 1 425 u8 unknown; // Usually 1
diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp
index 359891883..d707dabe2 100644
--- a/src/dedicated_room/yuzu_room.cpp
+++ b/src/dedicated_room/yuzu_room.cpp
@@ -49,6 +49,7 @@ static void PrintHelp(const char* argv0) {
49 " [options] <filename>\n" 49 " [options] <filename>\n"
50 "--room-name The name of the room\n" 50 "--room-name The name of the room\n"
51 "--room-description The room description\n" 51 "--room-description The room description\n"
52 "--bind-address The bind address for the room\n"
52 "--port The port used for the room\n" 53 "--port The port used for the room\n"
53 "--max_members The maximum number of players for this room\n" 54 "--max_members The maximum number of players for this room\n"
54 "--password The password for the room\n" 55 "--password The password for the room\n"
@@ -195,6 +196,7 @@ int main(int argc, char** argv) {
195 std::string web_api_url; 196 std::string web_api_url;
196 std::string ban_list_file; 197 std::string ban_list_file;
197 std::string log_file = "yuzu-room.log"; 198 std::string log_file = "yuzu-room.log";
199 std::string bind_address;
198 u64 preferred_game_id = 0; 200 u64 preferred_game_id = 0;
199 u32 port = Network::DefaultRoomPort; 201 u32 port = Network::DefaultRoomPort;
200 u32 max_members = 16; 202 u32 max_members = 16;
@@ -203,6 +205,7 @@ int main(int argc, char** argv) {
203 static struct option long_options[] = { 205 static struct option long_options[] = {
204 {"room-name", required_argument, 0, 'n'}, 206 {"room-name", required_argument, 0, 'n'},
205 {"room-description", required_argument, 0, 'd'}, 207 {"room-description", required_argument, 0, 'd'},
208 {"bind-address", required_argument, 0, 's'},
206 {"port", required_argument, 0, 'p'}, 209 {"port", required_argument, 0, 'p'},
207 {"max_members", required_argument, 0, 'm'}, 210 {"max_members", required_argument, 0, 'm'},
208 {"password", required_argument, 0, 'w'}, 211 {"password", required_argument, 0, 'w'},
@@ -222,7 +225,8 @@ int main(int argc, char** argv) {
222 InitializeLogging(log_file); 225 InitializeLogging(log_file);
223 226
224 while (optind < argc) { 227 while (optind < argc) {
225 int arg = getopt_long(argc, argv, "n:d:p:m:w:g:u:t:a:i:l:hv", long_options, &option_index); 228 int arg =
229 getopt_long(argc, argv, "n:d:s:p:m:w:g:u:t:a:i:l:hv", long_options, &option_index);
226 if (arg != -1) { 230 if (arg != -1) {
227 switch (static_cast<char>(arg)) { 231 switch (static_cast<char>(arg)) {
228 case 'n': 232 case 'n':
@@ -231,6 +235,9 @@ int main(int argc, char** argv) {
231 case 'd': 235 case 'd':
232 room_description.assign(optarg); 236 room_description.assign(optarg);
233 break; 237 break;
238 case 's':
239 bind_address.assign(optarg);
240 break;
234 case 'p': 241 case 'p':
235 port = strtoul(optarg, &endarg, 0); 242 port = strtoul(optarg, &endarg, 0);
236 break; 243 break;
@@ -295,6 +302,9 @@ int main(int argc, char** argv) {
295 PrintHelp(argv[0]); 302 PrintHelp(argv[0]);
296 return -1; 303 return -1;
297 } 304 }
305 if (bind_address.empty()) {
306 LOG_INFO(Network, "Bind address is empty: defaulting to 0.0.0.0");
307 }
298 if (port > UINT16_MAX) { 308 if (port > UINT16_MAX) {
299 LOG_ERROR(Network, "Port needs to be in the range 0 - 65535!"); 309 LOG_ERROR(Network, "Port needs to be in the range 0 - 65535!");
300 PrintHelp(argv[0]); 310 PrintHelp(argv[0]);
@@ -358,8 +368,8 @@ int main(int argc, char** argv) {
358 if (auto room = network.GetRoom().lock()) { 368 if (auto room = network.GetRoom().lock()) {
359 AnnounceMultiplayerRoom::GameInfo preferred_game_info{.name = preferred_game, 369 AnnounceMultiplayerRoom::GameInfo preferred_game_info{.name = preferred_game,
360 .id = preferred_game_id}; 370 .id = preferred_game_id};
361 if (!room->Create(room_name, room_description, "", port, password, max_members, username, 371 if (!room->Create(room_name, room_description, bind_address, port, password, max_members,
362 preferred_game_info, std::move(verify_backend), ban_list, 372 username, preferred_game_info, std::move(verify_backend), ban_list,
363 enable_yuzu_mods)) { 373 enable_yuzu_mods)) {
364 LOG_INFO(Network, "Failed to create room: "); 374 LOG_INFO(Network, "Failed to create room: ");
365 return -1; 375 return -1;
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index a126c359c..02e161270 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -77,6 +77,14 @@ void Fermi2D::Blit() {
77 const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); 77 const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
78 const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 && 78 const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 &&
79 src.format != regs.dst.format; 79 src.format != regs.dst.format;
80
81 auto srcX = args.src_x0;
82 auto srcY = args.src_y0;
83 if (args.sample_mode.origin == Origin::Corner) {
84 srcX -= (args.du_dx >> 33) << 32;
85 srcY -= (args.dv_dy >> 33) << 32;
86 }
87
80 Config config{ 88 Config config{
81 .operation = regs.operation, 89 .operation = regs.operation,
82 .filter = args.sample_mode.filter, 90 .filter = args.sample_mode.filter,
@@ -86,10 +94,10 @@ void Fermi2D::Blit() {
86 .dst_y0 = args.dst_y0, 94 .dst_y0 = args.dst_y0,
87 .dst_x1 = args.dst_x0 + args.dst_width, 95 .dst_x1 = args.dst_x0 + args.dst_width,
88 .dst_y1 = args.dst_y0 + args.dst_height, 96 .dst_y1 = args.dst_y0 + args.dst_height,
89 .src_x0 = static_cast<s32>(args.src_x0 >> 32), 97 .src_x0 = static_cast<s32>(srcX >> 32),
90 .src_y0 = static_cast<s32>(args.src_y0 >> 32), 98 .src_y0 = static_cast<s32>(srcY >> 32),
91 .src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32), 99 .src_x1 = static_cast<s32>((srcX + args.du_dx * args.dst_width) >> 32),
92 .src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32), 100 .src_y1 = static_cast<s32>((srcY + args.dv_dy * args.dst_height) >> 32),
93 }; 101 };
94 102
95 const auto need_align_to_pitch = 103 const auto need_align_to_pitch =
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 614d61db4..0932fadc2 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -4,6 +4,7 @@
4#include <cstring> 4#include <cstring>
5#include <optional> 5#include <optional>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/bit_util.h"
7#include "common/scope_exit.h" 8#include "common/scope_exit.h"
8#include "common/settings.h" 9#include "common/settings.h"
9#include "core/core.h" 10#include "core/core.h"
@@ -259,12 +260,13 @@ u32 Maxwell3D::GetMaxCurrentVertices() {
259size_t Maxwell3D::EstimateIndexBufferSize() { 260size_t Maxwell3D::EstimateIndexBufferSize() {
260 GPUVAddr start_address = regs.index_buffer.StartAddress(); 261 GPUVAddr start_address = regs.index_buffer.StartAddress();
261 GPUVAddr end_address = regs.index_buffer.EndAddress(); 262 GPUVAddr end_address = regs.index_buffer.EndAddress();
262 static constexpr std::array<size_t, 4> max_sizes = { 263 static constexpr std::array<size_t, 3> max_sizes = {std::numeric_limits<u8>::max(),
263 std::numeric_limits<u8>::max(), std::numeric_limits<u16>::max(), 264 std::numeric_limits<u16>::max(),
264 std::numeric_limits<u32>::max(), std::numeric_limits<u32>::max()}; 265 std::numeric_limits<u32>::max()};
265 const size_t byte_size = regs.index_buffer.FormatSizeInBytes(); 266 const size_t byte_size = regs.index_buffer.FormatSizeInBytes();
267 const size_t log2_byte_size = Common::Log2Ceil64(byte_size);
266 return std::min<size_t>( 268 return std::min<size_t>(
267 memory_manager.GetMemoryLayoutSize(start_address, byte_size * max_sizes[byte_size]) / 269 memory_manager.GetMemoryLayoutSize(start_address, byte_size * max_sizes[log2_byte_size]) /
268 byte_size, 270 byte_size,
269 static_cast<size_t>(end_address - start_address)); 271 static_cast<size_t>(end_address - start_address));
270} 272}
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index 8aa07ef9d..47c74e4d8 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -10,7 +10,14 @@
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13MasterSemaphore::MasterSemaphore(const Device& device) { 13MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) {
14 if (!device.HasTimelineSemaphore()) {
15 static constexpr VkFenceCreateInfo fence_ci{
16 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
17 fence = device.GetLogical().CreateFence(fence_ci);
18 return;
19 }
20
14 static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{ 21 static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{
15 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 22 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
16 .pNext = nullptr, 23 .pNext = nullptr,
@@ -42,4 +49,134 @@ MasterSemaphore::MasterSemaphore(const Device& device) {
42 49
43MasterSemaphore::~MasterSemaphore() = default; 50MasterSemaphore::~MasterSemaphore() = default;
44 51
52void MasterSemaphore::Refresh() {
53 if (!semaphore) {
54 // If we don't support timeline semaphores, there's nothing to refresh
55 return;
56 }
57
58 u64 this_tick{};
59 u64 counter{};
60 do {
61 this_tick = gpu_tick.load(std::memory_order_acquire);
62 counter = semaphore.GetCounter();
63 if (counter < this_tick) {
64 return;
65 }
66 } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release,
67 std::memory_order_relaxed));
68}
69
70void MasterSemaphore::Wait(u64 tick) {
71 if (!semaphore) {
72 // If we don't support timeline semaphores, use an atomic wait
73 while (true) {
74 u64 current_value = gpu_tick.load(std::memory_order_relaxed);
75 if (current_value >= tick) {
76 return;
77 }
78 gpu_tick.wait(current_value);
79 }
80
81 return;
82 }
83
84 // No need to wait if the GPU is ahead of the tick
85 if (IsFree(tick)) {
86 return;
87 }
88
89 // Update the GPU tick and try again
90 Refresh();
91
92 if (IsFree(tick)) {
93 return;
94 }
95
96 // If none of the above is hit, fallback to a regular wait
97 while (!semaphore.Wait(tick)) {
98 }
99
100 Refresh();
101}
102
103VkResult MasterSemaphore::SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
104 VkSemaphore wait_semaphore, u64 host_tick) {
105 if (semaphore) {
106 return SubmitQueueTimeline(cmdbuf, signal_semaphore, wait_semaphore, host_tick);
107 } else {
108 return SubmitQueueFence(cmdbuf, signal_semaphore, wait_semaphore, host_tick);
109 }
110}
111
112static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
113 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
114 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
115};
116
117VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf,
118 VkSemaphore signal_semaphore,
119 VkSemaphore wait_semaphore, u64 host_tick) {
120 const VkSemaphore timeline_semaphore = *semaphore;
121
122 const u32 num_signal_semaphores = signal_semaphore ? 2 : 1;
123 const std::array signal_values{host_tick, u64(0)};
124 const std::array signal_semaphores{timeline_semaphore, signal_semaphore};
125
126 const u32 num_wait_semaphores = wait_semaphore ? 2 : 1;
127 const std::array wait_values{host_tick - 1, u64(1)};
128 const std::array wait_semaphores{timeline_semaphore, wait_semaphore};
129
130 const VkTimelineSemaphoreSubmitInfo timeline_si{
131 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
132 .pNext = nullptr,
133 .waitSemaphoreValueCount = num_wait_semaphores,
134 .pWaitSemaphoreValues = wait_values.data(),
135 .signalSemaphoreValueCount = num_signal_semaphores,
136 .pSignalSemaphoreValues = signal_values.data(),
137 };
138 const VkSubmitInfo submit_info{
139 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
140 .pNext = &timeline_si,
141 .waitSemaphoreCount = num_wait_semaphores,
142 .pWaitSemaphores = wait_semaphores.data(),
143 .pWaitDstStageMask = wait_stage_masks.data(),
144 .commandBufferCount = 1,
145 .pCommandBuffers = cmdbuf.address(),
146 .signalSemaphoreCount = num_signal_semaphores,
147 .pSignalSemaphores = signal_semaphores.data(),
148 };
149
150 return device.GetGraphicsQueue().Submit(submit_info);
151}
152
153VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
154 VkSemaphore wait_semaphore, u64 host_tick) {
155 const u32 num_signal_semaphores = signal_semaphore ? 1 : 0;
156 const u32 num_wait_semaphores = wait_semaphore ? 1 : 0;
157
158 const VkSubmitInfo submit_info{
159 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
160 .pNext = nullptr,
161 .waitSemaphoreCount = num_wait_semaphores,
162 .pWaitSemaphores = &wait_semaphore,
163 .pWaitDstStageMask = wait_stage_masks.data(),
164 .commandBufferCount = 1,
165 .pCommandBuffers = cmdbuf.address(),
166 .signalSemaphoreCount = num_signal_semaphores,
167 .pSignalSemaphores = &signal_semaphore,
168 };
169
170 auto result = device.GetGraphicsQueue().Submit(submit_info, *fence);
171
172 if (result == VK_SUCCESS) {
173 fence.Wait();
174 fence.Reset();
175 gpu_tick.store(host_tick);
176 gpu_tick.notify_all();
177 }
178
179 return result;
180}
181
45} // namespace Vulkan 182} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 689f02ea5..f2f61f781 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -4,6 +4,8 @@
4#pragma once 4#pragma once
5 5
6#include <atomic> 6#include <atomic>
7#include <condition_variable>
8#include <mutex>
7#include <thread> 9#include <thread>
8 10
9#include "common/common_types.h" 11#include "common/common_types.h"
@@ -29,11 +31,6 @@ public:
29 return gpu_tick.load(std::memory_order_acquire); 31 return gpu_tick.load(std::memory_order_acquire);
30 } 32 }
31 33
32 /// Returns the timeline semaphore handle.
33 [[nodiscard]] VkSemaphore Handle() const noexcept {
34 return *semaphore;
35 }
36
37 /// Returns true when a tick has been hit by the GPU. 34 /// Returns true when a tick has been hit by the GPU.
38 [[nodiscard]] bool IsFree(u64 tick) const noexcept { 35 [[nodiscard]] bool IsFree(u64 tick) const noexcept {
39 return KnownGpuTick() >= tick; 36 return KnownGpuTick() >= tick;
@@ -45,37 +42,24 @@ public:
45 } 42 }
46 43
47 /// Refresh the known GPU tick 44 /// Refresh the known GPU tick
48 void Refresh() { 45 void Refresh();
49 u64 this_tick{};
50 u64 counter{};
51 do {
52 this_tick = gpu_tick.load(std::memory_order_acquire);
53 counter = semaphore.GetCounter();
54 if (counter < this_tick) {
55 return;
56 }
57 } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release,
58 std::memory_order_relaxed));
59 }
60 46
61 /// Waits for a tick to be hit on the GPU 47 /// Waits for a tick to be hit on the GPU
62 void Wait(u64 tick) { 48 void Wait(u64 tick);
63 // No need to wait if the GPU is ahead of the tick 49
64 if (IsFree(tick)) { 50 /// Submits the device graphics queue, updating the tick as necessary
65 return; 51 VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
66 } 52 VkSemaphore wait_semaphore, u64 host_tick);
67 // Update the GPU tick and try again 53
68 Refresh(); 54private:
69 if (IsFree(tick)) { 55 VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
70 return; 56 VkSemaphore wait_semaphore, u64 host_tick);
71 } 57 VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
72 // If none of the above is hit, fallback to a regular wait 58 VkSemaphore wait_semaphore, u64 host_tick);
73 while (!semaphore.Wait(tick)) {
74 }
75 Refresh();
76 }
77 59
78private: 60private:
61 const Device& device; ///< Device.
62 vk::Fence fence; ///< Fence.
79 vk::Semaphore semaphore; ///< Timeline semaphore. 63 vk::Semaphore semaphore; ///< Timeline semaphore.
80 std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. 64 std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
81 std::atomic<u64> current_tick{1}; ///< Current logical tick. 65 std::atomic<u64> current_tick{1}; ///< Current logical tick.
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index b264e6ada..057e16967 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -212,45 +212,13 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
212 const u64 signal_value = master_semaphore->NextTick(); 212 const u64 signal_value = master_semaphore->NextTick();
213 Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { 213 Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) {
214 cmdbuf.End(); 214 cmdbuf.End();
215 const VkSemaphore timeline_semaphore = master_semaphore->Handle();
216
217 const u32 num_signal_semaphores = signal_semaphore ? 2U : 1U;
218 const std::array signal_values{signal_value, u64(0)};
219 const std::array signal_semaphores{timeline_semaphore, signal_semaphore};
220
221 const u32 num_wait_semaphores = wait_semaphore ? 2U : 1U;
222 const std::array wait_values{signal_value - 1, u64(1)};
223 const std::array wait_semaphores{timeline_semaphore, wait_semaphore};
224 static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
225 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
226 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
227 };
228
229 const VkTimelineSemaphoreSubmitInfo timeline_si{
230 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
231 .pNext = nullptr,
232 .waitSemaphoreValueCount = num_wait_semaphores,
233 .pWaitSemaphoreValues = wait_values.data(),
234 .signalSemaphoreValueCount = num_signal_semaphores,
235 .pSignalSemaphoreValues = signal_values.data(),
236 };
237 const VkSubmitInfo submit_info{
238 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
239 .pNext = &timeline_si,
240 .waitSemaphoreCount = num_wait_semaphores,
241 .pWaitSemaphores = wait_semaphores.data(),
242 .pWaitDstStageMask = wait_stage_masks.data(),
243 .commandBufferCount = 1,
244 .pCommandBuffers = cmdbuf.address(),
245 .signalSemaphoreCount = num_signal_semaphores,
246 .pSignalSemaphores = signal_semaphores.data(),
247 };
248 215
249 if (on_submit) { 216 if (on_submit) {
250 on_submit(); 217 on_submit();
251 } 218 }
252 219
253 switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info)) { 220 switch (const VkResult result = master_semaphore->SubmitQueue(
221 cmdbuf, signal_semaphore, wait_semaphore, signal_value)) {
254 case VK_SUCCESS: 222 case VK_SUCCESS:
255 break; 223 break;
256 case VK_ERROR_DEVICE_LOST: 224 case VK_ERROR_DEVICE_LOST:
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 41b5da18a..7d5018151 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -145,7 +145,6 @@
145 FEATURE_NAME(robustness2, robustImageAccess2) \ 145 FEATURE_NAME(robustness2, robustImageAccess2) \
146 FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \ 146 FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \
147 FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \ 147 FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \
148 FEATURE_NAME(timeline_semaphore, timelineSemaphore) \
149 FEATURE_NAME(variable_pointer, variablePointers) \ 148 FEATURE_NAME(variable_pointer, variablePointers) \
150 FEATURE_NAME(variable_pointer, variablePointersStorageBuffer) 149 FEATURE_NAME(variable_pointer, variablePointersStorageBuffer)
151 150
@@ -158,6 +157,7 @@
158 FEATURE_NAME(provoking_vertex, provokingVertexLast) \ 157 FEATURE_NAME(provoking_vertex, provokingVertexLast) \
159 FEATURE_NAME(shader_float16_int8, shaderFloat16) \ 158 FEATURE_NAME(shader_float16_int8, shaderFloat16) \
160 FEATURE_NAME(shader_float16_int8, shaderInt8) \ 159 FEATURE_NAME(shader_float16_int8, shaderInt8) \
160 FEATURE_NAME(timeline_semaphore, timelineSemaphore) \
161 FEATURE_NAME(transform_feedback, transformFeedback) \ 161 FEATURE_NAME(transform_feedback, transformFeedback) \
162 FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \ 162 FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \
163 FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState) 163 FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState)
@@ -493,6 +493,10 @@ public:
493 return extensions.shader_atomic_int64; 493 return extensions.shader_atomic_int64;
494 } 494 }
495 495
496 bool HasTimelineSemaphore() const {
497 return features.timeline_semaphore.timelineSemaphore;
498 }
499
496 /// Returns the minimum supported version of SPIR-V. 500 /// Returns the minimum supported version of SPIR-V.
497 u32 SupportedSpirvVersion() const { 501 u32 SupportedSpirvVersion() const {
498 if (instance_version >= VK_API_VERSION_1_3) { 502 if (instance_version >= VK_API_VERSION_1_3) {