mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 23:06:43 +08:00 
			
		
		
		
	Merge pull request #10053 from german77/nfp_full
service: nfp: Implement all interfaces
This commit is contained in:
		
						commit
						799579c8d2
					
				| @ -570,10 +570,10 @@ add_library(core STATIC | ||||
|     hle/service/nfp/nfp.h | ||||
|     hle/service/nfp/nfp_device.cpp | ||||
|     hle/service/nfp/nfp_device.h | ||||
|     hle/service/nfp/nfp_interface.cpp | ||||
|     hle/service/nfp/nfp_interface.h | ||||
|     hle/service/nfp/nfp_result.h | ||||
|     hle/service/nfp/nfp_types.h | ||||
|     hle/service/nfp/nfp_user.cpp | ||||
|     hle/service/nfp/nfp_user.h | ||||
|     hle/service/ngct/ngct.cpp | ||||
|     hle/service/ngct/ngct.h | ||||
|     hle/service/nifm/nifm.cpp | ||||
|  | ||||
| @ -4,11 +4,138 @@ | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| #include "core/hle/service/nfp/nfp.h" | ||||
| #include "core/hle/service/nfp/nfp_user.h" | ||||
| #include "core/hle/service/nfp/nfp_interface.h" | ||||
| #include "core/hle/service/server_manager.h" | ||||
| 
 | ||||
| namespace Service::NFP { | ||||
| 
 | ||||
| class IUser final : public Interface { | ||||
| public: | ||||
|     explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IUser::Initialize, "Initialize"}, | ||||
|             {1, &IUser::Finalize, "Finalize"}, | ||||
|             {2, &IUser::ListDevices, "ListDevices"}, | ||||
|             {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, &IUser::SetApplicationArea, "SetApplicationArea"}, | ||||
|             {10, &IUser::Flush, "Flush"}, | ||||
|             {11, &IUser::Restore, "Restore"}, | ||||
|             {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, | ||||
|             {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, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||||
|             {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||||
|             {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class ISystem final : public Interface { | ||||
| public: | ||||
|     explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &ISystem::InitializeSystem, "InitializeSystem"}, | ||||
|             {1, &ISystem::FinalizeSystem, "FinalizeSystem"}, | ||||
|             {2, &ISystem::ListDevices, "ListDevices"}, | ||||
|             {3, &ISystem::StartDetection, "StartDetection"}, | ||||
|             {4, &ISystem::StopDetection, "StopDetection"}, | ||||
|             {5, &ISystem::Mount, "Mount"}, | ||||
|             {6, &ISystem::Unmount, "Unmount"}, | ||||
|             {10, &ISystem::Flush, "Flush"}, | ||||
|             {11, &ISystem::Restore, "Restore"}, | ||||
|             {12, &ISystem::CreateApplicationArea, "CreateApplicationArea"}, | ||||
|             {13, &ISystem::GetTagInfo, "GetTagInfo"}, | ||||
|             {14, &ISystem::GetRegisterInfo, "GetRegisterInfo"}, | ||||
|             {15, &ISystem::GetCommonInfo, "GetCommonInfo"}, | ||||
|             {16, &ISystem::GetModelInfo, "GetModelInfo"}, | ||||
|             {17, &ISystem::AttachActivateEvent, "AttachActivateEvent"}, | ||||
|             {18, &ISystem::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||||
|             {19, &ISystem::GetState, "GetState"}, | ||||
|             {20, &ISystem::GetDeviceState, "GetDeviceState"}, | ||||
|             {21, &ISystem::GetNpadId, "GetNpadId"}, | ||||
|             {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||||
|             {100, &ISystem::Format, "Format"}, | ||||
|             {101, &ISystem::GetAdminInfo, "GetAdminInfo"}, | ||||
|             {102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, | ||||
|             {103, &ISystem::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, | ||||
|             {104, &ISystem::DeleteRegisterInfo, "DeleteRegisterInfo"}, | ||||
|             {105, &ISystem::DeleteApplicationArea, "DeleteApplicationArea"}, | ||||
|             {106, &ISystem::ExistsApplicationArea, "ExistsApplicationArea"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class IDebug final : public Interface { | ||||
| public: | ||||
|     explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IDebug::InitializeDebug, "InitializeDebug"}, | ||||
|             {1, &IDebug::FinalizeDebug, "FinalizeDebug"}, | ||||
|             {2, &IDebug::ListDevices, "ListDevices"}, | ||||
|             {3, &IDebug::StartDetection, "StartDetection"}, | ||||
|             {4, &IDebug::StopDetection, "StopDetection"}, | ||||
|             {5, &IDebug::Mount, "Mount"}, | ||||
|             {6, &IDebug::Unmount, "Unmount"}, | ||||
|             {7, &IDebug::OpenApplicationArea, "OpenApplicationArea"}, | ||||
|             {8, &IDebug::GetApplicationArea, "GetApplicationArea"}, | ||||
|             {9, &IDebug::SetApplicationArea, "SetApplicationArea"}, | ||||
|             {10, &IDebug::Flush, "Flush"}, | ||||
|             {11, &IDebug::Restore, "Restore"}, | ||||
|             {12, &IDebug::CreateApplicationArea, "CreateApplicationArea"}, | ||||
|             {13, &IDebug::GetTagInfo, "GetTagInfo"}, | ||||
|             {14, &IDebug::GetRegisterInfo, "GetRegisterInfo"}, | ||||
|             {15, &IDebug::GetCommonInfo, "GetCommonInfo"}, | ||||
|             {16, &IDebug::GetModelInfo, "GetModelInfo"}, | ||||
|             {17, &IDebug::AttachActivateEvent, "AttachActivateEvent"}, | ||||
|             {18, &IDebug::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||||
|             {19, &IDebug::GetState, "GetState"}, | ||||
|             {20, &IDebug::GetDeviceState, "GetDeviceState"}, | ||||
|             {21, &IDebug::GetNpadId, "GetNpadId"}, | ||||
|             {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||||
|             {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||||
|             {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"}, | ||||
|             {100, &IDebug::Format, "Format"}, | ||||
|             {101, &IDebug::GetAdminInfo, "GetAdminInfo"}, | ||||
|             {102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, | ||||
|             {103, &IDebug::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, | ||||
|             {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"}, | ||||
|             {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"}, | ||||
|             {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"}, | ||||
|             {200, &IDebug::GetAll, "GetAll"}, | ||||
|             {201, &IDebug::SetAll, "SetAll"}, | ||||
|             {202, &IDebug::FlushDebug, "FlushDebug"}, | ||||
|             {203, &IDebug::BreakTag, "BreakTag"}, | ||||
|             {204, nullptr, "ReadBackupData"}, | ||||
|             {205, nullptr, "WriteBackupData"}, | ||||
|             {206, nullptr, "WriteNtf"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class IUserManager final : public ServiceFramework<IUserManager> { | ||||
| public: | ||||
|     explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} { | ||||
| @ -37,10 +164,68 @@ private: | ||||
|     std::shared_ptr<IUser> user_interface; | ||||
| }; | ||||
| 
 | ||||
| class ISystemManager final : public ServiceFramework<ISystemManager> { | ||||
| public: | ||||
|     explicit ISystemManager(Core::System& system_) : ServiceFramework{system_, "nfp:sys"} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &ISystemManager::CreateSystemInterface, "CreateSystemInterface"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void CreateSystemInterface(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
| 
 | ||||
|         if (system_interface == nullptr) { | ||||
|             system_interface = std::make_shared<ISystem>(system); | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushIpcInterface<ISystem>(system_interface); | ||||
|     } | ||||
| 
 | ||||
|     std::shared_ptr<ISystem> system_interface; | ||||
| }; | ||||
| 
 | ||||
| class IDebugManager final : public ServiceFramework<IDebugManager> { | ||||
| public: | ||||
|     explicit IDebugManager(Core::System& system_) : ServiceFramework{system_, "nfp:dbg"} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IDebugManager::CreateDebugInterface, "CreateDebugInterface"}, | ||||
|         }; | ||||
|         // clang-format on
 | ||||
| 
 | ||||
|         RegisterHandlers(functions); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void CreateDebugInterface(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_NFP, "called"); | ||||
| 
 | ||||
|         if (system_interface == nullptr) { | ||||
|             system_interface = std::make_shared<IDebug>(system); | ||||
|         } | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.PushIpcInterface<IDebug>(system_interface); | ||||
|     } | ||||
| 
 | ||||
|     std::shared_ptr<IDebug> system_interface; | ||||
| }; | ||||
| 
 | ||||
| void LoopProcess(Core::System& system) { | ||||
|     auto server_manager = std::make_unique<ServerManager>(system); | ||||
| 
 | ||||
|     server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system)); | ||||
|     server_manager->RegisterNamedService("nfp:sys", std::make_shared<ISystemManager>(system)); | ||||
|     server_manager->RegisterNamedService("nfp:dbg", std::make_shared<IDebugManager>(system)); | ||||
|     ServerManager::RunServer(std::move(server_manager)); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,6 @@ | ||||
| #include "core/hle/service/nfp/amiibo_crypto.h" | ||||
| #include "core/hle/service/nfp/nfp_device.h" | ||||
| #include "core/hle/service/nfp/nfp_result.h" | ||||
| #include "core/hle/service/nfp/nfp_user.h" | ||||
| #include "core/hle/service/time/time_manager.h" | ||||
| #include "core/hle/service/time/time_zone_content_manager.h" | ||||
| #include "core/hle/service/time/time_zone_types.h" | ||||
| @ -241,6 +240,42 @@ Result NfpDevice::Flush() { | ||||
| 
 | ||||
|     tag_data.write_counter++; | ||||
| 
 | ||||
|     FlushWithBreak(BreakType::Normal); | ||||
| 
 | ||||
|     is_data_moddified = false; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::FlushDebug() { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     tag_data.write_counter++; | ||||
| 
 | ||||
|     FlushWithBreak(BreakType::Normal); | ||||
| 
 | ||||
|     is_data_moddified = false; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::FlushWithBreak(BreakType break_type) { | ||||
|     if (break_type != BreakType::Normal) { | ||||
|         LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     std::vector<u8> data(sizeof(EncryptedNTAG215File)); | ||||
|     if (is_plain_amiibo) { | ||||
|         memcpy(data.data(), &tag_data, sizeof(tag_data)); | ||||
| @ -258,8 +293,6 @@ Result NfpDevice::Flush() { | ||||
|         return WriteAmiiboFailed; | ||||
|     } | ||||
| 
 | ||||
|     is_data_moddified = false; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| @ -417,6 +450,38 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (tag_data.settings.settings.amiibo_initialized == 0) { | ||||
|         return RegistrationIsNotInitialized; | ||||
|     } | ||||
| 
 | ||||
|     Service::Mii::MiiManager manager; | ||||
|     const auto& settings = tag_data.settings; | ||||
| 
 | ||||
|     // TODO: Validate and complete this data
 | ||||
|     register_info = { | ||||
|         .mii_store_data = {}, | ||||
|         .creation_date = settings.init_date.GetWriteDate(), | ||||
|         .amiibo_name = GetAmiiboName(settings), | ||||
|         .font_region = settings.settings.font_region, | ||||
|     }; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
| @ -807,6 +872,159 @@ Result NfpDevice::DeleteApplicationArea() { | ||||
|     return Flush(); | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::ExistApplicationArea(bool& has_application_area) { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::GetAll(NfpData& data) const { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     CommonInfo common_info{}; | ||||
|     Service::Mii::MiiManager manager; | ||||
|     const u64 application_id = tag_data.application_id; | ||||
| 
 | ||||
|     GetCommonInfo(common_info); | ||||
| 
 | ||||
|     data = { | ||||
|         .magic = tag_data.constant_value, | ||||
|         .write_counter = tag_data.write_counter, | ||||
|         .settings_crc = tag_data.settings.crc, | ||||
|         .common_info = common_info, | ||||
|         .mii_char_info = tag_data.owner_mii, | ||||
|         .mii_store_data_extension = tag_data.mii_extension, | ||||
|         .creation_date = tag_data.settings.init_date.GetWriteDate(), | ||||
|         .amiibo_name = tag_data.settings.amiibo_name, | ||||
|         .amiibo_name_null_terminated = 0, | ||||
|         .settings = tag_data.settings.settings, | ||||
|         .unknown1 = tag_data.unknown, | ||||
|         .register_info_crc = tag_data.register_info_crc, | ||||
|         .unknown2 = tag_data.unknown2, | ||||
|         .application_id = application_id, | ||||
|         .access_id = tag_data.application_area_id, | ||||
|         .settings_crc_counter = tag_data.settings.crc_counter, | ||||
|         .font_region = tag_data.settings.settings.font_region, | ||||
|         .tag_type = PackedTagType::Type2, | ||||
|         .console_type = | ||||
|             static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf), | ||||
|         .application_id_byte = tag_data.application_id_byte, | ||||
|         .application_area = tag_data.application_area, | ||||
|     }; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::SetAll(const NfpData& data) { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     tag_data.constant_value = data.magic; | ||||
|     tag_data.write_counter = data.write_counter; | ||||
|     tag_data.settings.crc = data.settings_crc; | ||||
|     tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date); | ||||
|     tag_data.write_counter = data.common_info.write_counter; | ||||
|     tag_data.amiibo_version = data.common_info.version; | ||||
|     tag_data.owner_mii = data.mii_char_info; | ||||
|     tag_data.mii_extension = data.mii_store_data_extension; | ||||
|     tag_data.settings.init_date.SetWriteDate(data.creation_date); | ||||
|     tag_data.settings.amiibo_name = data.amiibo_name; | ||||
|     tag_data.settings.settings = data.settings; | ||||
|     tag_data.unknown = data.unknown1; | ||||
|     tag_data.register_info_crc = data.register_info_crc; | ||||
|     tag_data.unknown2 = data.unknown2; | ||||
|     tag_data.application_id = data.application_id; | ||||
|     tag_data.application_area_id = data.access_id; | ||||
|     tag_data.settings.crc_counter = data.settings_crc_counter; | ||||
|     tag_data.settings.settings.font_region.Assign(data.font_region); | ||||
|     tag_data.application_id_byte = data.application_id_byte; | ||||
|     tag_data.application_area = data.application_area; | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::BreakTag(BreakType break_type) { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     // TODO: Complete this implementation
 | ||||
| 
 | ||||
|     return FlushWithBreak(break_type); | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::ReadBackupData() { | ||||
|     // Not implemented
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::WriteBackupData() { | ||||
|     // Not implemented
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| Result NfpDevice::WriteNtf() { | ||||
|     if (device_state != DeviceState::TagMounted) { | ||||
|         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||||
|         if (device_state == DeviceState::TagRemoved) { | ||||
|             return TagRemoved; | ||||
|         } | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||||
|         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||||
|         return WrongDeviceState; | ||||
|     } | ||||
| 
 | ||||
|     // Not implemented
 | ||||
| 
 | ||||
|     return ResultSuccess; | ||||
| } | ||||
| 
 | ||||
| u64 NfpDevice::GetHandle() const { | ||||
|     // Generate a handle based of the npad id
 | ||||
|     return static_cast<u64>(npad_id); | ||||
|  | ||||
| @ -41,12 +41,16 @@ public: | ||||
|     Result StopDetection(); | ||||
|     Result Mount(MountTarget mount_target); | ||||
|     Result Unmount(); | ||||
| 
 | ||||
|     Result Flush(); | ||||
|     Result FlushDebug(); | ||||
|     Result FlushWithBreak(BreakType break_type); | ||||
| 
 | ||||
|     Result GetTagInfo(TagInfo& tag_info) const; | ||||
|     Result GetCommonInfo(CommonInfo& common_info) const; | ||||
|     Result GetModelInfo(ModelInfo& model_info) const; | ||||
|     Result GetRegisterInfo(RegisterInfo& register_info) const; | ||||
|     Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const; | ||||
|     Result GetAdminInfo(AdminInfo& admin_info) const; | ||||
| 
 | ||||
|     Result DeleteRegisterInfo(); | ||||
| @ -61,6 +65,14 @@ public: | ||||
|     Result CreateApplicationArea(u32 access_id, std::span<const u8> data); | ||||
|     Result RecreateApplicationArea(u32 access_id, std::span<const u8> data); | ||||
|     Result DeleteApplicationArea(); | ||||
|     Result ExistApplicationArea(bool& has_application_area); | ||||
| 
 | ||||
|     Result GetAll(NfpData& data) const; | ||||
|     Result SetAll(const NfpData& data); | ||||
|     Result BreakTag(BreakType break_type); | ||||
|     Result ReadBackupData(); | ||||
|     Result WriteBackupData(); | ||||
|     Result WriteNtf(); | ||||
| 
 | ||||
|     u64 GetHandle() const; | ||||
|     u32 GetApplicationAreaSize() const; | ||||
|  | ||||
| @ -7,42 +7,13 @@ | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/service/ipc_helpers.h" | ||||
| #include "core/hle/service/nfp/nfp_device.h" | ||||
| #include "core/hle/service/nfp/nfp_interface.h" | ||||
| #include "core/hle/service/nfp/nfp_result.h" | ||||
| #include "core/hle/service/nfp/nfp_user.h" | ||||
| 
 | ||||
| namespace Service::NFP { | ||||
| 
 | ||||
| IUser::IUser(Core::System& system_) | ||||
|     : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name} { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &IUser::Initialize, "Initialize"}, | ||||
|         {1, &IUser::Finalize, "Finalize"}, | ||||
|         {2, &IUser::ListDevices, "ListDevices"}, | ||||
|         {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, &IUser::SetApplicationArea, "SetApplicationArea"}, | ||||
|         {10, &IUser::Flush, "Flush"}, | ||||
|         {11, &IUser::Restore, "Restore"}, | ||||
|         {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, | ||||
|         {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, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||||
|         {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||||
|         {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| 
 | ||||
| Interface::Interface(Core::System& system_, const char* name) | ||||
|     : ServiceFramework{system_, name}, service_context{system_, service_name} { | ||||
|     availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); | ||||
| 
 | ||||
|     for (u32 device_index = 0; device_index < 10; device_index++) { | ||||
| @ -52,11 +23,11 @@ IUser::IUser(Core::System& system_) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| IUser ::~IUser() { | ||||
| Interface::~Interface() { | ||||
|     availability_change_event->Close(); | ||||
| } | ||||
| 
 | ||||
| void IUser::Initialize(HLERequestContext& ctx) { | ||||
| void Interface::Initialize(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::Initialized; | ||||
| @ -69,7 +40,33 @@ void IUser::Initialize(HLERequestContext& ctx) { | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void IUser::Finalize(HLERequestContext& ctx) { | ||||
| void Interface::InitializeSystem(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::Initialized; | ||||
| 
 | ||||
|     for (auto& device : devices) { | ||||
|         device->Initialize(); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void Interface::InitializeDebug(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::Initialized; | ||||
| 
 | ||||
|     for (auto& device : devices) { | ||||
|         device->Initialize(); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void Interface::Finalize(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::NonInitialized; | ||||
| @ -82,7 +79,33 @@ void IUser::Finalize(HLERequestContext& ctx) { | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void IUser::ListDevices(HLERequestContext& ctx) { | ||||
| void Interface::FinalizeSystem(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::NonInitialized; | ||||
| 
 | ||||
|     for (auto& device : devices) { | ||||
|         device->Finalize(); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void Interface::FinalizeDebug(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     state = State::NonInitialized; | ||||
| 
 | ||||
|     for (auto& device : devices) { | ||||
|         device->Finalize(); | ||||
|     } | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
| 
 | ||||
| void Interface::ListDevices(HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_NFP, "called"); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
| @ -128,7 +151,7 @@ void IUser::ListDevices(HLERequestContext& ctx) { | ||||
|     rb.Push(static_cast<s32>(nfp_devices.size())); | ||||
| } | ||||
| 
 | ||||
| void IUser::StartDetection(HLERequestContext& ctx) { | ||||
| void Interface::StartDetection(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; | ||||
| @ -153,7 +176,7 @@ void IUser::StartDetection(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::StopDetection(HLERequestContext& ctx) { | ||||
| void Interface::StopDetection(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -177,7 +200,7 @@ void IUser::StopDetection(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::Mount(HLERequestContext& ctx) { | ||||
| void Interface::Mount(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto model_type{rp.PopEnum<ModelType>()}; | ||||
| @ -204,7 +227,7 @@ void IUser::Mount(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::Unmount(HLERequestContext& ctx) { | ||||
| void Interface::Unmount(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -228,7 +251,7 @@ void IUser::Unmount(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::OpenApplicationArea(HLERequestContext& ctx) { | ||||
| void Interface::OpenApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto access_id{rp.Pop<u32>()}; | ||||
| @ -253,7 +276,7 @@ void IUser::OpenApplicationArea(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetApplicationArea(HLERequestContext& ctx) { | ||||
| void Interface::GetApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto data_size = ctx.GetWriteBufferSize(); | ||||
| @ -287,7 +310,7 @@ void IUser::GetApplicationArea(HLERequestContext& ctx) { | ||||
|     rb.Push(static_cast<u32>(data_size)); | ||||
| } | ||||
| 
 | ||||
| void IUser::SetApplicationArea(HLERequestContext& ctx) { | ||||
| void Interface::SetApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto data{ctx.ReadBuffer()}; | ||||
| @ -318,7 +341,7 @@ void IUser::SetApplicationArea(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::Flush(HLERequestContext& ctx) { | ||||
| void Interface::Flush(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -342,7 +365,7 @@ void IUser::Flush(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::Restore(HLERequestContext& ctx) { | ||||
| void Interface::Restore(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); | ||||
| @ -366,7 +389,7 @@ void IUser::Restore(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::CreateApplicationArea(HLERequestContext& ctx) { | ||||
| void Interface::CreateApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto access_id{rp.Pop<u32>()}; | ||||
| @ -399,7 +422,7 @@ void IUser::CreateApplicationArea(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetTagInfo(HLERequestContext& ctx) { | ||||
| void Interface::GetTagInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -425,7 +448,7 @@ void IUser::GetTagInfo(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetRegisterInfo(HLERequestContext& ctx) { | ||||
| void Interface::GetRegisterInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -451,7 +474,7 @@ void IUser::GetRegisterInfo(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetCommonInfo(HLERequestContext& ctx) { | ||||
| void Interface::GetCommonInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -477,7 +500,7 @@ void IUser::GetCommonInfo(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetModelInfo(HLERequestContext& ctx) { | ||||
| void Interface::GetModelInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -503,7 +526,7 @@ void IUser::GetModelInfo(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void IUser::AttachActivateEvent(HLERequestContext& ctx) { | ||||
| void Interface::AttachActivateEvent(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -527,7 +550,7 @@ void IUser::AttachActivateEvent(HLERequestContext& ctx) { | ||||
|     rb.PushCopyObjects(device.value()->GetActivateEvent()); | ||||
| } | ||||
| 
 | ||||
| void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { | ||||
| void Interface::AttachDeactivateEvent(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -551,7 +574,7 @@ void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { | ||||
|     rb.PushCopyObjects(device.value()->GetDeactivateEvent()); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetState(HLERequestContext& ctx) { | ||||
| void Interface::GetState(HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_NFP, "called"); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
| @ -559,7 +582,7 @@ void IUser::GetState(HLERequestContext& ctx) { | ||||
|     rb.PushEnum(state); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetDeviceState(HLERequestContext& ctx) { | ||||
| void Interface::GetDeviceState(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -577,7 +600,7 @@ void IUser::GetDeviceState(HLERequestContext& ctx) { | ||||
|     rb.PushEnum(device.value()->GetCurrentState()); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetNpadId(HLERequestContext& ctx) { | ||||
| void Interface::GetNpadId(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -601,7 +624,7 @@ void IUser::GetNpadId(HLERequestContext& ctx) { | ||||
|     rb.PushEnum(device.value()->GetNpadId()); | ||||
| } | ||||
| 
 | ||||
| void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { | ||||
| void Interface::GetApplicationAreaSize(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| @ -619,7 +642,7 @@ void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { | ||||
|     rb.Push(device.value()->GetApplicationAreaSize()); | ||||
| } | ||||
| 
 | ||||
| void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { | ||||
| void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { | ||||
|     LOG_INFO(Service_NFP, "called"); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
| @ -633,7 +656,7 @@ void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { | ||||
|     rb.PushCopyObjects(availability_change_event->GetReadableEvent()); | ||||
| } | ||||
| 
 | ||||
| void IUser::RecreateApplicationArea(HLERequestContext& ctx) { | ||||
| void Interface::RecreateApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto access_id{rp.Pop<u32>()}; | ||||
| @ -660,7 +683,361 @@ void IUser::RecreateApplicationArea(HLERequestContext& ctx) { | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| std::optional<std::shared_ptr<NfpDevice>> IUser::GetNfpDevice(u64 handle) { | ||||
| void Interface::Format(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->Format(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::GetAdminInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     AdminInfo admin_info{}; | ||||
|     const auto result = device.value()->GetAdminInfo(admin_info); | ||||
|     ctx.WriteBuffer(admin_info); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     RegisterInfoPrivate register_info{}; | ||||
|     const auto result = device.value()->GetRegisterInfoPrivate(register_info); | ||||
|     ctx.WriteBuffer(register_info); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto buffer{ctx.ReadBuffer()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle, | ||||
|               buffer.size()); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->SetRegisterInfoPrivate({}); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::DeleteRegisterInfo(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->DeleteRegisterInfo(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::DeleteApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->DeleteApplicationArea(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::ExistsApplicationArea(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     bool has_application_area = false; | ||||
|     const auto result = device.value()->ExistApplicationArea(has_application_area); | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(result); | ||||
|     rb.Push(has_application_area); | ||||
| } | ||||
| 
 | ||||
| void Interface::GetAll(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     NfpData data{}; | ||||
|     const auto result = device.value()->GetAll(data); | ||||
| 
 | ||||
|     ctx.WriteBuffer(data); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::SetAll(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto nfp_data{ctx.ReadBuffer()}; | ||||
| 
 | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     NfpData data{}; | ||||
|     memcpy(&data, nfp_data.data(), sizeof(NfpData)); | ||||
| 
 | ||||
|     const auto result = device.value()->SetAll(data); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::FlushDebug(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->FlushDebug(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::BreakTag(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     const auto break_type{rp.PopEnum<BreakType>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}, break_type={}", device_handle, break_type); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->BreakTag(break_type); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::ReadBackupData(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->ReadBackupData(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::WriteBackupData(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->WriteBackupData(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| void Interface::WriteNtf(HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto device_handle{rp.Pop<u64>()}; | ||||
|     LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||||
| 
 | ||||
|     if (state == State::NonInitialized) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NfcDisabled); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto device = GetNfpDevice(device_handle); | ||||
| 
 | ||||
|     if (!device.has_value()) { | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(DeviceNotFound); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const auto result = device.value()->WriteNtf(); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(result); | ||||
| } | ||||
| 
 | ||||
| std::optional<std::shared_ptr<NfpDevice>> Interface::GetNfpDevice(u64 handle) { | ||||
|     for (auto& device : devices) { | ||||
|         if (device->GetHandle() == handle) { | ||||
|             return device; | ||||
| @ -13,19 +13,17 @@ | ||||
| namespace Service::NFP { | ||||
| class NfpDevice; | ||||
| 
 | ||||
| class IUser final : public ServiceFramework<IUser> { | ||||
| class Interface : public ServiceFramework<Interface> { | ||||
| public: | ||||
|     explicit IUser(Core::System& system_); | ||||
|     ~IUser(); | ||||
| 
 | ||||
| private: | ||||
|     enum class State : u32 { | ||||
|         NonInitialized, | ||||
|         Initialized, | ||||
|     }; | ||||
|     explicit Interface(Core::System& system_, const char* name); | ||||
|     ~Interface() override; | ||||
| 
 | ||||
|     void Initialize(HLERequestContext& ctx); | ||||
|     void InitializeSystem(HLERequestContext& ctx); | ||||
|     void InitializeDebug(HLERequestContext& ctx); | ||||
|     void Finalize(HLERequestContext& ctx); | ||||
|     void FinalizeSystem(HLERequestContext& ctx); | ||||
|     void FinalizeDebug(HLERequestContext& ctx); | ||||
|     void ListDevices(HLERequestContext& ctx); | ||||
|     void StartDetection(HLERequestContext& ctx); | ||||
|     void StopDetection(HLERequestContext& ctx); | ||||
| @ -49,6 +47,26 @@ private: | ||||
|     void GetApplicationAreaSize(HLERequestContext& ctx); | ||||
|     void AttachAvailabilityChangeEvent(HLERequestContext& ctx); | ||||
|     void RecreateApplicationArea(HLERequestContext& ctx); | ||||
|     void Format(HLERequestContext& ctx); | ||||
|     void GetAdminInfo(HLERequestContext& ctx); | ||||
|     void GetRegisterInfoPrivate(HLERequestContext& ctx); | ||||
|     void SetRegisterInfoPrivate(HLERequestContext& ctx); | ||||
|     void DeleteRegisterInfo(HLERequestContext& ctx); | ||||
|     void DeleteApplicationArea(HLERequestContext& ctx); | ||||
|     void ExistsApplicationArea(HLERequestContext& ctx); | ||||
|     void GetAll(HLERequestContext& ctx); | ||||
|     void SetAll(HLERequestContext& ctx); | ||||
|     void FlushDebug(HLERequestContext& ctx); | ||||
|     void BreakTag(HLERequestContext& ctx); | ||||
|     void ReadBackupData(HLERequestContext& ctx); | ||||
|     void WriteBackupData(HLERequestContext& ctx); | ||||
|     void WriteNtf(HLERequestContext& ctx); | ||||
| 
 | ||||
| private: | ||||
|     enum class State : u32 { | ||||
|         NonInitialized, | ||||
|         Initialized, | ||||
|     }; | ||||
| 
 | ||||
|     std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle); | ||||
| 
 | ||||
| @ -109,6 +109,12 @@ enum class AppAreaVersion : u8 { | ||||
|     NotSet = 0xFF, | ||||
| }; | ||||
| 
 | ||||
| enum class BreakType : u32 { | ||||
|     Normal, | ||||
|     Unknown1, | ||||
|     Unknown2, | ||||
| }; | ||||
| 
 | ||||
| enum class CabinetMode : u8 { | ||||
|     StartNicknameAndOwnerSettings, | ||||
|     StartGameDataEraser, | ||||
| @ -181,6 +187,12 @@ struct AmiiboDate { | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     void SetWriteDate(const WriteDate& write_date) { | ||||
|         SetYear(write_date.year); | ||||
|         SetMonth(write_date.month); | ||||
|         SetDay(write_date.day); | ||||
|     } | ||||
| 
 | ||||
|     void SetYear(u16 year) { | ||||
|         const u16 year_converted = static_cast<u16>((year - 2000) << 9); | ||||
|         raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); | ||||
| @ -354,6 +366,15 @@ struct RegisterInfo { | ||||
| }; | ||||
| static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | ||||
| 
 | ||||
| struct RegisterInfoPrivate { | ||||
|     Service::Mii::MiiStoreData mii_store_data; | ||||
|     WriteDate creation_date; | ||||
|     AmiiboName amiibo_name; | ||||
|     u8 font_region; | ||||
|     INSERT_PADDING_BYTES(0x8E); | ||||
| }; | ||||
| static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); | ||||
| 
 | ||||
| struct AdminInfo { | ||||
|     u64 application_id; | ||||
|     u32 application_area_id; | ||||
| @ -366,6 +387,39 @@ struct AdminInfo { | ||||
| }; | ||||
| static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); | ||||
| 
 | ||||
| #pragma pack(1) | ||||
| // This is nn::nfp::NfpData
 | ||||
| struct NfpData { | ||||
|     u8 magic; | ||||
|     INSERT_PADDING_BYTES(0x1); | ||||
|     u8 write_counter; | ||||
|     INSERT_PADDING_BYTES(0x1); | ||||
|     u32 settings_crc; | ||||
|     INSERT_PADDING_BYTES(0x38); | ||||
|     CommonInfo common_info; | ||||
|     Service::Mii::Ver3StoreData mii_char_info; | ||||
|     Service::Mii::NfpStoreDataExtension mii_store_data_extension; | ||||
|     WriteDate creation_date; | ||||
|     std::array<u16_be, amiibo_name_length> amiibo_name; | ||||
|     u16 amiibo_name_null_terminated; | ||||
|     Settings settings; | ||||
|     u8 unknown1; | ||||
|     u32 register_info_crc; | ||||
|     std::array<u32, 5> unknown2; | ||||
|     INSERT_PADDING_BYTES(0x64); | ||||
|     u64 application_id; | ||||
|     u32 access_id; | ||||
|     u16 settings_crc_counter; | ||||
|     u8 font_region; | ||||
|     PackedTagType tag_type; | ||||
|     AppAreaVersion console_type; | ||||
|     u8 application_id_byte; | ||||
|     INSERT_PADDING_BYTES(0x2E); | ||||
|     ApplicationArea application_area; | ||||
| }; | ||||
| static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); | ||||
| #pragma pack() | ||||
| 
 | ||||
| struct SectorKey { | ||||
|     MifareCmd command; | ||||
|     u8 unknown; // Usually 1
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user