summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/hid/emulated_controller.cpp82
-rw-r--r--src/core/hid/emulated_controller.h28
-rw-r--r--src/core/hid/input_converter.cpp6
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp2
-rw-r--r--src/core/hle/service/nfc/common/device.cpp182
-rw-r--r--src/core/hle/service/nfc/common/device.h10
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp11
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h2
-rw-r--r--src/core/hle/service/nfc/mifare_types.h11
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp7
10 files changed, 209 insertions, 132 deletions
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 0a7777732..c937495f9 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -149,12 +149,16 @@ void EmulatedController::LoadDevices() {
149 149
150 camera_params[0] = right_joycon; 150 camera_params[0] = right_joycon;
151 camera_params[0].Set("camera", true); 151 camera_params[0].Set("camera", true);
152 camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
153 ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
154 nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
155 nfc_params[1] = right_joycon; 152 nfc_params[1] = right_joycon;
156 nfc_params[1].Set("nfc", true); 153 nfc_params[1].Set("nfc", true);
157 154
155 // Only map virtual devices to the first controller
156 if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) {
157 camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
158 ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
159 nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
160 }
161
158 output_params[LeftIndex] = left_joycon; 162 output_params[LeftIndex] = left_joycon;
159 output_params[RightIndex] = right_joycon; 163 output_params[RightIndex] = right_joycon;
160 output_params[2] = camera_params[1]; 164 output_params[2] = camera_params[1];
@@ -1176,10 +1180,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
1176 return; 1180 return;
1177 } 1181 }
1178 1182
1179 controller.nfc_state = { 1183 controller.nfc_state = controller.nfc_values;
1180 controller.nfc_values.state,
1181 controller.nfc_values.data,
1182 };
1183} 1184}
1184 1185
1185bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { 1186bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
@@ -1308,6 +1309,73 @@ bool EmulatedController::HasNfc() const {
1308 return is_connected && (has_virtual_nfc && is_virtual_nfc_supported); 1309 return is_connected && (has_virtual_nfc && is_virtual_nfc_supported);
1309} 1310}
1310 1311
1312bool EmulatedController::AddNfcHandle() {
1313 nfc_handles++;
1314 return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) ==
1315 Common::Input::DriverResult::Success;
1316}
1317
1318bool EmulatedController::RemoveNfcHandle() {
1319 nfc_handles--;
1320 if (nfc_handles <= 0) {
1321 return SetPollingMode(EmulatedDeviceIndex::RightIndex,
1322 Common::Input::PollingMode::Active) ==
1323 Common::Input::DriverResult::Success;
1324 }
1325 return true;
1326}
1327
1328bool EmulatedController::StartNfcPolling() {
1329 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1330 auto& nfc_virtual_output_device = output_devices[3];
1331
1332 return nfc_output_device->StartNfcPolling() == Common::Input::NfcState::Success ||
1333 nfc_virtual_output_device->StartNfcPolling() == Common::Input::NfcState::Success;
1334}
1335
1336bool EmulatedController::StopNfcPolling() {
1337 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1338 auto& nfc_virtual_output_device = output_devices[3];
1339
1340 return nfc_output_device->StopNfcPolling() == Common::Input::NfcState::Success ||
1341 nfc_virtual_output_device->StopNfcPolling() == Common::Input::NfcState::Success;
1342}
1343
1344bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
1345 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1346 auto& nfc_virtual_output_device = output_devices[3];
1347
1348 if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) {
1349 return true;
1350 }
1351
1352 return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success;
1353}
1354
1355bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
1356 Common::Input::MifareRequest& out_data) {
1357 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1358 auto& nfc_virtual_output_device = output_devices[3];
1359
1360 if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) {
1361 return true;
1362 }
1363
1364 return nfc_virtual_output_device->ReadMifareData(request, out_data) ==
1365 Common::Input::NfcState::Success;
1366}
1367
1368bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
1369 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1370 auto& nfc_virtual_output_device = output_devices[3];
1371
1372 if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) {
1373 return true;
1374 }
1375
1376 return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success;
1377}
1378
1311bool EmulatedController::WriteNfc(const std::vector<u8>& data) { 1379bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
1312 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; 1380 auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
1313 auto& nfc_virtual_output_device = output_devices[3]; 1381 auto& nfc_virtual_output_device = output_devices[3];
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 09fe1a0ab..d511e5fac 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -97,10 +97,7 @@ struct RingSensorForce {
97 f32 force; 97 f32 force;
98}; 98};
99 99
100struct NfcState { 100using NfcState = Common::Input::NfcStatus;
101 Common::Input::NfcState state{};
102 std::vector<u8> data{};
103};
104 101
105struct ControllerMotion { 102struct ControllerMotion {
106 Common::Vec3f accel{}; 103 Common::Vec3f accel{};
@@ -393,9 +390,31 @@ public:
393 /// Returns true if the device has nfc support 390 /// Returns true if the device has nfc support
394 bool HasNfc() const; 391 bool HasNfc() const;
395 392
393 /// Sets the joycon in nfc mode and increments the handle count
394 bool AddNfcHandle();
395
396 /// Decrements the handle count if zero sets the joycon in active mode
397 bool RemoveNfcHandle();
398
399 /// Start searching for nfc tags
400 bool StartNfcPolling();
401
402 /// Stop searching for nfc tags
403 bool StopNfcPolling();
404
405 /// Returns true if the nfc tag was readable
406 bool ReadAmiiboData(std::vector<u8>& data);
407
396 /// Returns true if the nfc tag was written 408 /// Returns true if the nfc tag was written
397 bool WriteNfc(const std::vector<u8>& data); 409 bool WriteNfc(const std::vector<u8>& data);
398 410
411 /// Returns true if the nfc tag was readable
412 bool ReadMifareData(const Common::Input::MifareRequest& request,
413 Common::Input::MifareRequest& out_data);
414
415 /// Returns true if the nfc tag was written
416 bool WriteMifareData(const Common::Input::MifareRequest& request);
417
399 /// Returns the led pattern corresponding to this emulated controller 418 /// Returns the led pattern corresponding to this emulated controller
400 LedPattern GetLedPattern() const; 419 LedPattern GetLedPattern() const;
401 420
@@ -532,6 +551,7 @@ private:
532 bool system_buttons_enabled{true}; 551 bool system_buttons_enabled{true};
533 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; 552 f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
534 u32 turbo_button_state{0}; 553 u32 turbo_button_state{0};
554 std::size_t nfc_handles{0};
535 555
536 // Temporary values to avoid doing changes while the controller is in configuring mode 556 // Temporary values to avoid doing changes while the controller is in configuring mode
537 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; 557 NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 4ccb1c596..a05716fd8 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -299,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
299 Common::Input::NfcStatus nfc{}; 299 Common::Input::NfcStatus nfc{};
300 switch (callback.type) { 300 switch (callback.type) {
301 case Common::Input::InputType::Nfc: 301 case Common::Input::InputType::Nfc:
302 nfc = { 302 return callback.nfc_status;
303 .state = callback.nfc_status,
304 .data = callback.raw_data,
305 };
306 break;
307 default: 303 default:
308 LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type); 304 LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
309 break; 305 break;
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index 8b754e9d4..19ed184e8 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -141,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
141 applet_output.device_handle = applet_input_common.device_handle; 141 applet_output.device_handle = applet_input_common.device_handle;
142 applet_output.result = CabinetResult::Cancel; 142 applet_output.result = CabinetResult::Cancel;
143 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); 143 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
144 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false); 144 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
145 nfp_device->Finalize(); 145 nfp_device->Finalize();
146 146
147 if (reg_result.IsSuccess()) { 147 if (reg_result.IsSuccess()) {
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index f4b180b06..5bf289818 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -93,7 +93,8 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
93 const auto nfc_status = npad_device->GetNfc(); 93 const auto nfc_status = npad_device->GetNfc();
94 switch (nfc_status.state) { 94 switch (nfc_status.state) {
95 case Common::Input::NfcState::NewAmiibo: 95 case Common::Input::NfcState::NewAmiibo:
96 LoadNfcTag(nfc_status.data); 96 LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length,
97 nfc_status.uuid);
97 break; 98 break;
98 case Common::Input::NfcState::AmiiboRemoved: 99 case Common::Input::NfcState::AmiiboRemoved:
99 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { 100 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
@@ -108,28 +109,46 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
108 } 109 }
109} 110}
110 111
111bool NfcDevice::LoadNfcTag(std::span<const u8> data) { 112bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) {
112 if (device_state != DeviceState::SearchingForTag) { 113 if (device_state != DeviceState::SearchingForTag) {
113 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); 114 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
114 return false; 115 return false;
115 } 116 }
116 117
118 if ((protocol & static_cast<u8>(allowed_protocols)) == 0) {
119 LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol);
120 return false;
121 }
122
123 real_tag_info = {
124 .uuid = uuid,
125 .uuid_length = uuid_length,
126 .protocol = static_cast<NfcProtocol>(protocol),
127 .tag_type = static_cast<TagType>(tag_type),
128 };
129
130 device_state = DeviceState::TagFound;
131 deactivate_event->GetReadableEvent().Clear();
132 activate_event->Signal();
133 return true;
134}
135
136bool NfcDevice::LoadAmiiboData() {
137 std::vector<u8> data{};
138
139 if (!npad_device->ReadAmiiboData(data)) {
140 return false;
141 }
142
117 if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { 143 if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
118 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); 144 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
119 return false; 145 return false;
120 } 146 }
121 147
122 mifare_data.resize(data.size());
123 memcpy(mifare_data.data(), data.data(), data.size());
124
125 memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); 148 memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
126 is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data); 149 is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
127 is_write_protected = false; 150 is_write_protected = false;
128 151
129 device_state = DeviceState::TagFound;
130 deactivate_event->GetReadableEvent().Clear();
131 activate_event->Signal();
132
133 // Fallback for plain amiibos 152 // Fallback for plain amiibos
134 if (is_plain_amiibo) { 153 if (is_plain_amiibo) {
135 LOG_INFO(Service_NFP, "Using plain amiibo"); 154 LOG_INFO(Service_NFP, "Using plain amiibo");
@@ -147,6 +166,7 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
147 return true; 166 return true;
148 } 167 }
149 168
169 LOG_INFO(Service_NFP, "Using encrypted amiibo");
150 tag_data = {}; 170 tag_data = {};
151 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); 171 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
152 return true; 172 return true;
@@ -162,7 +182,6 @@ void NfcDevice::CloseNfcTag() {
162 device_state = DeviceState::TagRemoved; 182 device_state = DeviceState::TagRemoved;
163 encrypted_tag_data = {}; 183 encrypted_tag_data = {};
164 tag_data = {}; 184 tag_data = {};
165 mifare_data = {};
166 activate_event->GetReadableEvent().Clear(); 185 activate_event->GetReadableEvent().Clear();
167 deactivate_event->Signal(); 186 deactivate_event->Signal();
168} 187}
@@ -179,8 +198,12 @@ void NfcDevice::Initialize() {
179 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable; 198 device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
180 encrypted_tag_data = {}; 199 encrypted_tag_data = {};
181 tag_data = {}; 200 tag_data = {};
182 mifare_data = {}; 201
183 is_initalized = true; 202 if (device_state != DeviceState::Initialized) {
203 return;
204 }
205
206 is_initalized = npad_device->AddNfcHandle();
184} 207}
185 208
186void NfcDevice::Finalize() { 209void NfcDevice::Finalize() {
@@ -190,6 +213,11 @@ void NfcDevice::Finalize() {
190 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { 213 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
191 StopDetection(); 214 StopDetection();
192 } 215 }
216
217 if (device_state != DeviceState::Unavailable) {
218 npad_device->RemoveNfcHandle();
219 }
220
193 device_state = DeviceState::Unavailable; 221 device_state = DeviceState::Unavailable;
194 is_initalized = false; 222 is_initalized = false;
195} 223}
@@ -200,10 +228,8 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
200 return ResultWrongDeviceState; 228 return ResultWrongDeviceState;
201 } 229 }
202 230
203 if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, 231 if (!npad_device->StartNfcPolling()) {
204 Common::Input::PollingMode::NFC) != 232 LOG_ERROR(Service_NFC, "Nfc polling not supported");
205 Common::Input::DriverResult::Success) {
206 LOG_ERROR(Service_NFC, "Nfc not supported");
207 return ResultNfcDisabled; 233 return ResultNfcDisabled;
208 } 234 }
209 235
@@ -213,9 +239,6 @@ Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
213} 239}
214 240
215Result NfcDevice::StopDetection() { 241Result NfcDevice::StopDetection() {
216 npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
217 Common::Input::PollingMode::Active);
218
219 if (device_state == DeviceState::Initialized) { 242 if (device_state == DeviceState::Initialized) {
220 return ResultSuccess; 243 return ResultSuccess;
221 } 244 }
@@ -225,6 +248,7 @@ Result NfcDevice::StopDetection() {
225 } 248 }
226 249
227 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { 250 if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
251 npad_device->StopNfcPolling();
228 device_state = DeviceState::Initialized; 252 device_state = DeviceState::Initialized;
229 return ResultSuccess; 253 return ResultSuccess;
230 } 254 }
@@ -233,7 +257,7 @@ Result NfcDevice::StopDetection() {
233 return ResultWrongDeviceState; 257 return ResultWrongDeviceState;
234} 258}
235 259
236Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { 260Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
237 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) { 261 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
238 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); 262 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
239 if (device_state == DeviceState::TagRemoved) { 263 if (device_state == DeviceState::TagRemoved) {
@@ -242,41 +266,15 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
242 return ResultWrongDeviceState; 266 return ResultWrongDeviceState;
243 } 267 }
244 268
245 UniqueSerialNumber uuid{}; 269 tag_info = real_tag_info;
246 u8 uuid_length{};
247 NfcProtocol protocol{NfcProtocol::TypeA};
248 TagType tag_type{TagType::Type2};
249
250 if (is_mifare) {
251 tag_type = TagType::Mifare;
252 uuid_length = sizeof(NFP::NtagTagUuid);
253 memcpy(uuid.data(), mifare_data.data(), uuid_length);
254 } else {
255 tag_type = TagType::Type2;
256 uuid_length = sizeof(NFP::NtagTagUuid);
257 NFP::NtagTagUuid nUuid{
258 .part1 = encrypted_tag_data.uuid.part1,
259 .part2 = encrypted_tag_data.uuid.part2,
260 .nintendo_id = encrypted_tag_data.uuid.nintendo_id,
261 };
262 memcpy(uuid.data(), &nUuid, uuid_length);
263 270
264 // Generate random UUID to bypass amiibo load limits 271 // Generate random UUID to bypass amiibo load limits
265 if (Settings::values.random_amiibo_id) { 272 if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) {
266 Common::TinyMT rng{}; 273 Common::TinyMT rng{};
267 rng.Initialize(static_cast<u32>(GetCurrentPosixTime())); 274 rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
268 rng.GenerateRandomBytes(uuid.data(), uuid_length); 275 rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length);
269 }
270 } 276 }
271 277
272 // Protocol and tag type may change here
273 tag_info = {
274 .uuid = uuid,
275 .uuid_length = uuid_length,
276 .protocol = protocol,
277 .tag_type = tag_type,
278 };
279
280 return ResultSuccess; 278 return ResultSuccess;
281} 279}
282 280
@@ -293,7 +291,7 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
293 Result result = ResultSuccess; 291 Result result = ResultSuccess;
294 292
295 TagInfo tag_info{}; 293 TagInfo tag_info{};
296 result = GetTagInfo(tag_info, true); 294 result = GetTagInfo(tag_info);
297 295
298 if (result.IsError()) { 296 if (result.IsError()) {
299 return result; 297 return result;
@@ -307,6 +305,8 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
307 return ResultInvalidArgument; 305 return ResultInvalidArgument;
308 } 306 }
309 307
308 Common::Input::MifareRequest request{};
309 Common::Input::MifareRequest out_data{};
310 const auto unknown = parameters[0].sector_key.unknown; 310 const auto unknown = parameters[0].sector_key.unknown;
311 for (std::size_t i = 0; i < parameters.size(); i++) { 311 for (std::size_t i = 0; i < parameters.size(); i++) {
312 if (unknown != parameters[i].sector_key.unknown) { 312 if (unknown != parameters[i].sector_key.unknown) {
@@ -315,25 +315,29 @@ Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameter
315 } 315 }
316 316
317 for (std::size_t i = 0; i < parameters.size(); i++) { 317 for (std::size_t i = 0; i < parameters.size(); i++) {
318 result = ReadMifare(parameters[i], read_block_data[i]); 318 if (parameters[i].sector_key.command == MifareCmd::None) {
319 if (result.IsError()) { 319 continue;
320 break;
321 } 320 }
321 request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
322 request.data[i].sector = parameters[i].sector_number;
323 memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
324 sizeof(KeyData));
322 } 325 }
323 326
324 return result; 327 if (!npad_device->ReadMifareData(request, out_data)) {
325}
326
327Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
328 MifareReadBlockData& read_block_data) const {
329 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
330 read_block_data.sector_number = parameter.sector_number;
331 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
332 return ResultMifareError288; 328 return ResultMifareError288;
333 } 329 }
334 330
335 // TODO: Use parameter.sector_key to read encrypted data 331 for (std::size_t i = 0; i < read_block_data.size(); i++) {
336 memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock)); 332 if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) {
333 continue;
334 }
335
336 read_block_data[i] = {
337 .data = out_data.data[i].data,
338 .sector_number = out_data.data[i].sector,
339 };
340 }
337 341
338 return ResultSuccess; 342 return ResultSuccess;
339} 343}
@@ -342,7 +346,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
342 Result result = ResultSuccess; 346 Result result = ResultSuccess;
343 347
344 TagInfo tag_info{}; 348 TagInfo tag_info{};
345 result = GetTagInfo(tag_info, true); 349 result = GetTagInfo(tag_info);
346 350
347 if (result.IsError()) { 351 if (result.IsError()) {
348 return result; 352 return result;
@@ -363,42 +367,25 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet
363 } 367 }
364 } 368 }
365 369
370 Common::Input::MifareRequest request{};
366 for (std::size_t i = 0; i < parameters.size(); i++) { 371 for (std::size_t i = 0; i < parameters.size(); i++) {
367 result = WriteMifare(parameters[i]); 372 if (parameters[i].sector_key.command == MifareCmd::None) {
368 if (result.IsError()) { 373 continue;
369 break;
370 } 374 }
375 request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
376 request.data[i].sector = parameters[i].sector_number;
377 memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
378 sizeof(KeyData));
379 memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData));
371 } 380 }
372 381
373 if (!npad_device->WriteNfc(mifare_data)) { 382 if (!npad_device->WriteMifareData(request)) {
374 LOG_ERROR(Service_NFP, "Error writing to file");
375 return ResultMifareError288; 383 return ResultMifareError288;
376 } 384 }
377 385
378 return result; 386 return result;
379} 387}
380 388
381Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
382 const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
383
384 if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
385 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
386 if (device_state == DeviceState::TagRemoved) {
387 return ResultTagRemoved;
388 }
389 return ResultWrongDeviceState;
390 }
391
392 if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
393 return ResultMifareError288;
394 }
395
396 // TODO: Use parameter.sector_key to encrypt the data
397 memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
398
399 return ResultSuccess;
400}
401
402Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, 389Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
403 std::span<const u8> command_data, 390 std::span<const u8> command_data,
404 std::span<u8> out_data) { 391 std::span<u8> out_data) {
@@ -412,6 +399,11 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
412 return ResultWrongDeviceState; 399 return ResultWrongDeviceState;
413 } 400 }
414 401
402 if (!LoadAmiiboData()) {
403 LOG_ERROR(Service_NFP, "Not an amiibo");
404 return ResultInvalidTagType;
405 }
406
415 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) { 407 if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
416 LOG_ERROR(Service_NFP, "Not an amiibo"); 408 LOG_ERROR(Service_NFP, "Not an amiibo");
417 return ResultInvalidTagType; 409 return ResultInvalidTagType;
@@ -562,7 +554,7 @@ Result NfcDevice::Restore() {
562 554
563 NFC::TagInfo tag_info{}; 555 NFC::TagInfo tag_info{};
564 std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{}; 556 std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
565 Result result = GetTagInfo(tag_info, false); 557 Result result = GetTagInfo(tag_info);
566 558
567 if (result.IsError()) { 559 if (result.IsError()) {
568 return result; 560 return result;
@@ -635,7 +627,7 @@ Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
635 // TODO: Validate this data 627 // TODO: Validate this data
636 common_info = { 628 common_info = {
637 .last_write_date = settings.write_date.GetWriteDate(), 629 .last_write_date = settings.write_date.GetWriteDate(),
638 .write_counter = tag_data.write_counter, 630 .write_counter = tag_data.application_write_counter,
639 .version = tag_data.amiibo_version, 631 .version = tag_data.amiibo_version,
640 .application_area_size = sizeof(NFP::ApplicationArea), 632 .application_area_size = sizeof(NFP::ApplicationArea),
641 }; 633 };
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index 7560210d6..0ed1ff34c 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -42,15 +42,12 @@ public:
42 Result StartDetection(NfcProtocol allowed_protocol); 42 Result StartDetection(NfcProtocol allowed_protocol);
43 Result StopDetection(); 43 Result StopDetection();
44 44
45 Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const; 45 Result GetTagInfo(TagInfo& tag_info) const;
46 46
47 Result ReadMifare(std::span<const MifareReadBlockParameter> parameters, 47 Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
48 std::span<MifareReadBlockData> read_block_data) const; 48 std::span<MifareReadBlockData> read_block_data) const;
49 Result ReadMifare(const MifareReadBlockParameter& parameter,
50 MifareReadBlockData& read_block_data) const;
51 49
52 Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); 50 Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
53 Result WriteMifare(const MifareWriteBlockParameter& parameter);
54 51
55 Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, 52 Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
56 std::span<const u8> command_data, std::span<u8> out_data); 53 std::span<const u8> command_data, std::span<u8> out_data);
@@ -105,7 +102,8 @@ public:
105 102
106private: 103private:
107 void NpadUpdate(Core::HID::ControllerTriggerType type); 104 void NpadUpdate(Core::HID::ControllerTriggerType type);
108 bool LoadNfcTag(std::span<const u8> data); 105 bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid);
106 bool LoadAmiiboData();
109 void CloseNfcTag(); 107 void CloseNfcTag();
110 108
111 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; 109 NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
@@ -140,8 +138,8 @@ private:
140 bool is_write_protected{}; 138 bool is_write_protected{};
141 NFP::MountTarget mount_target{NFP::MountTarget::None}; 139 NFP::MountTarget mount_target{NFP::MountTarget::None};
142 140
141 TagInfo real_tag_info{};
143 NFP::NTAG215File tag_data{}; 142 NFP::NTAG215File tag_data{};
144 std::vector<u8> mifare_data{};
145 NFP::EncryptedNTAG215File encrypted_tag_data{}; 143 NFP::EncryptedNTAG215File encrypted_tag_data{};
146}; 144};
147 145
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index b0456508e..562f3a28e 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -29,6 +29,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
29} 29}
30 30
31DeviceManager ::~DeviceManager() { 31DeviceManager ::~DeviceManager() {
32 if (is_initialized) {
33 Finalize();
34 }
32 service_context.CloseEvent(availability_change_event); 35 service_context.CloseEvent(availability_change_event);
33} 36}
34 37
@@ -125,14 +128,14 @@ Result DeviceManager::StopDetection(u64 device_handle) {
125 return result; 128 return result;
126} 129}
127 130
128Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const { 131Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
129 std::scoped_lock lock{mutex}; 132 std::scoped_lock lock{mutex};
130 133
131 std::shared_ptr<NfcDevice> device = nullptr; 134 std::shared_ptr<NfcDevice> device = nullptr;
132 auto result = GetDeviceHandle(device_handle, device); 135 auto result = GetDeviceHandle(device_handle, device);
133 136
134 if (result.IsSuccess()) { 137 if (result.IsSuccess()) {
135 result = device->GetTagInfo(tag_info, is_mifare); 138 result = device->GetTagInfo(tag_info);
136 result = VerifyDeviceResult(device, result); 139 result = VerifyDeviceResult(device, result);
137 } 140 }
138 141
@@ -546,7 +549,7 @@ Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) cons
546 NFC::TagInfo tag_info{}; 549 NFC::TagInfo tag_info{};
547 550
548 if (result.IsSuccess()) { 551 if (result.IsSuccess()) {
549 result = device->GetTagInfo(tag_info, false); 552 result = device->GetTagInfo(tag_info);
550 } 553 }
551 554
552 if (result.IsSuccess()) { 555 if (result.IsSuccess()) {
@@ -565,7 +568,7 @@ Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> dat
565 NFC::TagInfo tag_info{}; 568 NFC::TagInfo tag_info{};
566 569
567 if (result.IsSuccess()) { 570 if (result.IsSuccess()) {
568 result = device->GetTagInfo(tag_info, false); 571 result = device->GetTagInfo(tag_info);
569 } 572 }
570 573
571 if (result.IsSuccess()) { 574 if (result.IsSuccess()) {
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index 2971e280f..c61ba0cf3 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -33,7 +33,7 @@ public:
33 Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; 33 Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
34 Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); 34 Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
35 Result StopDetection(u64 device_handle); 35 Result StopDetection(u64 device_handle);
36 Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const; 36 Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const;
37 Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; 37 Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
38 Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; 38 Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
39 Result ReadMifare(u64 device_handle, 39 Result ReadMifare(u64 device_handle,
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h
index 75b59f021..467937399 100644
--- a/src/core/hle/service/nfc/mifare_types.h
+++ b/src/core/hle/service/nfc/mifare_types.h
@@ -11,9 +11,10 @@
11namespace Service::NFC { 11namespace Service::NFC {
12 12
13enum class MifareCmd : u8 { 13enum class MifareCmd : u8 {
14 None = 0x00,
15 Read = 0x30,
14 AuthA = 0x60, 16 AuthA = 0x60,
15 AuthB = 0x61, 17 AuthB = 0x61,
16 Read = 0x30,
17 Write = 0xA0, 18 Write = 0xA0,
18 Transfer = 0xB0, 19 Transfer = 0xB0,
19 Decrement = 0xC0, 20 Decrement = 0xC0,
@@ -35,17 +36,17 @@ static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
35 36
36// This is nn::nfc::MifareReadBlockParameter 37// This is nn::nfc::MifareReadBlockParameter
37struct MifareReadBlockParameter { 38struct MifareReadBlockParameter {
38 u8 sector_number; 39 u8 sector_number{};
39 INSERT_PADDING_BYTES(0x7); 40 INSERT_PADDING_BYTES(0x7);
40 SectorKey sector_key; 41 SectorKey sector_key{};
41}; 42};
42static_assert(sizeof(MifareReadBlockParameter) == 0x18, 43static_assert(sizeof(MifareReadBlockParameter) == 0x18,
43 "MifareReadBlockParameter is an invalid size"); 44 "MifareReadBlockParameter is an invalid size");
44 45
45// This is nn::nfc::MifareReadBlockData 46// This is nn::nfc::MifareReadBlockData
46struct MifareReadBlockData { 47struct MifareReadBlockData {
47 DataBlock data; 48 DataBlock data{};
48 u8 sector_number; 49 u8 sector_number{};
49 INSERT_PADDING_BYTES(0x7); 50 INSERT_PADDING_BYTES(0x7);
50}; 51};
51static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); 52static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 130fb7f78..e7ca7582e 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -174,8 +174,7 @@ void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
174 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); 174 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
175 175
176 TagInfo tag_info{}; 176 TagInfo tag_info{};
177 auto result = 177 auto result = GetManager()->GetTagInfo(device_handle, tag_info);
178 GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
179 result = TranslateResultToServiceError(result); 178 result = TranslateResultToServiceError(result);
180 179
181 if (result.IsSuccess()) { 180 if (result.IsSuccess()) {
@@ -216,8 +215,8 @@ void NfcInterface::ReadMifare(HLERequestContext& ctx) {
216 memcpy(read_commands.data(), buffer.data(), 215 memcpy(read_commands.data(), buffer.data(),
217 number_of_commands * sizeof(MifareReadBlockParameter)); 216 number_of_commands * sizeof(MifareReadBlockParameter));
218 217
219 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", 218 LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle,
220 device_handle, number_of_commands); 219 number_of_commands);
221 220
222 std::vector<MifareReadBlockData> out_data(number_of_commands); 221 std::vector<MifareReadBlockData> out_data(number_of_commands);
223 auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data); 222 auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);