summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar bunnei2022-11-20 00:48:39 -0800
committerGravatar GitHub2022-11-20 00:48:39 -0800
commit57a05b1653b316412492b7cf83738b702865b47e (patch)
treecb76a9aead5f545250301eb7928ecfb03e706931 /src/core
parentMerge pull request #9249 from goldenx86/available-vram (diff)
parentgeneral: Address review comments (diff)
downloadyuzu-57a05b1653b316412492b7cf83738b702865b47e.tar.gz
yuzu-57a05b1653b316412492b7cf83738b702865b47e.tar.xz
yuzu-57a05b1653b316412492b7cf83738b702865b47e.zip
Merge pull request #9238 from german77/cabinet_applet
service: am: Implement cabinet applet
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/frontend/applets/cabinet.cpp20
-rw-r--r--src/core/frontend/applets/cabinet.h37
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp177
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.h104
-rw-r--r--src/core/hle/service/am/applets/applets.cpp20
-rw-r--r--src/core/hle/service/am/applets/applets.h12
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp35
-rw-r--r--src/core/hle/service/nfp/nfp_device.h6
-rw-r--r--src/core/hle/service/nfp/nfp_types.h17
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp2
11 files changed, 419 insertions, 15 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f67f1ce92..740c5b0fd 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -120,6 +120,8 @@ add_library(core STATIC
120 file_sys/vfs_vector.h 120 file_sys/vfs_vector.h
121 file_sys/xts_archive.cpp 121 file_sys/xts_archive.cpp
122 file_sys/xts_archive.h 122 file_sys/xts_archive.h
123 frontend/applets/cabinet.cpp
124 frontend/applets/cabinet.h
123 frontend/applets/controller.cpp 125 frontend/applets/controller.cpp
124 frontend/applets/controller.h 126 frontend/applets/controller.h
125 frontend/applets/error.cpp 127 frontend/applets/error.cpp
@@ -312,6 +314,8 @@ add_library(core STATIC
312 hle/service/am/applet_ae.h 314 hle/service/am/applet_ae.h
313 hle/service/am/applet_oe.cpp 315 hle/service/am/applet_oe.cpp
314 hle/service/am/applet_oe.h 316 hle/service/am/applet_oe.h
317 hle/service/am/applets/applet_cabinet.cpp
318 hle/service/am/applets/applet_cabinet.h
315 hle/service/am/applets/applet_controller.cpp 319 hle/service/am/applets/applet_controller.cpp
316 hle/service/am/applets/applet_controller.h 320 hle/service/am/applets/applet_controller.h
317 hle/service/am/applets/applet_error.cpp 321 hle/service/am/applets/applet_error.cpp
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp
new file mode 100644
index 000000000..26c7fefe3
--- /dev/null
+++ b/src/core/frontend/applets/cabinet.cpp
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/frontend/applets/cabinet.h"
6
7#include <thread>
8
9namespace Core::Frontend {
10
11CabinetApplet::~CabinetApplet() = default;
12
13void DefaultCabinetApplet::ShowCabinetApplet(
14 const CabinetCallback& callback, const CabinetParameters& parameters,
15 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
16 LOG_WARNING(Service_AM, "(STUBBED) called");
17 callback(false, {});
18}
19
20} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h
new file mode 100644
index 000000000..c28a235c1
--- /dev/null
+++ b/src/core/frontend/applets/cabinet.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <functional>
7#include "core/hle/service/nfp/nfp_types.h"
8
9namespace Service::NFP {
10class NfpDevice;
11} // namespace Service::NFP
12
13namespace Core::Frontend {
14
15struct CabinetParameters {
16 Service::NFP::TagInfo tag_info;
17 Service::NFP::RegisterInfo register_info;
18 Service::NFP::CabinetMode mode;
19};
20
21using CabinetCallback = std::function<void(bool, const std::string&)>;
22
23class CabinetApplet {
24public:
25 virtual ~CabinetApplet();
26 virtual void ShowCabinetApplet(const CabinetCallback& callback,
27 const CabinetParameters& parameters,
28 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
29};
30
31class DefaultCabinetApplet final : public CabinetApplet {
32public:
33 void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
34 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
35};
36
37} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
new file mode 100644
index 000000000..d0969b0f1
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -0,0 +1,177 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/frontend/applets/cabinet.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_cabinet.h"
13#include "core/hle/service/mii/mii_manager.h"
14#include "core/hle/service/nfp/nfp_device.h"
15
16namespace Service::AM::Applets {
17
18Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
19 const Core::Frontend::CabinetApplet& frontend_)
20 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
21 system_,
22 "CabinetApplet"} {
23
24 availability_change_event =
25 service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent");
26}
27
28Cabinet::~Cabinet() = default;
29
30void Cabinet::Initialize() {
31 Applet::Initialize();
32
33 LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
34
35 LOG_DEBUG(Service_HID,
36 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
37 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
38 common_args.arguments_version, common_args.library_version,
39 common_args.play_startup_sound, common_args.size, common_args.system_tick,
40 common_args.theme_color);
41
42 const auto storage = broker.PopNormalDataToApplet();
43 ASSERT(storage != nullptr);
44
45 const auto applet_input_data = storage->GetData();
46 ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings));
47
48 std::memcpy(&applet_input_common, applet_input_data.data(),
49 sizeof(StartParamForAmiiboSettings));
50}
51
52bool Cabinet::TransactionComplete() const {
53 return is_complete;
54}
55
56Result Cabinet::GetStatus() const {
57 return ResultSuccess;
58}
59
60void Cabinet::ExecuteInteractive() {
61 ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
62}
63
64void Cabinet::Execute() {
65 if (is_complete) {
66 return;
67 }
68
69 const auto callback = [this](bool apply_changes, const std::string& amiibo_name) {
70 DisplayCompleted(apply_changes, amiibo_name);
71 };
72
73 // TODO: listen on all controllers
74 if (nfp_device == nullptr) {
75 nfp_device = std::make_shared<Service::NFP::NfpDevice>(
76 system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
77 nfp_device->Initialize();
78 nfp_device->StartDetection(Service::NFP::TagProtocol::All);
79 }
80
81 const Core::Frontend::CabinetParameters parameters{
82 .tag_info = applet_input_common.tag_info,
83 .register_info = applet_input_common.register_info,
84 .mode = applet_input_common.applet_mode,
85 };
86
87 switch (applet_input_common.applet_mode) {
88 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
89 case Service::NFP::CabinetMode::StartGameDataEraser:
90 case Service::NFP::CabinetMode::StartRestorer:
91 case Service::NFP::CabinetMode::StartFormatter:
92 frontend.ShowCabinetApplet(callback, parameters, nfp_device);
93 break;
94 default:
95 UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
96 DisplayCompleted(false, {});
97 break;
98 }
99}
100
101void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) {
102 Service::Mii::MiiManager manager;
103 ReturnValueForAmiiboSettings applet_output{};
104
105 if (!apply_changes) {
106 Cancel();
107 }
108
109 if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
110 nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
111 Cancel();
112 }
113
114 if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
115 nfp_device->Mount(Service::NFP::MountTarget::All);
116 }
117
118 switch (applet_input_common.applet_mode) {
119 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
120 Service::NFP::AmiiboName name{};
121 std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
122 nfp_device->SetNicknameAndOwner(name);
123 break;
124 }
125 case Service::NFP::CabinetMode::StartGameDataEraser:
126 nfp_device->DeleteApplicationArea();
127 break;
128 case Service::NFP::CabinetMode::StartRestorer:
129 nfp_device->RestoreAmiibo();
130 break;
131 case Service::NFP::CabinetMode::StartFormatter:
132 nfp_device->DeleteAllData();
133 break;
134 default:
135 UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
136 break;
137 }
138
139 applet_output.device_handle = applet_input_common.device_handle;
140 applet_output.result = CabinetResult::Cancel;
141 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
142 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
143 nfp_device->Finalize();
144
145 if (reg_result.IsSuccess()) {
146 applet_output.result |= CabinetResult::RegisterInfo;
147 }
148
149 if (tag_result.IsSuccess()) {
150 applet_output.result |= CabinetResult::TagInfo;
151 }
152
153 std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
154 std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
155
156 is_complete = true;
157
158 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
159 broker.SignalStateChanged();
160}
161
162void Cabinet::Cancel() {
163 ReturnValueForAmiiboSettings applet_output{};
164 applet_output.device_handle = applet_input_common.device_handle;
165 applet_output.result = CabinetResult::Cancel;
166 nfp_device->Finalize();
167
168 std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
169 std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
170
171 is_complete = true;
172
173 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
174 broker.SignalStateChanged();
175}
176
177} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
new file mode 100644
index 000000000..84197a807
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "core/hle/result.h"
9#include "core/hle/service/am/applets/applets.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nfp/nfp_types.h"
12
13namespace Kernel {
14class KEvent;
15class KReadableEvent;
16} // namespace Kernel
17
18namespace Core {
19class System;
20} // namespace Core
21
22namespace Service::NFP {
23class NfpDevice;
24}
25
26namespace Service::AM::Applets {
27
28enum class CabinetAppletVersion : u32 {
29 Version1 = 0x1,
30};
31
32enum class CabinetResult : u8 {
33 Cancel = 0,
34 TagInfo = 1 << 1,
35 RegisterInfo = 1 << 2,
36 All = TagInfo | RegisterInfo,
37};
38DECLARE_ENUM_FLAG_OPERATORS(CabinetResult)
39
40// This is nn::nfp::AmiiboSettingsStartParam
41struct AmiiboSettingsStartParam {
42 u64 device_handle;
43 std::array<u8, 0x20> param_1;
44 u8 param_2;
45};
46static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
47 "AmiiboSettingsStartParam is an invalid size");
48
49#pragma pack(push, 1)
50// This is nn::nfp::StartParamForAmiiboSettings
51struct StartParamForAmiiboSettings {
52 u8 param_1;
53 Service::NFP::CabinetMode applet_mode;
54 u8 flags;
55 u8 amiibo_settings_1;
56 u64 device_handle;
57 Service::NFP::TagInfo tag_info;
58 Service::NFP::RegisterInfo register_info;
59 std::array<u8, 0x20> amiibo_settings_3;
60 INSERT_PADDING_BYTES(0x24);
61};
62static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8,
63 "StartParamForAmiiboSettings is an invalid size");
64
65// This is nn::nfp::ReturnValueForAmiiboSettings
66struct ReturnValueForAmiiboSettings {
67 CabinetResult result;
68 INSERT_PADDING_BYTES(0x3);
69 u64 device_handle;
70 Service::NFP::TagInfo tag_info;
71 Service::NFP::RegisterInfo register_info;
72 INSERT_PADDING_BYTES(0x24);
73};
74static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
75 "ReturnValueForAmiiboSettings is an invalid size");
76#pragma pack(pop)
77
78class Cabinet final : public Applet {
79public:
80 explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
81 const Core::Frontend::CabinetApplet& frontend_);
82 ~Cabinet() override;
83
84 void Initialize() override;
85
86 bool TransactionComplete() const override;
87 Result GetStatus() const override;
88 void ExecuteInteractive() override;
89 void Execute() override;
90 void DisplayCompleted(bool apply_changes, std::string_view amiibo_name);
91 void Cancel();
92
93private:
94 const Core::Frontend::CabinetApplet& frontend;
95 Core::System& system;
96
97 bool is_complete{false};
98 std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
99 Kernel::KEvent* availability_change_event;
100 KernelHelpers::ServiceContext service_context;
101 StartParamForAmiiboSettings applet_input_common{};
102};
103
104} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 7062df21c..10afbc2da 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
8#include "core/frontend/applets/controller.h" 9#include "core/frontend/applets/controller.h"
9#include "core/frontend/applets/error.h" 10#include "core/frontend/applets/error.h"
10#include "core/frontend/applets/general_frontend.h" 11#include "core/frontend/applets/general_frontend.h"
@@ -16,6 +17,7 @@
16#include "core/hle/service/am/am.h" 17#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applet_ae.h" 18#include "core/hle/service/am/applet_ae.h"
18#include "core/hle/service/am/applet_oe.h" 19#include "core/hle/service/am/applet_oe.h"
20#include "core/hle/service/am/applets/applet_cabinet.h"
19#include "core/hle/service/am/applets/applet_controller.h" 21#include "core/hle/service/am/applets/applet_controller.h"
20#include "core/hle/service/am/applets/applet_error.h" 22#include "core/hle/service/am/applets/applet_error.h"
21#include "core/hle/service/am/applets/applet_general_backend.h" 23#include "core/hle/service/am/applets/applet_general_backend.h"
@@ -171,13 +173,15 @@ void Applet::Initialize() {
171 173
172AppletFrontendSet::AppletFrontendSet() = default; 174AppletFrontendSet::AppletFrontendSet() = default;
173 175
174AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, 176AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
177 ControllerApplet controller_applet, ErrorApplet error_applet,
175 MiiEdit mii_edit_, 178 MiiEdit mii_edit_,
176 ParentalControlsApplet parental_controls_applet, 179 ParentalControlsApplet parental_controls_applet,
177 PhotoViewer photo_viewer_, ProfileSelect profile_select_, 180 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
178 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) 181 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
179 : controller{std::move(controller_applet)}, error{std::move(error_applet)}, 182 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
180 mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, 183 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
184 parental_controls{std::move(parental_controls_applet)},
181 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, 185 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
182 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} 186 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
183 187
@@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
196} 200}
197 201
198void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 202void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
203 if (set.cabinet != nullptr) {
204 frontend.cabinet = std::move(set.cabinet);
205 }
206
199 if (set.controller != nullptr) { 207 if (set.controller != nullptr) {
200 frontend.controller = std::move(set.controller); 208 frontend.controller = std::move(set.controller);
201 } 209 }
@@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() {
235} 243}
236 244
237void AppletManager::SetDefaultAppletsIfMissing() { 245void AppletManager::SetDefaultAppletsIfMissing() {
246 if (frontend.cabinet == nullptr) {
247 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
248 }
249
238 if (frontend.controller == nullptr) { 250 if (frontend.controller == nullptr) {
239 frontend.controller = 251 frontend.controller =
240 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); 252 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
@@ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
279 switch (id) { 291 switch (id) {
280 case AppletId::Auth: 292 case AppletId::Auth:
281 return std::make_shared<Auth>(system, mode, *frontend.parental_controls); 293 return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
294 case AppletId::Cabinet:
295 return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
282 case AppletId::Controller: 296 case AppletId::Controller:
283 return std::make_shared<Controller>(system, mode, *frontend.controller); 297 return std::make_shared<Controller>(system, mode, *frontend.controller);
284 case AppletId::Error: 298 case AppletId::Error:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 12c6a5b1a..a22eb62a8 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -16,6 +16,7 @@ class System;
16} 16}
17 17
18namespace Core::Frontend { 18namespace Core::Frontend {
19class CabinetApplet;
19class ControllerApplet; 20class ControllerApplet;
20class ECommerceApplet; 21class ECommerceApplet;
21class ErrorApplet; 22class ErrorApplet;
@@ -176,6 +177,7 @@ protected:
176}; 177};
177 178
178struct AppletFrontendSet { 179struct AppletFrontendSet {
180 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
179 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; 181 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
180 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 182 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
181 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; 183 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
@@ -186,10 +188,11 @@ struct AppletFrontendSet {
186 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 188 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
187 189
188 AppletFrontendSet(); 190 AppletFrontendSet();
189 AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, 191 AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
190 MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, 192 ErrorApplet error_applet, MiiEdit mii_edit_,
191 PhotoViewer photo_viewer_, ProfileSelect profile_select_, 193 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
192 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); 194 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
195 WebBrowser web_browser_);
193 ~AppletFrontendSet(); 196 ~AppletFrontendSet();
194 197
195 AppletFrontendSet(const AppletFrontendSet&) = delete; 198 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -198,6 +201,7 @@ struct AppletFrontendSet {
198 AppletFrontendSet(AppletFrontendSet&&) noexcept; 201 AppletFrontendSet(AppletFrontendSet&&) noexcept;
199 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 202 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
200 203
204 CabinetApplet cabinet;
201 ControllerApplet controller; 205 ControllerApplet controller;
202 ErrorApplet error; 206 ErrorApplet error;
203 MiiEdit mii_edit; 207 MiiEdit mii_edit;
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
index b19672560..e1bf90d7c 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfp/nfp_device.cpp
@@ -77,6 +77,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
77 LoadAmiibo(nfc_status.data); 77 LoadAmiibo(nfc_status.data);
78 break; 78 break;
79 case Common::Input::NfcState::AmiiboRemoved: 79 case Common::Input::NfcState::AmiiboRemoved:
80 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
81 break;
82 }
80 if (device_state != DeviceState::SearchingForTag) { 83 if (device_state != DeviceState::SearchingForTag) {
81 CloseAmiibo(); 84 CloseAmiibo();
82 } 85 }
@@ -97,6 +100,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
97 return false; 100 return false;
98 } 101 }
99 102
103 // TODO: Filter by allowed_protocols here
104
100 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); 105 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
101 106
102 device_state = DeviceState::TagFound; 107 device_state = DeviceState::TagFound;
@@ -143,7 +148,7 @@ void NfpDevice::Finalize() {
143 device_state = DeviceState::Unavailable; 148 device_state = DeviceState::Unavailable;
144} 149}
145 150
146Result NfpDevice::StartDetection(s32 protocol_) { 151Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
147 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { 152 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
148 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 153 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
149 return WrongDeviceState; 154 return WrongDeviceState;
@@ -155,7 +160,7 @@ Result NfpDevice::StartDetection(s32 protocol_) {
155 } 160 }
156 161
157 device_state = DeviceState::SearchingForTag; 162 device_state = DeviceState::SearchingForTag;
158 protocol = protocol_; 163 allowed_protocols = allowed_protocol;
159 return ResultSuccess; 164 return ResultSuccess;
160} 165}
161 166
@@ -469,6 +474,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
469 return ResultSuccess; 474 return ResultSuccess;
470} 475}
471 476
477Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
478 application_area_id = {};
479
480 if (device_state != DeviceState::TagMounted) {
481 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
482 if (device_state == DeviceState::TagRemoved) {
483 return TagRemoved;
484 }
485 return WrongDeviceState;
486 }
487
488 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
489 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
490 return WrongDeviceState;
491 }
492
493 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
494 LOG_WARNING(Service_NFP, "Application area is not initialized");
495 return ApplicationAreaIsNotInitialized;
496 }
497
498 application_area_id = tag_data.application_area_id;
499
500 return ResultSuccess;
501}
502
472Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { 503Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
473 if (device_state != DeviceState::TagMounted) { 504 if (device_state != DeviceState::TagMounted) {
474 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 505 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
index 76d0e9ae4..3d1cb4609 100644
--- a/src/core/hle/service/nfp/nfp_device.h
+++ b/src/core/hle/service/nfp/nfp_device.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
@@ -37,7 +38,7 @@ public:
37 void Initialize(); 38 void Initialize();
38 void Finalize(); 39 void Finalize();
39 40
40 Result StartDetection(s32 protocol_); 41 Result StartDetection(TagProtocol allowed_protocol);
41 Result StopDetection(); 42 Result StopDetection();
42 Result Mount(MountTarget mount_target); 43 Result Mount(MountTarget mount_target);
43 Result Unmount(); 44 Result Unmount();
@@ -53,6 +54,7 @@ public:
53 Result DeleteAllData(); 54 Result DeleteAllData();
54 55
55 Result OpenApplicationArea(u32 access_id); 56 Result OpenApplicationArea(u32 access_id);
57 Result GetApplicationAreaId(u32& application_area_id) const;
56 Result GetApplicationArea(std::vector<u8>& data) const; 58 Result GetApplicationArea(std::vector<u8>& data) const;
57 Result SetApplicationArea(std::span<const u8> data); 59 Result SetApplicationArea(std::span<const u8> data);
58 Result CreateApplicationArea(u32 access_id, std::span<const u8> data); 60 Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
@@ -88,7 +90,7 @@ private:
88 90
89 bool is_data_moddified{}; 91 bool is_data_moddified{};
90 bool is_app_area_open{}; 92 bool is_app_area_open{};
91 s32 protocol{}; 93 TagProtocol allowed_protocols{};
92 s64 current_posix_time{}; 94 s64 current_posix_time{};
93 MountTarget mount_target{MountTarget::None}; 95 MountTarget mount_target{MountTarget::None};
94 DeviceState device_state{DeviceState::Unavailable}; 96 DeviceState device_state{DeviceState::Unavailable};
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 63d5917cb..69858096a 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -88,11 +88,22 @@ enum class PackedTagType : u8 {
88 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s 88 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
89}; 89};
90 90
91// Verify this enum. It might be completely wrong default protocol is 0x48
91enum class TagProtocol : u32 { 92enum class TagProtocol : u32 {
92 None, 93 None,
93 TypeA, // ISO14443A 94 TypeA = 1U << 0, // ISO14443A
94 TypeB, // ISO14443B 95 TypeB = 1U << 1, // ISO14443B
95 TypeF, // Sony Felica 96 TypeF = 1U << 2, // Sony Felica
97 Unknown1 = 1U << 3,
98 Unknown2 = 1U << 5,
99 All = 0xFFFFFFFFU,
100};
101
102enum class CabinetMode : u8 {
103 StartNicknameAndOwnerSettings,
104 StartGameDataEraser,
105 StartRestorer,
106 StartFormatter,
96}; 107};
97 108
98using UniqueSerialNumber = std::array<u8, 7>; 109using UniqueSerialNumber = std::array<u8, 7>;
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 33e2ef518..ac492cc27 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -130,7 +130,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
130void IUser::StartDetection(Kernel::HLERequestContext& ctx) { 130void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
131 IPC::RequestParser rp{ctx}; 131 IPC::RequestParser rp{ctx};
132 const auto device_handle{rp.Pop<u64>()}; 132 const auto device_handle{rp.Pop<u64>()};
133 const auto nfp_protocol{rp.Pop<s32>()}; 133 const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
134 LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); 134 LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
135 135
136 if (state == State::NonInitialized) { 136 if (state == State::NonInitialized) {