summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar David2018-10-24 10:28:17 +1100
committerGravatar bunnei2018-10-23 19:28:17 -0400
commit50e4e81fd3a998813316cdabd05ef56b12c91fae (patch)
treeb5b77eec3bdc55b411c04ca6a9d4a44f1e670f9c
parentMerge pull request #1515 from DarkLordZach/dlc-lfs (diff)
downloadyuzu-50e4e81fd3a998813316cdabd05ef56b12c91fae.tar.gz
yuzu-50e4e81fd3a998813316cdabd05ef56b12c91fae.tar.xz
yuzu-50e4e81fd3a998813316cdabd05ef56b12c91fae.zip
Added Amiibo support (#1390)
* Fixed conflict with nfp * Few fixups for nfc * Conflict 2 * Fixed AttachAvailabilityChangeEvent * Conflict 3 * Fixed byte padding * Refactored amiibo to not reside in "System" * Removed remaining references of nfc from system * used enum for Nfc GetStateOld * Added missing newline * Moved file operations to front end * Conflict 4 * Amiibos now use structs and added mutexes * Removed amiibo_path
-rw-r--r--src/core/hle/service/nfc/nfc.cpp53
-rw-r--r--src/core/hle/service/nfp/nfp.cpp268
-rw-r--r--src/core/hle/service/nfp/nfp.h23
-rw-r--r--src/core/settings.h1
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_general.cpp2
-rw-r--r--src/yuzu/configuration/configure_general.ui29
-rw-r--r--src/yuzu/main.cpp55
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui27
-rw-r--r--src/yuzu_cmd/config.cpp1
-rw-r--r--src/yuzu_cmd/default_ini.h4
12 files changed, 386 insertions, 80 deletions
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 8fec97db8..30e542542 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -10,12 +10,13 @@
10#include "core/hle/service/nfc/nfc.h" 10#include "core/hle/service/nfc/nfc.h"
11#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 12#include "core/hle/service/sm/sm.h"
13#include "core/settings.h"
13 14
14namespace Service::NFC { 15namespace Service::NFC {
15 16
16class IAm final : public ServiceFramework<IAm> { 17class IAm final : public ServiceFramework<IAm> {
17public: 18public:
18 explicit IAm() : ServiceFramework{"IAm"} { 19 explicit IAm() : ServiceFramework{"NFC::IAm"} {
19 // clang-format off 20 // clang-format off
20 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
21 {0, nullptr, "Initialize"}, 22 {0, nullptr, "Initialize"},
@@ -52,7 +53,7 @@ private:
52 53
53class MFIUser final : public ServiceFramework<MFIUser> { 54class MFIUser final : public ServiceFramework<MFIUser> {
54public: 55public:
55 explicit MFIUser() : ServiceFramework{"IUser"} { 56 explicit MFIUser() : ServiceFramework{"NFC::MFIUser"} {
56 // clang-format off 57 // clang-format off
57 static const FunctionInfo functions[] = { 58 static const FunctionInfo functions[] = {
58 {0, nullptr, "Initialize"}, 59 {0, nullptr, "Initialize"},
@@ -100,13 +101,13 @@ private:
100 101
101class IUser final : public ServiceFramework<IUser> { 102class IUser final : public ServiceFramework<IUser> {
102public: 103public:
103 explicit IUser() : ServiceFramework{"IUser"} { 104 explicit IUser() : ServiceFramework{"NFC::IUser"} {
104 // clang-format off 105 // clang-format off
105 static const FunctionInfo functions[] = { 106 static const FunctionInfo functions[] = {
106 {0, nullptr, "Initialize"}, 107 {0, &IUser::InitializeOld, "InitializeOld"},
107 {1, nullptr, "Finalize"}, 108 {1, &IUser::FinalizeOld, "FinalizeOld"},
108 {2, nullptr, "GetState"}, 109 {2, &IUser::GetStateOld, "GetStateOld"},
109 {3, nullptr, "IsNfcEnabled"}, 110 {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"},
110 {400, nullptr, "Initialize"}, 111 {400, nullptr, "Initialize"},
111 {401, nullptr, "Finalize"}, 112 {401, nullptr, "Finalize"},
112 {402, nullptr, "GetState"}, 113 {402, nullptr, "GetState"},
@@ -130,11 +131,47 @@ public:
130 131
131 RegisterHandlers(functions); 132 RegisterHandlers(functions);
132 } 133 }
134
135private:
136 enum class NfcStates : u32 {
137 Finalized = 6,
138 };
139
140 void InitializeOld(Kernel::HLERequestContext& ctx) {
141 IPC::ResponseBuilder rb{ctx, 2, 0};
142 rb.Push(RESULT_SUCCESS);
143
144 // We don't deal with hardware initialization so we can just stub this.
145 LOG_DEBUG(Service_NFC, "called");
146 }
147
148 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
149 IPC::ResponseBuilder rb{ctx, 3};
150 rb.Push(RESULT_SUCCESS);
151 rb.PushRaw<u8>(Settings::values.enable_nfc);
152
153 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
154 }
155
156 void GetStateOld(Kernel::HLERequestContext& ctx) {
157 LOG_WARNING(Service_NFC, "(STUBBED) called");
158
159 IPC::ResponseBuilder rb{ctx, 3};
160 rb.Push(RESULT_SUCCESS);
161 rb.PushEnum(NfcStates::Finalized); // TODO(ogniK): Figure out if this matches nfp
162 }
163
164 void FinalizeOld(Kernel::HLERequestContext& ctx) {
165 LOG_WARNING(Service_NFC, "(STUBBED) called");
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(RESULT_SUCCESS);
169 }
133}; 170};
134 171
135class NFC_U final : public ServiceFramework<NFC_U> { 172class NFC_U final : public ServiceFramework<NFC_U> {
136public: 173public:
137 explicit NFC_U() : ServiceFramework{"nfc:u"} { 174 explicit NFC_U() : ServiceFramework{"nfc:user"} {
138 // clang-format off 175 // clang-format off
139 static const FunctionInfo functions[] = { 176 static const FunctionInfo functions[] = {
140 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, 177 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 39c0c1e63..9a4eb9301 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -2,56 +2,67 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <atomic>
6
5#include "common/logging/log.h" 7#include "common/logging/log.h"
6#include "core/core.h" 8#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/lock.h"
9#include "core/hle/service/hid/hid.h" 12#include "core/hle/service/hid/hid.h"
10#include "core/hle/service/nfp/nfp.h" 13#include "core/hle/service/nfp/nfp.h"
11#include "core/hle/service/nfp/nfp_user.h" 14#include "core/hle/service/nfp/nfp_user.h"
12 15
13namespace Service::NFP { 16namespace Service::NFP {
14 17
18namespace ErrCodes {
19constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
20 -1); // TODO(ogniK): Find the actual error code
21}
22
15Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 23Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
16 : ServiceFramework(name), module(std::move(module)) {} 24 : ServiceFramework(name), module(std::move(module)) {
25 auto& kernel = Core::System::GetInstance().Kernel();
26 nfc_tag_load =
27 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected");
28}
17 29
18Module::Interface::~Interface() = default; 30Module::Interface::~Interface() = default;
19 31
20class IUser final : public ServiceFramework<IUser> { 32class IUser final : public ServiceFramework<IUser> {
21public: 33public:
22 IUser() : ServiceFramework("IUser") { 34 IUser(Module::Interface& nfp_interface)
35 : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) {
23 static const FunctionInfo functions[] = { 36 static const FunctionInfo functions[] = {
24 {0, &IUser::Initialize, "Initialize"}, 37 {0, &IUser::Initialize, "Initialize"},
25 {1, nullptr, "Finalize"}, 38 {1, &IUser::Finalize, "Finalize"},
26 {2, &IUser::ListDevices, "ListDevices"}, 39 {2, &IUser::ListDevices, "ListDevices"},
27 {3, nullptr, "StartDetection"}, 40 {3, &IUser::StartDetection, "StartDetection"},
28 {4, nullptr, "StopDetection"}, 41 {4, &IUser::StopDetection, "StopDetection"},
29 {5, nullptr, "Mount"}, 42 {5, &IUser::Mount, "Mount"},
30 {6, nullptr, "Unmount"}, 43 {6, &IUser::Unmount, "Unmount"},
31 {7, nullptr, "OpenApplicationArea"}, 44 {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
32 {8, nullptr, "GetApplicationArea"}, 45 {8, &IUser::GetApplicationArea, "GetApplicationArea"},
33 {9, nullptr, "SetApplicationArea"}, 46 {9, nullptr, "SetApplicationArea"},
34 {10, nullptr, "Flush"}, 47 {10, nullptr, "Flush"},
35 {11, nullptr, "Restore"}, 48 {11, nullptr, "Restore"},
36 {12, nullptr, "CreateApplicationArea"}, 49 {12, nullptr, "CreateApplicationArea"},
37 {13, nullptr, "GetTagInfo"}, 50 {13, &IUser::GetTagInfo, "GetTagInfo"},
38 {14, nullptr, "GetRegisterInfo"}, 51 {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
39 {15, nullptr, "GetCommonInfo"}, 52 {15, &IUser::GetCommonInfo, "GetCommonInfo"},
40 {16, nullptr, "GetModelInfo"}, 53 {16, &IUser::GetModelInfo, "GetModelInfo"},
41 {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, 54 {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
42 {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, 55 {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
43 {19, &IUser::GetState, "GetState"}, 56 {19, &IUser::GetState, "GetState"},
44 {20, &IUser::GetDeviceState, "GetDeviceState"}, 57 {20, &IUser::GetDeviceState, "GetDeviceState"},
45 {21, &IUser::GetNpadId, "GetNpadId"}, 58 {21, &IUser::GetNpadId, "GetNpadId"},
46 {22, nullptr, "GetApplicationArea2"}, 59 {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
47 {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, 60 {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
48 {24, nullptr, "RecreateApplicationArea"}, 61 {24, nullptr, "RecreateApplicationArea"},
49 }; 62 };
50 RegisterHandlers(functions); 63 RegisterHandlers(functions);
51 64
52 auto& kernel = Core::System::GetInstance().Kernel(); 65 auto& kernel = Core::System::GetInstance().Kernel();
53 activate_event =
54 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:ActivateEvent");
55 deactivate_event = 66 deactivate_event =
56 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); 67 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
57 availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 68 availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
@@ -59,6 +70,17 @@ public:
59 } 70 }
60 71
61private: 72private:
73 struct TagInfo {
74 std::array<u8, 10> uuid;
75 u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
76 // mean something else
77 INSERT_PADDING_BYTES(0x15);
78 u32_le protocol;
79 u32_le tag_type;
80 INSERT_PADDING_BYTES(0x2c);
81 };
82 static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
83
62 enum class State : u32 { 84 enum class State : u32 {
63 NonInitialized = 0, 85 NonInitialized = 0,
64 Initialized = 1, 86 Initialized = 1,
@@ -66,15 +88,40 @@ private:
66 88
67 enum class DeviceState : u32 { 89 enum class DeviceState : u32 {
68 Initialized = 0, 90 Initialized = 0,
91 SearchingForTag = 1,
92 TagFound = 2,
93 TagRemoved = 3,
94 TagNearby = 4,
95 Unknown5 = 5,
96 Finalized = 6
69 }; 97 };
70 98
99 struct CommonInfo {
100 u16_be last_write_year;
101 u8 last_write_month;
102 u8 last_write_day;
103 u16_be write_counter;
104 u16_be version;
105 u32_be application_area_size;
106 INSERT_PADDING_BYTES(0x34);
107 };
108 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
109
71 void Initialize(Kernel::HLERequestContext& ctx) { 110 void Initialize(Kernel::HLERequestContext& ctx) {
72 LOG_WARNING(Service_NFP, "(STUBBED) called"); 111 IPC::ResponseBuilder rb{ctx, 2, 0};
112 rb.Push(RESULT_SUCCESS);
73 113
74 state = State::Initialized; 114 state = State::Initialized;
75 115
76 IPC::ResponseBuilder rb{ctx, 2}; 116 LOG_DEBUG(Service_NFC, "called");
117 }
118
119 void GetState(Kernel::HLERequestContext& ctx) {
120 IPC::ResponseBuilder rb{ctx, 3, 0};
77 rb.Push(RESULT_SUCCESS); 121 rb.Push(RESULT_SUCCESS);
122 rb.PushRaw<u32>(static_cast<u32>(state));
123
124 LOG_DEBUG(Service_NFC, "called");
78 } 125 }
79 126
80 void ListDevices(Kernel::HLERequestContext& ctx) { 127 void ListDevices(Kernel::HLERequestContext& ctx) {
@@ -83,80 +130,217 @@ private:
83 130
84 ctx.WriteBuffer(&device_handle, sizeof(device_handle)); 131 ctx.WriteBuffer(&device_handle, sizeof(device_handle));
85 132
86 LOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); 133 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
87 134
88 IPC::ResponseBuilder rb{ctx, 3}; 135 IPC::ResponseBuilder rb{ctx, 3};
89 rb.Push(RESULT_SUCCESS); 136 rb.Push(RESULT_SUCCESS);
90 rb.Push<u32>(0); 137 rb.Push<u32>(1);
91 } 138 }
92 139
93 void AttachActivateEvent(Kernel::HLERequestContext& ctx) { 140 void GetNpadId(Kernel::HLERequestContext& ctx) {
94 IPC::RequestParser rp{ctx}; 141 IPC::RequestParser rp{ctx};
95 const u64 dev_handle = rp.Pop<u64>(); 142 const u64 dev_handle = rp.Pop<u64>();
96 LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); 143 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
144 IPC::ResponseBuilder rb{ctx, 3};
145 rb.Push(RESULT_SUCCESS);
146 rb.Push<u32>(npad_id);
147 }
97 148
149 void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
150 IPC::RequestParser rp{ctx};
151 const u64 dev_handle = rp.Pop<u64>();
152 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
98 IPC::ResponseBuilder rb{ctx, 2, 1}; 153 IPC::ResponseBuilder rb{ctx, 2, 1};
99 rb.Push(RESULT_SUCCESS); 154 rb.Push(RESULT_SUCCESS);
100 rb.PushCopyObjects(activate_event); 155 rb.PushCopyObjects(nfp_interface.GetNFCEvent());
156 has_attached_handle = true;
101 } 157 }
102 158
103 void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { 159 void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
104 IPC::RequestParser rp{ctx}; 160 IPC::RequestParser rp{ctx};
105 const u64 dev_handle = rp.Pop<u64>(); 161 const u64 dev_handle = rp.Pop<u64>();
106 LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); 162 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
107 163
108 IPC::ResponseBuilder rb{ctx, 2, 1}; 164 IPC::ResponseBuilder rb{ctx, 2, 1};
109 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
110 rb.PushCopyObjects(deactivate_event); 166 rb.PushCopyObjects(deactivate_event);
111 } 167 }
112 168
113 void GetState(Kernel::HLERequestContext& ctx) { 169 void StopDetection(Kernel::HLERequestContext& ctx) {
114 LOG_WARNING(Service_NFP, "(STUBBED) called"); 170 LOG_DEBUG(Service_NFP, "called");
115 IPC::ResponseBuilder rb{ctx, 3}; 171 switch (device_state) {
172 case DeviceState::TagFound:
173 case DeviceState::TagNearby:
174 deactivate_event->Signal();
175 device_state = DeviceState::Initialized;
176 break;
177 case DeviceState::SearchingForTag:
178 case DeviceState::TagRemoved:
179 device_state = DeviceState::Initialized;
180 break;
181 }
182 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(RESULT_SUCCESS); 183 rb.Push(RESULT_SUCCESS);
117 rb.Push<u32>(static_cast<u32>(state));
118 } 184 }
119 185
120 void GetDeviceState(Kernel::HLERequestContext& ctx) { 186 void GetDeviceState(Kernel::HLERequestContext& ctx) {
121 LOG_WARNING(Service_NFP, "(STUBBED) called"); 187 LOG_DEBUG(Service_NFP, "called");
188 auto nfc_event = nfp_interface.GetNFCEvent();
189 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
190 device_state = DeviceState::TagFound;
191 nfc_event->Clear();
192 }
193
122 IPC::ResponseBuilder rb{ctx, 3}; 194 IPC::ResponseBuilder rb{ctx, 3};
123 rb.Push(RESULT_SUCCESS); 195 rb.Push(RESULT_SUCCESS);
124 rb.Push<u32>(static_cast<u32>(device_state)); 196 rb.Push<u32>(static_cast<u32>(device_state));
125 } 197 }
126 198
127 void GetNpadId(Kernel::HLERequestContext& ctx) { 199 void StartDetection(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 200 LOG_DEBUG(Service_NFP, "called");
129 const u64 dev_handle = rp.Pop<u64>(); 201
130 LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); 202 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
131 IPC::ResponseBuilder rb{ctx, 3}; 203 device_state = DeviceState::SearchingForTag;
204 }
205 IPC::ResponseBuilder rb{ctx, 2};
206 rb.Push(RESULT_SUCCESS);
207 }
208
209 void GetTagInfo(Kernel::HLERequestContext& ctx) {
210 LOG_DEBUG(Service_NFP, "called");
211
212 IPC::ResponseBuilder rb{ctx, 2};
213 auto amiibo = nfp_interface.GetAmiiboBuffer();
214 TagInfo tag_info{};
215 std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size()));
216 tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
217
218 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
219 tag_info.tag_type = 2;
220 ctx.WriteBuffer(&tag_info, sizeof(TagInfo));
221 rb.Push(RESULT_SUCCESS);
222 }
223
224 void Mount(Kernel::HLERequestContext& ctx) {
225 LOG_DEBUG(Service_NFP, "called");
226
227 device_state = DeviceState::TagNearby;
228 IPC::ResponseBuilder rb{ctx, 2};
229 rb.Push(RESULT_SUCCESS);
230 }
231
232 void GetModelInfo(Kernel::HLERequestContext& ctx) {
233 LOG_DEBUG(Service_NFP, "called");
234
235 IPC::ResponseBuilder rb{ctx, 2};
236 auto amiibo = nfp_interface.GetAmiiboBuffer();
237 ctx.WriteBuffer(&amiibo.model_info, sizeof(amiibo.model_info));
238 rb.Push(RESULT_SUCCESS);
239 }
240
241 void Unmount(Kernel::HLERequestContext& ctx) {
242 LOG_DEBUG(Service_NFP, "called");
243
244 device_state = DeviceState::TagFound;
245
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(RESULT_SUCCESS);
248 }
249
250 void Finalize(Kernel::HLERequestContext& ctx) {
251 LOG_DEBUG(Service_NFP, "called");
252
253 device_state = DeviceState::Finalized;
254
255 IPC::ResponseBuilder rb{ctx, 2};
132 rb.Push(RESULT_SUCCESS); 256 rb.Push(RESULT_SUCCESS);
133 rb.Push<u32>(npad_id);
134 } 257 }
135 258
136 void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { 259 void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
137 IPC::RequestParser rp{ctx}; 260 LOG_WARNING(Service_NFP, "(STUBBED) called");
138 const u64 dev_handle = rp.Pop<u64>();
139 LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
140 261
141 IPC::ResponseBuilder rb{ctx, 2, 1}; 262 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS); 263 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(availability_change_event); 264 rb.PushCopyObjects(availability_change_event);
144 } 265 }
145 266
146 const u64 device_handle{0xDEAD}; 267 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
147 const u32 npad_id{0}; // This is the first player controller id 268 LOG_WARNING(Service_NFP, "(STUBBED) called");
269
270 // TODO(ogniK): Pull Mii and owner data from amiibo
271
272 IPC::ResponseBuilder rb{ctx, 2};
273 rb.Push(RESULT_SUCCESS);
274 }
275
276 void GetCommonInfo(Kernel::HLERequestContext& ctx) {
277 LOG_WARNING(Service_NFP, "(STUBBED) called");
278
279 // TODO(ogniK): Pull common information from amiibo
280
281 CommonInfo common_info{};
282 common_info.application_area_size = 0;
283 ctx.WriteBuffer(&common_info, sizeof(CommonInfo));
284
285 IPC::ResponseBuilder rb{ctx, 2};
286 rb.Push(RESULT_SUCCESS);
287 }
288
289 void OpenApplicationArea(Kernel::HLERequestContext& ctx) {
290 LOG_DEBUG(Service_NFP, "called");
291 // We don't need to worry about this since we can just open the file
292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(RESULT_SUCCESS);
294 }
295
296 void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
297 LOG_WARNING(Service_NFP, "(STUBBED) called");
298 // We don't need to worry about this since we can just open the file
299 IPC::ResponseBuilder rb{ctx, 3};
300 rb.Push(RESULT_SUCCESS);
301 rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
302 }
303
304 void GetApplicationArea(Kernel::HLERequestContext& ctx) {
305 LOG_WARNING(Service_NFP, "(STUBBED) called");
306
307 // TODO(ogniK): Pull application area from amiibo
308
309 IPC::ResponseBuilder rb{ctx, 3};
310 rb.Push(RESULT_SUCCESS);
311 rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
312 }
313
314 bool has_attached_handle{};
315 const u64 device_handle{Common::MakeMagic('Y', 'U', 'Z', 'U')};
316 const u32 npad_id{0}; // Player 1 controller
148 State state{State::NonInitialized}; 317 State state{State::NonInitialized};
149 DeviceState device_state{DeviceState::Initialized}; 318 DeviceState device_state{DeviceState::Initialized};
150 Kernel::SharedPtr<Kernel::Event> activate_event;
151 Kernel::SharedPtr<Kernel::Event> deactivate_event; 319 Kernel::SharedPtr<Kernel::Event> deactivate_event;
152 Kernel::SharedPtr<Kernel::Event> availability_change_event; 320 Kernel::SharedPtr<Kernel::Event> availability_change_event;
321 const Module::Interface& nfp_interface;
153}; 322};
154 323
155void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 324void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
156 LOG_DEBUG(Service_NFP, "called"); 325 LOG_DEBUG(Service_NFP, "called");
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 326 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(RESULT_SUCCESS); 327 rb.Push(RESULT_SUCCESS);
159 rb.PushIpcInterface<IUser>(); 328 rb.PushIpcInterface<IUser>(*this);
329}
330
331void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
332 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
333 if (buffer.size() < sizeof(AmiiboFile)) {
334 return; // Failed to load file
335 }
336 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
337 nfc_tag_load->Signal();
338}
339const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const {
340 return nfc_tag_load;
341}
342const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
343 return amiibo;
160} 344}
161 345
162void InstallInterfaces(SM::ServiceManager& service_manager) { 346void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 77df343c4..46370dedd 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <vector>
9#include "core/hle/kernel/event.h"
7#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
8 11
9namespace Service::NFP { 12namespace Service::NFP {
@@ -15,7 +18,27 @@ public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 18 explicit Interface(std::shared_ptr<Module> module, const char* name);
16 ~Interface() override; 19 ~Interface() override;
17 20
21 struct ModelInfo {
22 std::array<u8, 0x8> amiibo_identification_block;
23 INSERT_PADDING_BYTES(0x38);
24 };
25 static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
26
27 struct AmiiboFile {
28 std::array<u8, 10> uuid;
29 INSERT_PADDING_BYTES(0x4a);
30 ModelInfo model_info;
31 };
32 static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size");
33
18 void CreateUserInterface(Kernel::HLERequestContext& ctx); 34 void CreateUserInterface(Kernel::HLERequestContext& ctx);
35 void LoadAmiibo(const std::vector<u8>& buffer);
36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const;
37 const AmiiboFile& GetAmiiboBuffer() const;
38
39 private:
40 Kernel::SharedPtr<Kernel::Event> nfc_tag_load{};
41 AmiiboFile amiibo{};
19 42
20 protected: 43 protected:
21 std::shared_ptr<Module> module; 44 std::shared_ptr<Module> module;
diff --git a/src/core/settings.h b/src/core/settings.h
index 8f2da01c8..ca80718e2 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -113,6 +113,7 @@ static const std::array<const char*, NumAnalogs> mapping = {{
113struct Values { 113struct Values {
114 // System 114 // System
115 bool use_docked_mode; 115 bool use_docked_mode;
116 bool enable_nfc;
116 std::string username; 117 std::string username;
117 int language_index; 118 int language_index;
118 119
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 71c6ebb41..d029590ff 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -122,6 +122,7 @@ void Config::ReadValues() {
122 122
123 qt_config->beginGroup("System"); 123 qt_config->beginGroup("System");
124 Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool(); 124 Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
125 Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool();
125 Settings::values.username = qt_config->value("username", "yuzu").toString().toStdString(); 126 Settings::values.username = qt_config->value("username", "yuzu").toString().toStdString();
126 Settings::values.language_index = qt_config->value("language_index", 1).toInt(); 127 Settings::values.language_index = qt_config->value("language_index", 1).toInt();
127 qt_config->endGroup(); 128 qt_config->endGroup();
@@ -258,6 +259,7 @@ void Config::SaveValues() {
258 259
259 qt_config->beginGroup("System"); 260 qt_config->beginGroup("System");
260 qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode); 261 qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
262 qt_config->setValue("enable_nfc", Settings::values.enable_nfc);
261 qt_config->setValue("username", QString::fromStdString(Settings::values.username)); 263 qt_config->setValue("username", QString::fromStdString(Settings::values.username));
262 qt_config->setValue("language_index", Settings::values.language_index); 264 qt_config->setValue("language_index", Settings::values.language_index);
263 qt_config->endGroup(); 265 qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index f5db9e55b..537d6e576 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -31,6 +31,7 @@ void ConfigureGeneral::setConfiguration() {
31 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 31 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
32 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); 32 ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
33 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode); 33 ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
34 ui->enable_nfc->setChecked(Settings::values.enable_nfc);
34} 35}
35 36
36void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { 37void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
@@ -45,4 +46,5 @@ void ConfigureGeneral::applyConfiguration() {
45 46
46 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked(); 47 Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
47 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked(); 48 Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
49 Settings::values.enable_nfc = ui->enable_nfc->isChecked();
48} 50}
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 1775c4d40..b82fffde8 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -68,19 +68,26 @@
68 <property name="title"> 68 <property name="title">
69 <string>Emulation</string> 69 <string>Emulation</string>
70 </property> 70 </property>
71 <layout class="QHBoxLayout" name="EmulationHorizontalLayout"> 71 <layout class="QHBoxLayout" name="EmulationHorizontalLayout">
72 <item>
73 <layout class="QVBoxLayout" name="EmulationVerticalLayout">
74 <item>
75 <widget class="QCheckBox" name="use_docked_mode">
76 <property name="text">
77 <string>Enable docked mode</string>
78 </property>
79 </widget>
80 </item>
72 <item> 81 <item>
73 <layout class="QVBoxLayout" name="EmulationVerticalLayout"> 82 <widget class="QCheckBox" name="enable_nfc">
74 <item> 83 <property name="text">
75 <widget class="QCheckBox" name="use_docked_mode"> 84 <string>Enable NFC</string>
76 <property name="text"> 85 </property>
77 <string>Enable docked mode</string> 86 </widget>
78 </property>
79 </widget>
80 </item>
81 </layout>
82 </item> 87 </item>
83 </layout> 88 </layout>
89 </item>
90 </layout>
84 </widget> 91 </widget>
85 </item> 92 </item>
86 <item> 93 <item>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 36c702195..be9896614 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -60,6 +60,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
60#include "core/hle/kernel/process.h" 60#include "core/hle/kernel/process.h"
61#include "core/hle/service/filesystem/filesystem.h" 61#include "core/hle/service/filesystem/filesystem.h"
62#include "core/hle/service/filesystem/fsp_ldr.h" 62#include "core/hle/service/filesystem/fsp_ldr.h"
63#include "core/hle/service/nfp/nfp.h"
64#include "core/hle/service/sm/sm.h"
63#include "core/loader/loader.h" 65#include "core/loader/loader.h"
64#include "core/perf_stats.h" 66#include "core/perf_stats.h"
65#include "core/settings.h" 67#include "core/settings.h"
@@ -424,6 +426,7 @@ void GMainWindow::ConnectMenuEvents() {
424 connect(ui.action_Select_SDMC_Directory, &QAction::triggered, this, 426 connect(ui.action_Select_SDMC_Directory, &QAction::triggered, this,
425 [this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::SDMC); }); 427 [this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::SDMC); });
426 connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); 428 connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close);
429 connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
427 430
428 // Emulation 431 // Emulation
429 connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); 432 connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
@@ -692,6 +695,7 @@ void GMainWindow::ShutdownGame() {
692 ui.action_Stop->setEnabled(false); 695 ui.action_Stop->setEnabled(false);
693 ui.action_Restart->setEnabled(false); 696 ui.action_Restart->setEnabled(false);
694 ui.action_Report_Compatibility->setEnabled(false); 697 ui.action_Report_Compatibility->setEnabled(false);
698 ui.action_Load_Amiibo->setEnabled(false);
695 render_window->hide(); 699 render_window->hide();
696 game_list->show(); 700 game_list->show();
697 game_list->setFilterFocus(); 701 game_list->setFilterFocus();
@@ -1191,6 +1195,7 @@ void GMainWindow::OnStartGame() {
1191 ui.action_Report_Compatibility->setEnabled(true); 1195 ui.action_Report_Compatibility->setEnabled(true);
1192 1196
1193 discord_rpc->Update(); 1197 discord_rpc->Update();
1198 ui.action_Load_Amiibo->setEnabled(true);
1194} 1199}
1195 1200
1196void GMainWindow::OnPauseGame() { 1201void GMainWindow::OnPauseGame() {
@@ -1295,6 +1300,27 @@ void GMainWindow::OnConfigure() {
1295 } 1300 }
1296} 1301}
1297 1302
1303void GMainWindow::OnLoadAmiibo() {
1304 const QString extensions{"*.bin"};
1305 const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
1306 const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter);
1307 if (!filename.isEmpty()) {
1308 Core::System& system{Core::System::GetInstance()};
1309 Service::SM::ServiceManager& sm = system.ServiceManager();
1310 auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
1311 if (nfc != nullptr) {
1312 auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb");
1313 if (!nfc_file.IsOpen()) {
1314 return;
1315 }
1316 std::vector<u8> amiibo_buffer(nfc_file.GetSize());
1317 nfc_file.ReadBytes(amiibo_buffer.data(), amiibo_buffer.size());
1318 nfc_file.Close();
1319 nfc->LoadAmiibo(amiibo_buffer);
1320 }
1321 }
1322}
1323
1298void GMainWindow::OnAbout() { 1324void GMainWindow::OnAbout() {
1299 AboutDialog aboutDialog(this); 1325 AboutDialog aboutDialog(this);
1300 aboutDialog.exec(); 1326 aboutDialog.exec();
@@ -1335,15 +1361,17 @@ void GMainWindow::UpdateStatusBar() {
1335void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) { 1361void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
1336 QMessageBox::StandardButton answer; 1362 QMessageBox::StandardButton answer;
1337 QString status_message; 1363 QString status_message;
1338 const QString common_message = tr( 1364 const QString common_message =
1339 "The game you are trying to load requires additional files from your Switch to be dumped " 1365 tr("The game you are trying to load requires additional files from your Switch to be "
1340 "before playing.<br/><br/>For more information on dumping these files, please see the " 1366 "dumped "
1341 "following wiki page: <a " 1367 "before playing.<br/><br/>For more information on dumping these files, please see the "
1342 "href='https://yuzu-emu.org/wiki/" 1368 "following wiki page: <a "
1343 "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System " 1369 "href='https://yuzu-emu.org/wiki/"
1344 "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit " 1370 "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
1345 "back to the game list? Continuing emulation may result in crashes, corrupted save " 1371 "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to "
1346 "data, or other bugs."); 1372 "quit "
1373 "back to the game list? Continuing emulation may result in crashes, corrupted save "
1374 "data, or other bugs.");
1347 switch (result) { 1375 switch (result) {
1348 case Core::System::ResultStatus::ErrorSystemFiles: { 1376 case Core::System::ResultStatus::ErrorSystemFiles: {
1349 QString message = "yuzu was unable to locate a Switch system archive"; 1377 QString message = "yuzu was unable to locate a Switch system archive";
@@ -1374,9 +1402,12 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
1374 this, tr("Fatal Error"), 1402 this, tr("Fatal Error"),
1375 tr("yuzu has encountered a fatal error, please see the log for more details. " 1403 tr("yuzu has encountered a fatal error, please see the log for more details. "
1376 "For more information on accessing the log, please see the following page: " 1404 "For more information on accessing the log, please see the following page: "
1377 "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to " 1405 "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
1378 "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? " 1406 "to "
1379 "Continuing emulation may result in crashes, corrupted save data, or other bugs."), 1407 "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game "
1408 "list? "
1409 "Continuing emulation may result in crashes, corrupted save data, or other "
1410 "bugs."),
1380 QMessageBox::Yes | QMessageBox::No, QMessageBox::No); 1411 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
1381 status_message = "Fatal Error encountered"; 1412 status_message = "Fatal Error encountered";
1382 break; 1413 break;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index c8cbc0ba8..7c7c223e1 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -166,6 +166,7 @@ private slots:
166 void OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target); 166 void OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target);
167 void OnMenuRecentFile(); 167 void OnMenuRecentFile();
168 void OnConfigure(); 168 void OnConfigure();
169 void OnLoadAmiibo();
169 void OnAbout(); 170 void OnAbout();
170 void OnToggleFilterBar(); 171 void OnToggleFilterBar();
171 void OnDisplayTitleBars(bool); 172 void OnDisplayTitleBars(bool);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index dffd9c788..48d099591 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -57,8 +57,8 @@
57 <string>Recent Files</string> 57 <string>Recent Files</string>
58 </property> 58 </property>
59 </widget> 59 </widget>
60 <addaction name="action_Install_File_NAND" /> 60 <addaction name="action_Install_File_NAND"/>
61 <addaction name="separator"/> 61 <addaction name="separator"/>
62 <addaction name="action_Load_File"/> 62 <addaction name="action_Load_File"/>
63 <addaction name="action_Load_Folder"/> 63 <addaction name="action_Load_Folder"/>
64 <addaction name="separator"/> 64 <addaction name="separator"/>
@@ -68,6 +68,8 @@
68 <addaction name="action_Select_NAND_Directory"/> 68 <addaction name="action_Select_NAND_Directory"/>
69 <addaction name="action_Select_SDMC_Directory"/> 69 <addaction name="action_Select_SDMC_Directory"/>
70 <addaction name="separator"/> 70 <addaction name="separator"/>
71 <addaction name="action_Load_Amiibo"/>
72 <addaction name="separator"/>
71 <addaction name="action_Exit"/> 73 <addaction name="action_Exit"/>
72 </widget> 74 </widget>
73 <widget class="QMenu" name="menu_Emulation"> 75 <widget class="QMenu" name="menu_Emulation">
@@ -117,11 +119,14 @@
117 <addaction name="menu_Tools" /> 119 <addaction name="menu_Tools" />
118 <addaction name="menu_Help"/> 120 <addaction name="menu_Help"/>
119 </widget> 121 </widget>
120 <action name="action_Install_File_NAND"> 122 <action name="action_Install_File_NAND">
121 <property name="text"> 123 <property name="enabled">
122 <string>Install File to NAND...</string> 124 <bool>true</bool>
123 </property> 125 </property>
124 </action> 126 <property name="text">
127 <string>Install File to NAND...</string>
128 </property>
129 </action>
125 <action name="action_Load_File"> 130 <action name="action_Load_File">
126 <property name="text"> 131 <property name="text">
127 <string>Load File...</string> 132 <string>Load File...</string>
@@ -253,6 +258,14 @@
253 <string>Restart</string> 258 <string>Restart</string>
254 </property> 259 </property>
255 </action> 260 </action>
261 <action name="action_Load_Amiibo">
262 <property name="enabled">
263 <bool>false</bool>
264 </property>
265 <property name="text">
266 <string>Load Amiibo...</string>
267 </property>
268 </action>
256 <action name="action_Report_Compatibility"> 269 <action name="action_Report_Compatibility">
257 <property name="enabled"> 270 <property name="enabled">
258 <bool>false</bool> 271 <bool>false</bool>
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 5e42e48b2..654a15a5c 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -125,6 +125,7 @@ void Config::ReadValues() {
125 125
126 // System 126 // System
127 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); 127 Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
128 Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true);
128 Settings::values.username = sdl2_config->Get("System", "username", "yuzu"); 129 Settings::values.username = sdl2_config->Get("System", "username", "yuzu");
129 if (Settings::values.username.empty()) { 130 if (Settings::values.username.empty()) {
130 Settings::values.username = "yuzu"; 131 Settings::values.username = "yuzu";
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index a97b75f7b..e0b223cd6 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -174,6 +174,10 @@ use_virtual_sd =
174# 1: Yes, 0 (default): No 174# 1: Yes, 0 (default): No
175use_docked_mode = 175use_docked_mode =
176 176
177# Allow the use of NFC in games
178# 1 (default): Yes, 0 : No
179enable_nfc =
180
177# Sets the account username, max length is 32 characters 181# Sets the account username, max length is 32 characters
178# yuzu (default) 182# yuzu (default)
179username = yuzu 183username = yuzu