mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 15:39:02 -05:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -10,12 +10,13 @@ | ||||
| #include "core/hle/service/nfc/nfc.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "core/hle/service/sm/sm.h" | ||||
| #include "core/settings.h" | ||||
|  | ||||
| namespace Service::NFC { | ||||
|  | ||||
| class IAm final : public ServiceFramework<IAm> { | ||||
| public: | ||||
|     explicit IAm() : ServiceFramework{"IAm"} { | ||||
|     explicit IAm() : ServiceFramework{"NFC::IAm"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, nullptr, "Initialize"}, | ||||
| @@ -52,7 +53,7 @@ private: | ||||
|  | ||||
| class MFIUser final : public ServiceFramework<MFIUser> { | ||||
| public: | ||||
|     explicit MFIUser() : ServiceFramework{"IUser"} { | ||||
|     explicit MFIUser() : ServiceFramework{"NFC::MFIUser"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, nullptr, "Initialize"}, | ||||
| @@ -100,13 +101,13 @@ private: | ||||
|  | ||||
| class IUser final : public ServiceFramework<IUser> { | ||||
| public: | ||||
|     explicit IUser() : ServiceFramework{"IUser"} { | ||||
|     explicit IUser() : ServiceFramework{"NFC::IUser"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, nullptr, "Initialize"}, | ||||
|             {1, nullptr, "Finalize"}, | ||||
|             {2, nullptr, "GetState"}, | ||||
|             {3, nullptr, "IsNfcEnabled"}, | ||||
|             {0, &IUser::InitializeOld, "InitializeOld"}, | ||||
|             {1, &IUser::FinalizeOld, "FinalizeOld"}, | ||||
|             {2, &IUser::GetStateOld, "GetStateOld"}, | ||||
|             {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"}, | ||||
|             {400, nullptr, "Initialize"}, | ||||
|             {401, nullptr, "Finalize"}, | ||||
|             {402, nullptr, "GetState"}, | ||||
| @@ -130,11 +131,47 @@ public: | ||||
|  | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     enum class NfcStates : u32 { | ||||
|         Finalized = 6, | ||||
|     }; | ||||
|  | ||||
|     void InitializeOld(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 0}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | ||||
|         // We don't deal with hardware initialization so we can just stub this. | ||||
|         LOG_DEBUG(Service_NFC, "called"); | ||||
|     } | ||||
|  | ||||
|     void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushRaw<u8>(Settings::values.enable_nfc); | ||||
|  | ||||
|         LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); | ||||
|     } | ||||
|  | ||||
|     void GetStateOld(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushEnum(NfcStates::Finalized); // TODO(ogniK): Figure out if this matches nfp | ||||
|     } | ||||
|  | ||||
|     void FinalizeOld(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFC, "(STUBBED) called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class NFC_U final : public ServiceFramework<NFC_U> { | ||||
| public: | ||||
|     explicit NFC_U() : ServiceFramework{"nfc:u"} { | ||||
|     explicit NFC_U() : ServiceFramework{"nfc:user"} { | ||||
|         // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, | ||||
|   | ||||
| @@ -2,56 +2,67 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <atomic> | ||||
|  | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/lock.h" | ||||
| #include "core/hle/service/hid/hid.h" | ||||
| #include "core/hle/service/nfp/nfp.h" | ||||
| #include "core/hle/service/nfp/nfp_user.h" | ||||
|  | ||||
| namespace Service::NFP { | ||||
|  | ||||
| namespace ErrCodes { | ||||
| constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, | ||||
|                                     -1); // TODO(ogniK): Find the actual error code | ||||
| } | ||||
|  | ||||
| Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | ||||
|     : ServiceFramework(name), module(std::move(module)) {} | ||||
|     : ServiceFramework(name), module(std::move(module)) { | ||||
|     auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|     nfc_tag_load = | ||||
|         Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); | ||||
| } | ||||
|  | ||||
| Module::Interface::~Interface() = default; | ||||
|  | ||||
| class IUser final : public ServiceFramework<IUser> { | ||||
| public: | ||||
|     IUser() : ServiceFramework("IUser") { | ||||
|     IUser(Module::Interface& nfp_interface) | ||||
|         : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IUser::Initialize, "Initialize"}, | ||||
|             {1, nullptr, "Finalize"}, | ||||
|             {1, &IUser::Finalize, "Finalize"}, | ||||
|             {2, &IUser::ListDevices, "ListDevices"}, | ||||
|             {3, nullptr, "StartDetection"}, | ||||
|             {4, nullptr, "StopDetection"}, | ||||
|             {5, nullptr, "Mount"}, | ||||
|             {6, nullptr, "Unmount"}, | ||||
|             {7, nullptr, "OpenApplicationArea"}, | ||||
|             {8, nullptr, "GetApplicationArea"}, | ||||
|             {3, &IUser::StartDetection, "StartDetection"}, | ||||
|             {4, &IUser::StopDetection, "StopDetection"}, | ||||
|             {5, &IUser::Mount, "Mount"}, | ||||
|             {6, &IUser::Unmount, "Unmount"}, | ||||
|             {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, | ||||
|             {8, &IUser::GetApplicationArea, "GetApplicationArea"}, | ||||
|             {9, nullptr, "SetApplicationArea"}, | ||||
|             {10, nullptr, "Flush"}, | ||||
|             {11, nullptr, "Restore"}, | ||||
|             {12, nullptr, "CreateApplicationArea"}, | ||||
|             {13, nullptr, "GetTagInfo"}, | ||||
|             {14, nullptr, "GetRegisterInfo"}, | ||||
|             {15, nullptr, "GetCommonInfo"}, | ||||
|             {16, nullptr, "GetModelInfo"}, | ||||
|             {13, &IUser::GetTagInfo, "GetTagInfo"}, | ||||
|             {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, | ||||
|             {15, &IUser::GetCommonInfo, "GetCommonInfo"}, | ||||
|             {16, &IUser::GetModelInfo, "GetModelInfo"}, | ||||
|             {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, | ||||
|             {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||||
|             {19, &IUser::GetState, "GetState"}, | ||||
|             {20, &IUser::GetDeviceState, "GetDeviceState"}, | ||||
|             {21, &IUser::GetNpadId, "GetNpadId"}, | ||||
|             {22, nullptr, "GetApplicationArea2"}, | ||||
|             {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||||
|             {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||||
|             {24, nullptr, "RecreateApplicationArea"}, | ||||
|         }; | ||||
|         RegisterHandlers(functions); | ||||
|  | ||||
|         auto& kernel = Core::System::GetInstance().Kernel(); | ||||
|         activate_event = | ||||
|             Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:ActivateEvent"); | ||||
|         deactivate_event = | ||||
|             Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); | ||||
|         availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | ||||
| @@ -59,6 +70,17 @@ public: | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     struct TagInfo { | ||||
|         std::array<u8, 10> uuid; | ||||
|         u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it | ||||
|                         // mean something else | ||||
|         INSERT_PADDING_BYTES(0x15); | ||||
|         u32_le protocol; | ||||
|         u32_le tag_type; | ||||
|         INSERT_PADDING_BYTES(0x2c); | ||||
|     }; | ||||
|     static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size"); | ||||
|  | ||||
|     enum class State : u32 { | ||||
|         NonInitialized = 0, | ||||
|         Initialized = 1, | ||||
| @@ -66,15 +88,40 @@ private: | ||||
|  | ||||
|     enum class DeviceState : u32 { | ||||
|         Initialized = 0, | ||||
|         SearchingForTag = 1, | ||||
|         TagFound = 2, | ||||
|         TagRemoved = 3, | ||||
|         TagNearby = 4, | ||||
|         Unknown5 = 5, | ||||
|         Finalized = 6 | ||||
|     }; | ||||
|  | ||||
|     struct CommonInfo { | ||||
|         u16_be last_write_year; | ||||
|         u8 last_write_month; | ||||
|         u8 last_write_day; | ||||
|         u16_be write_counter; | ||||
|         u16_be version; | ||||
|         u32_be application_area_size; | ||||
|         INSERT_PADDING_BYTES(0x34); | ||||
|     }; | ||||
|     static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | ||||
|  | ||||
|     void Initialize(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 0}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|  | ||||
|         state = State::Initialized; | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         LOG_DEBUG(Service_NFC, "called"); | ||||
|     } | ||||
|  | ||||
|     void GetState(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::ResponseBuilder rb{ctx, 3, 0}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushRaw<u32>(static_cast<u32>(state)); | ||||
|  | ||||
|         LOG_DEBUG(Service_NFC, "called"); | ||||
|     } | ||||
|  | ||||
|     void ListDevices(Kernel::HLERequestContext& ctx) { | ||||
| @@ -83,80 +130,217 @@ private: | ||||
|  | ||||
|         ctx.WriteBuffer(&device_handle, sizeof(device_handle)); | ||||
|  | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size); | ||||
|         LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(0); | ||||
|         rb.Push<u32>(1); | ||||
|     } | ||||
|  | ||||
|     void GetNpadId(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const u64 dev_handle = rp.Pop<u64>(); | ||||
|         LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(npad_id); | ||||
|     } | ||||
|  | ||||
|     void AttachActivateEvent(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const u64 dev_handle = rp.Pop<u64>(); | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | ||||
|  | ||||
|         LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushCopyObjects(activate_event); | ||||
|         rb.PushCopyObjects(nfp_interface.GetNFCEvent()); | ||||
|         has_attached_handle = true; | ||||
|     } | ||||
|  | ||||
|     void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const u64 dev_handle = rp.Pop<u64>(); | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | ||||
|         LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushCopyObjects(deactivate_event); | ||||
|     } | ||||
|  | ||||
|     void GetState(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     void StopDetection(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|         switch (device_state) { | ||||
|         case DeviceState::TagFound: | ||||
|         case DeviceState::TagNearby: | ||||
|             deactivate_event->Signal(); | ||||
|             device_state = DeviceState::Initialized; | ||||
|             break; | ||||
|         case DeviceState::SearchingForTag: | ||||
|         case DeviceState::TagRemoved: | ||||
|             device_state = DeviceState::Initialized; | ||||
|             break; | ||||
|         } | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(static_cast<u32>(state)); | ||||
|     } | ||||
|  | ||||
|     void GetDeviceState(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|         auto nfc_event = nfp_interface.GetNFCEvent(); | ||||
|         if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { | ||||
|             device_state = DeviceState::TagFound; | ||||
|             nfc_event->Clear(); | ||||
|         } | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(static_cast<u32>(device_state)); | ||||
|     } | ||||
|  | ||||
|     void GetNpadId(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const u64 dev_handle = rp.Pop<u64>(); | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     void StartDetection(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { | ||||
|             device_state = DeviceState::SearchingForTag; | ||||
|         } | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void GetTagInfo(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         auto amiibo = nfp_interface.GetAmiiboBuffer(); | ||||
|         TagInfo tag_info{}; | ||||
|         std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size())); | ||||
|         tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); | ||||
|  | ||||
|         tag_info.protocol = 1; // TODO(ogniK): Figure out actual values | ||||
|         tag_info.tag_type = 2; | ||||
|         ctx.WriteBuffer(&tag_info, sizeof(TagInfo)); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void Mount(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         device_state = DeviceState::TagNearby; | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void GetModelInfo(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         auto amiibo = nfp_interface.GetAmiiboBuffer(); | ||||
|         ctx.WriteBuffer(&amiibo.model_info, sizeof(amiibo.model_info)); | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void Unmount(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         device_state = DeviceState::TagFound; | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void Finalize(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|  | ||||
|         device_state = DeviceState::Finalized; | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.Push<u32>(npad_id); | ||||
|     } | ||||
|  | ||||
|     void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { | ||||
|         IPC::RequestParser rp{ctx}; | ||||
|         const u64 dev_handle = rp.Pop<u64>(); | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle); | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushCopyObjects(availability_change_event); | ||||
|     } | ||||
|  | ||||
|     const u64 device_handle{0xDEAD}; | ||||
|     const u32 npad_id{0}; // This is the first player controller id | ||||
|     void GetRegisterInfo(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|  | ||||
|         // TODO(ogniK): Pull Mii and owner data from amiibo | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void GetCommonInfo(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|  | ||||
|         // TODO(ogniK): Pull common information from amiibo | ||||
|  | ||||
|         CommonInfo common_info{}; | ||||
|         common_info.application_area_size = 0; | ||||
|         ctx.WriteBuffer(&common_info, sizeof(CommonInfo)); | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void OpenApplicationArea(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
|         // We don't need to worry about this since we can just open the file | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|     } | ||||
|  | ||||
|     void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|         // We don't need to worry about this since we can just open the file | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub | ||||
|     } | ||||
|  | ||||
|     void GetApplicationArea(Kernel::HLERequestContext& ctx) { | ||||
|         LOG_WARNING(Service_NFP, "(STUBBED) called"); | ||||
|  | ||||
|         // TODO(ogniK): Pull application area from amiibo | ||||
|  | ||||
|         IPC::ResponseBuilder rb{ctx, 3}; | ||||
|         rb.Push(RESULT_SUCCESS); | ||||
|         rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub | ||||
|     } | ||||
|  | ||||
|     bool has_attached_handle{}; | ||||
|     const u64 device_handle{Common::MakeMagic('Y', 'U', 'Z', 'U')}; | ||||
|     const u32 npad_id{0}; // Player 1 controller | ||||
|     State state{State::NonInitialized}; | ||||
|     DeviceState device_state{DeviceState::Initialized}; | ||||
|     Kernel::SharedPtr<Kernel::Event> activate_event; | ||||
|     Kernel::SharedPtr<Kernel::Event> deactivate_event; | ||||
|     Kernel::SharedPtr<Kernel::Event> availability_change_event; | ||||
|     const Module::Interface& nfp_interface; | ||||
| }; | ||||
|  | ||||
| void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_NFP, "called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushIpcInterface<IUser>(); | ||||
|     rb.PushIpcInterface<IUser>(*this); | ||||
| } | ||||
|  | ||||
| void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { | ||||
|     std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); | ||||
|     if (buffer.size() < sizeof(AmiiboFile)) { | ||||
|         return; // Failed to load file | ||||
|     } | ||||
|     std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); | ||||
|     nfc_tag_load->Signal(); | ||||
| } | ||||
| const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { | ||||
|     return nfc_tag_load; | ||||
| } | ||||
| const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { | ||||
|     return amiibo; | ||||
| } | ||||
|  | ||||
| void InstallInterfaces(SM::ServiceManager& service_manager) { | ||||
|   | ||||
| @@ -4,6 +4,9 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <vector> | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Service::NFP { | ||||
| @@ -15,7 +18,27 @@ public: | ||||
|         explicit Interface(std::shared_ptr<Module> module, const char* name); | ||||
|         ~Interface() override; | ||||
|  | ||||
|         struct ModelInfo { | ||||
|             std::array<u8, 0x8> amiibo_identification_block; | ||||
|             INSERT_PADDING_BYTES(0x38); | ||||
|         }; | ||||
|         static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); | ||||
|  | ||||
|         struct AmiiboFile { | ||||
|             std::array<u8, 10> uuid; | ||||
|             INSERT_PADDING_BYTES(0x4a); | ||||
|             ModelInfo model_info; | ||||
|         }; | ||||
|         static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); | ||||
|  | ||||
|         void CreateUserInterface(Kernel::HLERequestContext& ctx); | ||||
|         void LoadAmiibo(const std::vector<u8>& buffer); | ||||
|         const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; | ||||
|         const AmiiboFile& GetAmiiboBuffer() const; | ||||
|  | ||||
|     private: | ||||
|         Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; | ||||
|         AmiiboFile amiibo{}; | ||||
|  | ||||
|     protected: | ||||
|         std::shared_ptr<Module> module; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 David
					David