mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 06:46:40 +08:00 
			
		
		
		
	Merge pull request #9369 from german77/mifare
service: nfc: Implement mifare service
This commit is contained in:
		
						commit
						04779b3d2a
					
				| @ -528,6 +528,8 @@ add_library(core STATIC | |||||||
|     hle/service/mnpp/mnpp_app.h |     hle/service/mnpp/mnpp_app.h | ||||||
|     hle/service/ncm/ncm.cpp |     hle/service/ncm/ncm.cpp | ||||||
|     hle/service/ncm/ncm.h |     hle/service/ncm/ncm.h | ||||||
|  |     hle/service/nfc/mifare_user.cpp | ||||||
|  |     hle/service/nfc/mifare_user.h | ||||||
|     hle/service/nfc/nfc.cpp |     hle/service/nfc/nfc.cpp | ||||||
|     hle/service/nfc/nfc.h |     hle/service/nfc/nfc.h | ||||||
|     hle/service/nfc/nfc_device.cpp |     hle/service/nfc/nfc_device.cpp | ||||||
|  | |||||||
							
								
								
									
										400
									
								
								src/core/hle/service/nfc/mifare_user.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								src/core/hle/service/nfc/mifare_user.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,400 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #include "common/logging/log.h" | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/hid/hid_types.h" | ||||||
|  | #include "core/hle/ipc_helpers.h" | ||||||
|  | #include "core/hle/kernel/k_event.h" | ||||||
|  | #include "core/hle/service/nfc/mifare_user.h" | ||||||
|  | #include "core/hle/service/nfc/nfc_device.h" | ||||||
|  | #include "core/hle/service/nfc/nfc_result.h" | ||||||
|  | 
 | ||||||
|  | namespace Service::NFC { | ||||||
|  | 
 | ||||||
|  | MFIUser::MFIUser(Core::System& system_) | ||||||
|  |     : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} { | ||||||
|  |     static const FunctionInfo functions[] = { | ||||||
|  |         {0, &MFIUser::Initialize, "Initialize"}, | ||||||
|  |         {1, &MFIUser::Finalize, "Finalize"}, | ||||||
|  |         {2, &MFIUser::ListDevices, "ListDevices"}, | ||||||
|  |         {3, &MFIUser::StartDetection, "StartDetection"}, | ||||||
|  |         {4, &MFIUser::StopDetection, "StopDetection"}, | ||||||
|  |         {5, &MFIUser::Read, "Read"}, | ||||||
|  |         {6, &MFIUser::Write, "Write"}, | ||||||
|  |         {7, &MFIUser::GetTagInfo, "GetTagInfo"}, | ||||||
|  |         {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, | ||||||
|  |         {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, | ||||||
|  |         {10, &MFIUser::GetState, "GetState"}, | ||||||
|  |         {11, &MFIUser::GetDeviceState, "GetDeviceState"}, | ||||||
|  |         {12, &MFIUser::GetNpadId, "GetNpadId"}, | ||||||
|  |         {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, | ||||||
|  |     }; | ||||||
|  |     RegisterHandlers(functions); | ||||||
|  | 
 | ||||||
|  |     availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent"); | ||||||
|  | 
 | ||||||
|  |     for (u32 device_index = 0; device_index < 10; device_index++) { | ||||||
|  |         devices[device_index] = | ||||||
|  |             std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, | ||||||
|  |                                         service_context, availability_change_event); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | MFIUser ::~MFIUser() { | ||||||
|  |     availability_change_event->Close(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::Initialize(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_NFC, "called"); | ||||||
|  | 
 | ||||||
|  |     state = State::Initialized; | ||||||
|  | 
 | ||||||
|  |     for (auto& device : devices) { | ||||||
|  |         device->Initialize(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 0}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::Finalize(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_NFC, "called"); | ||||||
|  | 
 | ||||||
|  |     state = State::NonInitialized; | ||||||
|  | 
 | ||||||
|  |     for (auto& device : devices) { | ||||||
|  |         device->Finalize(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::ListDevices(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_DEBUG(Service_NFC, "called"); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!ctx.CanWriteBuffer()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareInvalidArgument); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (ctx.GetWriteBufferSize() == 0) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareInvalidArgument); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::vector<u64> nfp_devices; | ||||||
|  |     const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); | ||||||
|  | 
 | ||||||
|  |     for (const auto& device : devices) { | ||||||
|  |         if (nfp_devices.size() >= max_allowed_devices) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { | ||||||
|  |             nfp_devices.push_back(device->GetHandle()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (nfp_devices.empty()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ctx.WriteBuffer(nfp_devices); | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.Push(static_cast<s32>(nfp_devices.size())); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::StartDetection(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto result = device.value()->StartDetection(NFP::TagProtocol::All); | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::StopDetection(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     const auto result = device.value()->StopDetection(); | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::Read(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     const auto buffer{ctx.ReadBuffer()}; | ||||||
|  |     const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()}; | ||||||
|  |     std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands); | ||||||
|  | 
 | ||||||
|  |     memcpy(read_commands.data(), buffer.data(), | ||||||
|  |            number_of_commands * sizeof(NFP::MifareReadBlockParameter)); | ||||||
|  | 
 | ||||||
|  |     LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", | ||||||
|  |              device_handle, number_of_commands); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Result result = ResultSuccess; | ||||||
|  |     std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); | ||||||
|  |     for (std::size_t i = 0; i < number_of_commands; i++) { | ||||||
|  |         result = device.value()->MifareRead(read_commands[i], out_data[i]); | ||||||
|  |         if (result.IsError()) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ctx.WriteBuffer(out_data); | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::Write(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     const auto buffer{ctx.ReadBuffer()}; | ||||||
|  |     const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()}; | ||||||
|  |     std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands); | ||||||
|  | 
 | ||||||
|  |     memcpy(write_commands.data(), buffer.data(), | ||||||
|  |            number_of_commands * sizeof(NFP::MifareWriteBlockParameter)); | ||||||
|  | 
 | ||||||
|  |     LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", | ||||||
|  |              device_handle, number_of_commands); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Result result = ResultSuccess; | ||||||
|  |     std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); | ||||||
|  |     for (std::size_t i = 0; i < number_of_commands; i++) { | ||||||
|  |         result = device.value()->MifareWrite(write_commands[i]); | ||||||
|  |         if (result.IsError()) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (result.IsSuccess()) { | ||||||
|  |         result = device.value()->Flush(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetTagInfo(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     NFP::TagInfo tag_info{}; | ||||||
|  |     const auto result = device.value()->GetTagInfo(tag_info, true); | ||||||
|  |     ctx.WriteBuffer(tag_info); | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |     rb.Push(result); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetActivateEventHandle(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushCopyObjects(device.value()->GetActivateEvent()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetDeactivateEventHandle(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushCopyObjects(device.value()->GetDeactivateEvent()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetState(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_DEBUG(Service_NFC, "called"); | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushEnum(state); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetDeviceState(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushEnum(device.value()->GetCurrentState()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetNpadId(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp{ctx}; | ||||||
|  |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|  |     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto device = GetNfcDevice(device_handle); | ||||||
|  | 
 | ||||||
|  |     if (!device.has_value()) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareDeviceNotFound); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushEnum(device.value()->GetNpadId()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) { | ||||||
|  |     LOG_INFO(Service_NFC, "called"); | ||||||
|  | 
 | ||||||
|  |     if (state == State::NonInitialized) { | ||||||
|  |         IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|  |         rb.Push(MifareNfcDisabled); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||||
|  |     rb.Push(ResultSuccess); | ||||||
|  |     rb.PushCopyObjects(availability_change_event->GetReadableEvent()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) { | ||||||
|  |     for (auto& device : devices) { | ||||||
|  |         if (device->GetHandle() == handle) { | ||||||
|  |             return device; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return std::nullopt; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Service::NFC
 | ||||||
							
								
								
									
										52
									
								
								src/core/hle/service/nfc/mifare_user.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/core/hle/service/nfc/mifare_user.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <array> | ||||||
|  | #include <memory> | ||||||
|  | #include <optional> | ||||||
|  | 
 | ||||||
|  | #include "core/hle/service/kernel_helpers.h" | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  | 
 | ||||||
|  | namespace Service::NFC { | ||||||
|  | class NfcDevice; | ||||||
|  | 
 | ||||||
|  | class MFIUser final : public ServiceFramework<MFIUser> { | ||||||
|  | public: | ||||||
|  |     explicit MFIUser(Core::System& system_); | ||||||
|  |     ~MFIUser(); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     enum class State : u32 { | ||||||
|  |         NonInitialized, | ||||||
|  |         Initialized, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     void Initialize(Kernel::HLERequestContext& ctx); | ||||||
|  |     void Finalize(Kernel::HLERequestContext& ctx); | ||||||
|  |     void ListDevices(Kernel::HLERequestContext& ctx); | ||||||
|  |     void StartDetection(Kernel::HLERequestContext& ctx); | ||||||
|  |     void StopDetection(Kernel::HLERequestContext& ctx); | ||||||
|  |     void Read(Kernel::HLERequestContext& ctx); | ||||||
|  |     void Write(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetTagInfo(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetActivateEventHandle(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetState(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetDeviceState(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetNpadId(Kernel::HLERequestContext& ctx); | ||||||
|  |     void GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); | ||||||
|  | 
 | ||||||
|  |     KernelHelpers::ServiceContext service_context; | ||||||
|  | 
 | ||||||
|  |     std::array<std::shared_ptr<NfcDevice>, 10> devices{}; | ||||||
|  | 
 | ||||||
|  |     State state{State::NonInitialized}; | ||||||
|  |     Kernel::KEvent* availability_change_event; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Service::NFC
 | ||||||
| @ -6,6 +6,7 @@ | |||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
| #include "common/settings.h" | #include "common/settings.h" | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
|  | #include "core/hle/service/nfc/mifare_user.h" | ||||||
| #include "core/hle/service/nfc/nfc.h" | #include "core/hle/service/nfc/nfc.h" | ||||||
| #include "core/hle/service/nfc/nfc_user.h" | #include "core/hle/service/nfc/nfc_user.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| @ -50,32 +51,6 @@ private: | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class MFIUser final : public ServiceFramework<MFIUser> { |  | ||||||
| public: |  | ||||||
|     explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} { |  | ||||||
|         // clang-format off
 |  | ||||||
|         static const FunctionInfo functions[] = { |  | ||||||
|             {0, nullptr, "Initialize"}, |  | ||||||
|             {1, nullptr, "Finalize"}, |  | ||||||
|             {2, nullptr, "ListDevices"}, |  | ||||||
|             {3, nullptr, "StartDetection"}, |  | ||||||
|             {4, nullptr, "StopDetection"}, |  | ||||||
|             {5, nullptr, "Read"}, |  | ||||||
|             {6, nullptr, "Write"}, |  | ||||||
|             {7, nullptr, "GetTagInfo"}, |  | ||||||
|             {8, nullptr, "GetActivateEventHandle"}, |  | ||||||
|             {9, nullptr, "GetDeactivateEventHandle"}, |  | ||||||
|             {10, nullptr, "GetState"}, |  | ||||||
|             {11, nullptr, "GetDeviceState"}, |  | ||||||
|             {12, nullptr, "GetNpadId"}, |  | ||||||
|             {13, nullptr, "GetAvailabilityChangeEventHandle"}, |  | ||||||
|         }; |  | ||||||
|         // clang-format on
 |  | ||||||
| 
 |  | ||||||
|         RegisterHandlers(functions); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { | class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { | ||||||
| public: | public: | ||||||
|     explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { |     explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { | ||||||
|  | |||||||
| @ -77,11 +77,13 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) { | |||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (data.size() != sizeof(NFP::EncryptedNTAG215File)) { |     if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { | ||||||
|         LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); |         LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     tag_data.resize(data.size()); | ||||||
|  |     memcpy(tag_data.data(), data.data(), data.size()); | ||||||
|     memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |     memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); | ||||||
| 
 | 
 | ||||||
|     device_state = NFP::DeviceState::TagFound; |     device_state = NFP::DeviceState::TagFound; | ||||||
| @ -121,7 +123,7 @@ void NfcDevice::Finalize() { | |||||||
|     device_state = NFP::DeviceState::Unavailable; |     device_state = NFP::DeviceState::Unavailable; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result NfcDevice::StartDetection(s32 protocol_) { | Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { | ||||||
|     if (device_state != NFP::DeviceState::Initialized && |     if (device_state != NFP::DeviceState::Initialized && | ||||||
|         device_state != NFP::DeviceState::TagRemoved) { |         device_state != NFP::DeviceState::TagRemoved) { | ||||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||||
| @ -134,7 +136,7 @@ Result NfcDevice::StartDetection(s32 protocol_) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     device_state = NFP::DeviceState::SearchingForTag; |     device_state = NFP::DeviceState::SearchingForTag; | ||||||
|     protocol = protocol_; |     allowed_protocols = allowed_protocol; | ||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -160,7 +162,7 @@ Result NfcDevice::StopDetection() { | |||||||
|     return WrongDeviceState; |     return WrongDeviceState; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | Result NfcDevice::Flush() { | ||||||
|     if (device_state != NFP::DeviceState::TagFound && |     if (device_state != NFP::DeviceState::TagFound && | ||||||
|         device_state != NFP::DeviceState::TagMounted) { |         device_state != NFP::DeviceState::TagMounted) { | ||||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||||
| @ -170,6 +172,34 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | |||||||
|         return WrongDeviceState; |         return WrongDeviceState; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (!npad_device->WriteNfc(tag_data)) { | ||||||
|  |         LOG_ERROR(Service_NFP, "Error writing to file"); | ||||||
|  |         return MifareReadError; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { | ||||||
|  |     if (device_state != NFP::DeviceState::TagFound && | ||||||
|  |         device_state != NFP::DeviceState::TagMounted) { | ||||||
|  |         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||||
|  |         if (device_state == NFP::DeviceState::TagRemoved) { | ||||||
|  |             return TagRemoved; | ||||||
|  |         } | ||||||
|  |         return WrongDeviceState; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (is_mifare) { | ||||||
|  |         tag_info = { | ||||||
|  |             .uuid = encrypted_tag_data.uuid.uid, | ||||||
|  |             .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), | ||||||
|  |             .protocol = NFP::TagProtocol::TypeA, | ||||||
|  |             .tag_type = NFP::TagType::Type4, | ||||||
|  |         }; | ||||||
|  |         return ResultSuccess; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Protocol and tag type may change here
 |     // Protocol and tag type may change here
 | ||||||
|     tag_info = { |     tag_info = { | ||||||
|         .uuid = encrypted_tag_data.uuid.uid, |         .uuid = encrypted_tag_data.uuid.uid, | ||||||
| @ -181,6 +211,52 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { | |||||||
|     return ResultSuccess; |     return ResultSuccess; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter, | ||||||
|  |                              NFP::MifareReadBlockData& read_block_data) { | ||||||
|  |     const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); | ||||||
|  |     read_block_data.sector_number = parameter.sector_number; | ||||||
|  | 
 | ||||||
|  |     if (device_state != NFP::DeviceState::TagFound && | ||||||
|  |         device_state != NFP::DeviceState::TagMounted) { | ||||||
|  |         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||||
|  |         if (device_state == NFP::DeviceState::TagRemoved) { | ||||||
|  |             return TagRemoved; | ||||||
|  |         } | ||||||
|  |         return WrongDeviceState; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { | ||||||
|  |         return MifareReadError; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO: Use parameter.sector_key to read encrypted data
 | ||||||
|  |     memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock)); | ||||||
|  | 
 | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) { | ||||||
|  |     const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); | ||||||
|  | 
 | ||||||
|  |     if (device_state != NFP::DeviceState::TagFound && | ||||||
|  |         device_state != NFP::DeviceState::TagMounted) { | ||||||
|  |         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||||
|  |         if (device_state == NFP::DeviceState::TagRemoved) { | ||||||
|  |             return TagRemoved; | ||||||
|  |         } | ||||||
|  |         return WrongDeviceState; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { | ||||||
|  |         return MifareReadError; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // TODO: Use parameter.sector_key to encrypt the data
 | ||||||
|  |     memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock)); | ||||||
|  | 
 | ||||||
|  |     return ResultSuccess; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| u64 NfcDevice::GetHandle() const { | u64 NfcDevice::GetHandle() const { | ||||||
|     // Generate a handle based of the npad id
 |     // Generate a handle based of the npad id
 | ||||||
|     return static_cast<u64>(npad_id); |     return static_cast<u64>(npad_id); | ||||||
|  | |||||||
| @ -34,10 +34,16 @@ public: | |||||||
|     void Initialize(); |     void Initialize(); | ||||||
|     void Finalize(); |     void Finalize(); | ||||||
| 
 | 
 | ||||||
|     Result StartDetection(s32 protocol_); |     Result StartDetection(NFP::TagProtocol allowed_protocol); | ||||||
|     Result StopDetection(); |     Result StopDetection(); | ||||||
|  |     Result Flush(); | ||||||
| 
 | 
 | ||||||
|     Result GetTagInfo(NFP::TagInfo& tag_info) const; |     Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const; | ||||||
|  | 
 | ||||||
|  |     Result MifareRead(const NFP::MifareReadBlockParameter& parameter, | ||||||
|  |                       NFP::MifareReadBlockData& read_block_data); | ||||||
|  | 
 | ||||||
|  |     Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter); | ||||||
| 
 | 
 | ||||||
|     u64 GetHandle() const; |     u64 GetHandle() const; | ||||||
|     NFP::DeviceState GetCurrentState() const; |     NFP::DeviceState GetCurrentState() const; | ||||||
| @ -61,10 +67,11 @@ private: | |||||||
|     Kernel::KEvent* deactivate_event = nullptr; |     Kernel::KEvent* deactivate_event = nullptr; | ||||||
|     Kernel::KEvent* availability_change_event = nullptr; |     Kernel::KEvent* availability_change_event = nullptr; | ||||||
| 
 | 
 | ||||||
|     s32 protocol{}; |     NFP::TagProtocol allowed_protocols{}; | ||||||
|     NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; |     NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; | ||||||
| 
 | 
 | ||||||
|     NFP::EncryptedNTAG215File encrypted_tag_data{}; |     NFP::EncryptedNTAG215File encrypted_tag_data{}; | ||||||
|  |     std::vector<u8> tag_data{}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Service::NFC
 | } // namespace Service::NFC
 | ||||||
|  | |||||||
| @ -12,6 +12,12 @@ constexpr Result InvalidArgument(ErrorModule::NFC, 65); | |||||||
| constexpr Result WrongDeviceState(ErrorModule::NFC, 73); | constexpr Result WrongDeviceState(ErrorModule::NFC, 73); | ||||||
| constexpr Result NfcDisabled(ErrorModule::NFC, 80); | constexpr Result NfcDisabled(ErrorModule::NFC, 80); | ||||||
| constexpr Result TagRemoved(ErrorModule::NFC, 97); | constexpr Result TagRemoved(ErrorModule::NFC, 97); | ||||||
| constexpr Result CorruptedData(ErrorModule::NFC, 144); | 
 | ||||||
|  | constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); | ||||||
|  | constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); | ||||||
|  | constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); | ||||||
|  | constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); | ||||||
|  | constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); | ||||||
|  | constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); | ||||||
| 
 | 
 | ||||||
| } // namespace Service::NFC
 | } // namespace Service::NFC
 | ||||||
|  | |||||||
| @ -201,7 +201,7 @@ void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { | |||||||
| void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | void IUser::StartDetection(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp{ctx}; |     IPC::RequestParser rp{ctx}; | ||||||
|     const auto device_handle{rp.Pop<u64>()}; |     const auto device_handle{rp.Pop<u64>()}; | ||||||
|     const auto nfp_protocol{rp.Pop<s32>()}; |     const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()}; | ||||||
|     LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); |     LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); | ||||||
| 
 | 
 | ||||||
|     if (state == State::NonInitialized) { |     if (state == State::NonInitialized) { | ||||||
| @ -267,7 +267,7 @@ void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     NFP::TagInfo tag_info{}; |     NFP::TagInfo tag_info{}; | ||||||
|     const auto result = device.value()->GetTagInfo(tag_info); |     const auto result = device.value()->GetTagInfo(tag_info, false); | ||||||
|     ctx.WriteBuffer(tag_info); |     ctx.WriteBuffer(tag_info); | ||||||
|     IPC::ResponseBuilder rb{ctx, 2}; |     IPC::ResponseBuilder rb{ctx, 2}; | ||||||
|     rb.Push(result); |     rb.Push(result); | ||||||
|  | |||||||
| @ -106,11 +106,24 @@ enum class CabinetMode : u8 { | |||||||
|     StartFormatter, |     StartFormatter, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum class MifareCmd : u8 { | ||||||
|  |     AuthA = 0x60, | ||||||
|  |     AuthB = 0x61, | ||||||
|  |     Read = 0x30, | ||||||
|  |     Write = 0xA0, | ||||||
|  |     Transfer = 0xB0, | ||||||
|  |     Decrement = 0xC0, | ||||||
|  |     Increment = 0xC1, | ||||||
|  |     Store = 0xC2 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| using UniqueSerialNumber = std::array<u8, 7>; | using UniqueSerialNumber = std::array<u8, 7>; | ||||||
| using LockBytes = std::array<u8, 2>; | using LockBytes = std::array<u8, 2>; | ||||||
| using HashData = std::array<u8, 0x20>; | using HashData = std::array<u8, 0x20>; | ||||||
| using ApplicationArea = std::array<u8, 0xD8>; | using ApplicationArea = std::array<u8, 0xD8>; | ||||||
| using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; | using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; | ||||||
|  | using DataBlock = std::array<u8, 0x10>; | ||||||
|  | using KeyData = std::array<u8, 0x6>; | ||||||
| 
 | 
 | ||||||
| struct TagUuid { | struct TagUuid { | ||||||
|     UniqueSerialNumber uid; |     UniqueSerialNumber uid; | ||||||
| @ -323,4 +336,37 @@ struct RegisterInfo { | |||||||
| }; | }; | ||||||
| static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | ||||||
| 
 | 
 | ||||||
|  | struct SectorKey { | ||||||
|  |     MifareCmd command; | ||||||
|  |     u8 unknown; // Usually 1
 | ||||||
|  |     INSERT_PADDING_BYTES(0x6); | ||||||
|  |     KeyData sector_key; | ||||||
|  |     INSERT_PADDING_BYTES(0x2); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); | ||||||
|  | 
 | ||||||
|  | struct MifareReadBlockParameter { | ||||||
|  |     u8 sector_number; | ||||||
|  |     INSERT_PADDING_BYTES(0x7); | ||||||
|  |     SectorKey sector_key; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(MifareReadBlockParameter) == 0x18, | ||||||
|  |               "MifareReadBlockParameter is an invalid size"); | ||||||
|  | 
 | ||||||
|  | struct MifareReadBlockData { | ||||||
|  |     DataBlock data; | ||||||
|  |     u8 sector_number; | ||||||
|  |     INSERT_PADDING_BYTES(0x7); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); | ||||||
|  | 
 | ||||||
|  | struct MifareWriteBlockParameter { | ||||||
|  |     DataBlock data; | ||||||
|  |     u8 sector_number; | ||||||
|  |     INSERT_PADDING_BYTES(0x7); | ||||||
|  |     SectorKey sector_key; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(MifareWriteBlockParameter) == 0x28, | ||||||
|  |               "MifareWriteBlockParameter is an invalid size"); | ||||||
|  | 
 | ||||||
| } // namespace Service::NFP
 | } // namespace Service::NFP
 | ||||||
|  | |||||||
| @ -47,20 +47,20 @@ Common::Input::NfcState VirtualAmiibo::SupportsNfc( | |||||||
| 
 | 
 | ||||||
| Common::Input::NfcState VirtualAmiibo::WriteNfcData( | Common::Input::NfcState VirtualAmiibo::WriteNfcData( | ||||||
|     [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { |     [[maybe_unused]] const PadIdentifier& identifier_, const std::vector<u8>& data) { | ||||||
|     const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite, |     const Common::FS::IOFile nfc_file{file_path, Common::FS::FileAccessMode::ReadWrite, | ||||||
|                                       Common::FS::FileType::BinaryFile}; |                                       Common::FS::FileType::BinaryFile}; | ||||||
| 
 | 
 | ||||||
|     if (!amiibo_file.IsOpen()) { |     if (!nfc_file.IsOpen()) { | ||||||
|         LOG_ERROR(Core, "Amiibo is already on use"); |         LOG_ERROR(Core, "Amiibo is already on use"); | ||||||
|         return Common::Input::NfcState::WriteFailed; |         return Common::Input::NfcState::WriteFailed; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!amiibo_file.Write(data)) { |     if (!nfc_file.Write(data)) { | ||||||
|         LOG_ERROR(Service_NFP, "Error writting to file"); |         LOG_ERROR(Service_NFP, "Error writting to file"); | ||||||
|         return Common::Input::NfcState::WriteFailed; |         return Common::Input::NfcState::WriteFailed; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     amiibo_data = data; |     nfc_data = data; | ||||||
| 
 | 
 | ||||||
|     return Common::Input::NfcState::Success; |     return Common::Input::NfcState::Success; | ||||||
| } | } | ||||||
| @ -70,32 +70,44 @@ VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | ||||||
|     const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read, |     const Common::FS::IOFile nfc_file{filename, Common::FS::FileAccessMode::Read, | ||||||
|                                       Common::FS::FileType::BinaryFile}; |                                       Common::FS::FileType::BinaryFile}; | ||||||
| 
 | 
 | ||||||
|     if (state != State::WaitingForAmiibo) { |     if (state != State::WaitingForAmiibo) { | ||||||
|         return Info::WrongDeviceState; |         return Info::WrongDeviceState; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!amiibo_file.IsOpen()) { |     if (!nfc_file.IsOpen()) { | ||||||
|         return Info::UnableToLoad; |         return Info::UnableToLoad; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     amiibo_data.resize(amiibo_size); |     switch (nfc_file.GetSize()) { | ||||||
| 
 |     case AmiiboSize: | ||||||
|     if (amiibo_file.Read(amiibo_data) < amiibo_size_without_password) { |     case AmiiboSizeWithoutPassword: | ||||||
|  |         nfc_data.resize(AmiiboSize); | ||||||
|  |         if (nfc_file.Read(nfc_data) < AmiiboSizeWithoutPassword) { | ||||||
|  |             return Info::NotAnAmiibo; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     case MifareSize: | ||||||
|  |         nfc_data.resize(MifareSize); | ||||||
|  |         if (nfc_file.Read(nfc_data) < MifareSize) { | ||||||
|  |             return Info::NotAnAmiibo; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|         return Info::NotAnAmiibo; |         return Info::NotAnAmiibo; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     file_path = filename; |     file_path = filename; | ||||||
|     state = State::AmiiboIsOpen; |     state = State::AmiiboIsOpen; | ||||||
|     SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); |     SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | ||||||
|     return Info::Success; |     return Info::Success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { | ||||||
|     if (state == State::AmiiboIsOpen) { |     if (state == State::AmiiboIsOpen) { | ||||||
|         SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); |         SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | ||||||
|         return Info::Success; |         return Info::Success; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -53,12 +53,13 @@ public: | |||||||
|     std::string GetLastFilePath() const; |     std::string GetLastFilePath() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     static constexpr std::size_t amiibo_size = 0x21C; |     static constexpr std::size_t AmiiboSize = 0x21C; | ||||||
|     static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; |     static constexpr std::size_t AmiiboSizeWithoutPassword = AmiiboSize - 0x8; | ||||||
|  |     static constexpr std::size_t MifareSize = 0x400; | ||||||
| 
 | 
 | ||||||
|     std::string file_path{}; |     std::string file_path{}; | ||||||
|     State state{State::Initialized}; |     State state{State::Initialized}; | ||||||
|     std::vector<u8> amiibo_data; |     std::vector<u8> nfc_data; | ||||||
|     Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive}; |     Common::Input::PollingMode polling_mode{Common::Input::PollingMode::Pasive}; | ||||||
| }; | }; | ||||||
| } // namespace InputCommon
 | } // namespace InputCommon
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user