summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/hle/service/nfc/nfc.cpp71
-rw-r--r--src/core/hle/service/nfc/nfc_device.cpp197
-rw-r--r--src/core/hle/service/nfc/nfc_device.h70
-rw-r--r--src/core/hle/service/nfc/nfc_result.h17
-rw-r--r--src/core/hle/service/nfc/nfc_user.cpp365
-rw-r--r--src/core/hle/service/nfc/nfc_user.h52
-rw-r--r--src/core/hle/service/nfp/amiibo_crypto.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp6
-rw-r--r--src/core/hle/service/nfp/nfp_device.h3
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp15
-rw-r--r--src/core/hle/service/nfp/nfp_user.h5
12 files changed, 723 insertions, 84 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 740c5b0fd..5629980d9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -530,6 +530,11 @@ add_library(core STATIC
hle/service/ncm/ncm.h
hle/service/nfc/nfc.cpp
hle/service/nfc/nfc.h
+ hle/service/nfc/nfc_device.cpp
+ hle/service/nfc/nfc_device.h
+ hle/service/nfc/nfc_result.h
+ hle/service/nfc/nfc_user.cpp
+ hle/service/nfc/nfc_user.h
hle/service/nfp/amiibo_crypto.cpp
hle/service/nfp/amiibo_crypto.h
hle/service/nfp/nfp.cpp
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 046c5f18f..2f4bacb3b 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -7,6 +7,7 @@
#include "common/settings.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/nfc/nfc_user.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -97,76 +98,6 @@ private:
}
};
-class IUser final : public ServiceFramework<IUser> {
-public:
- explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IUser::InitializeOld, "InitializeOld"},
- {1, &IUser::FinalizeOld, "FinalizeOld"},
- {2, &IUser::GetStateOld, "GetStateOld"},
- {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"},
- {400, &IUser::InitializeOld, "Initialize"},
- {401, &IUser::FinalizeOld, "Finalize"},
- {402, &IUser::GetStateOld, "GetState"},
- {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"},
- {404, nullptr, "ListDevices"},
- {405, nullptr, "GetDeviceState"},
- {406, nullptr, "GetNpadId"},
- {407, nullptr, "AttachAvailabilityChangeEvent"},
- {408, nullptr, "StartDetection"},
- {409, nullptr, "StopDetection"},
- {410, nullptr, "GetTagInfo"},
- {411, nullptr, "AttachActivateEvent"},
- {412, nullptr, "AttachDeactivateEvent"},
- {1000, nullptr, "ReadMifare"},
- {1001, nullptr, "WriteMifare"},
- {1300, nullptr, "SendCommandByPassThrough"},
- {1301, nullptr, "KeepPassThroughSession"},
- {1302, nullptr, "ReleasePassThroughSession"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- enum class NfcStates : u32 {
- Finalized = 6,
- };
-
- void InitializeOld(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0};
- rb.Push(ResultSuccess);
- // We don't deal with hardware initialization so we can just stub this.
- }
-
- void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw<u8>(true);
- }
-
- void GetStateOld(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFC, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- 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(ResultSuccess);
- }
-};
-
class NFC_U final : public ServiceFramework<NFC_U> {
public:
explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
new file mode 100644
index 000000000..4d514cf5f
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_device.cpp
@@ -0,0 +1,197 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/input.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_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/nfc_device.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_user.h"
+
+namespace Service::NFC {
+NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_)
+ : npad_id{npad_id_}, system{system_}, service_context{service_context_},
+ availability_change_event{availability_change_event_} {
+ activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
+ deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
+ npad_device = system.HIDCore().GetEmulatedController(npad_id);
+
+ Core::HID::ControllerUpdateCallback engine_callback{
+ .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
+ .is_npad_service = false,
+ };
+ is_controller_set = true;
+ callback_key = npad_device->SetCallback(engine_callback);
+}
+
+NfcDevice::~NfcDevice() {
+ activate_event->Close();
+ deactivate_event->Close();
+ if (!is_controller_set) {
+ return;
+ }
+ npad_device->DeleteCallback(callback_key);
+ is_controller_set = false;
+};
+
+void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
+ if (type == Core::HID::ControllerTriggerType::Connected ||
+ type == Core::HID::ControllerTriggerType::Disconnected) {
+ availability_change_event->Signal();
+ return;
+ }
+
+ if (type != Core::HID::ControllerTriggerType::Nfc) {
+ return;
+ }
+
+ if (!npad_device->IsConnected()) {
+ return;
+ }
+
+ const auto nfc_status = npad_device->GetNfc();
+ switch (nfc_status.state) {
+ case Common::Input::NfcState::NewAmiibo:
+ LoadNfcTag(nfc_status.data);
+ break;
+ case Common::Input::NfcState::AmiiboRemoved:
+ if (device_state != NFP::DeviceState::SearchingForTag) {
+ CloseNfcTag();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
+ if (device_state != NFP::DeviceState::SearchingForTag) {
+ LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
+ return false;
+ }
+
+ if (data.size() != sizeof(NFP::EncryptedNTAG215File)) {
+ LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
+ return false;
+ }
+
+ memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+
+ device_state = NFP::DeviceState::TagFound;
+ deactivate_event->GetReadableEvent().Clear();
+ activate_event->Signal();
+ return true;
+}
+
+void NfcDevice::CloseNfcTag() {
+ LOG_INFO(Service_NFC, "Remove nfc tag");
+
+ device_state = NFP::DeviceState::TagRemoved;
+ encrypted_tag_data = {};
+ activate_event->GetReadableEvent().Clear();
+ deactivate_event->Signal();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
+ return activate_event->GetReadableEvent();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
+ return deactivate_event->GetReadableEvent();
+}
+
+void NfcDevice::Initialize() {
+ device_state =
+ npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
+ encrypted_tag_data = {};
+}
+
+void NfcDevice::Finalize() {
+ if (device_state == NFP::DeviceState::SearchingForTag ||
+ device_state == NFP::DeviceState::TagRemoved) {
+ StopDetection();
+ }
+ device_state = NFP::DeviceState::Unavailable;
+}
+
+Result NfcDevice::StartDetection(s32 protocol_) {
+ if (device_state != NFP::DeviceState::Initialized &&
+ device_state != NFP::DeviceState::TagRemoved) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return WrongDeviceState;
+ }
+
+ if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) {
+ LOG_ERROR(Service_NFC, "Nfc not supported");
+ return NfcDisabled;
+ }
+
+ device_state = NFP::DeviceState::SearchingForTag;
+ protocol = protocol_;
+ return ResultSuccess;
+}
+
+Result NfcDevice::StopDetection() {
+ npad_device->SetPollingMode(Common::Input::PollingMode::Active);
+
+ if (device_state == NFP::DeviceState::Initialized) {
+ return ResultSuccess;
+ }
+
+ if (device_state == NFP::DeviceState::TagFound ||
+ device_state == NFP::DeviceState::TagMounted) {
+ CloseNfcTag();
+ return ResultSuccess;
+ }
+ if (device_state == NFP::DeviceState::SearchingForTag ||
+ device_state == NFP::DeviceState::TagRemoved) {
+ device_state = NFP::DeviceState::Initialized;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return WrongDeviceState;
+}
+
+Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) 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;
+ }
+
+ // Protocol and tag type may change here
+ 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::Type2,
+ };
+
+ return ResultSuccess;
+}
+
+u64 NfcDevice::GetHandle() const {
+ // Generate a handle based of the npad id
+ return static_cast<u64>(npad_id);
+}
+
+NFP::DeviceState NfcDevice::GetCurrentState() const {
+ return device_state;
+}
+
+Core::HID::NpadIdType NfcDevice::GetNpadId() const {
+ return npad_id;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h
new file mode 100644
index 000000000..fa1348f1a
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_device.h
@@ -0,0 +1,70 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Core::HID {
+class EmulatedController;
+enum class ControllerTriggerType;
+enum class NpadIdType : u32;
+} // namespace Core::HID
+
+namespace Service::NFC {
+class NfcDevice {
+public:
+ NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_);
+ ~NfcDevice();
+
+ void Initialize();
+ void Finalize();
+
+ Result StartDetection(s32 protocol_);
+ Result StopDetection();
+
+ Result GetTagInfo(NFP::TagInfo& tag_info) const;
+
+ u64 GetHandle() const;
+ NFP::DeviceState GetCurrentState() const;
+ Core::HID::NpadIdType GetNpadId() const;
+
+ Kernel::KReadableEvent& GetActivateEvent() const;
+ Kernel::KReadableEvent& GetDeactivateEvent() const;
+
+private:
+ void NpadUpdate(Core::HID::ControllerTriggerType type);
+ bool LoadNfcTag(std::span<const u8> data);
+ void CloseNfcTag();
+
+ bool is_controller_set{};
+ int callback_key;
+ const Core::HID::NpadIdType npad_id;
+ Core::System& system;
+ Core::HID::EmulatedController* npad_device = nullptr;
+ KernelHelpers::ServiceContext& service_context;
+ Kernel::KEvent* activate_event = nullptr;
+ Kernel::KEvent* deactivate_event = nullptr;
+ Kernel::KEvent* availability_change_event = nullptr;
+
+ s32 protocol{};
+ NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
+
+ NFP::EncryptedNTAG215File encrypted_tag_data{};
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
new file mode 100644
index 000000000..537dc15f4
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::NFC {
+
+constexpr Result DeviceNotFound(ErrorModule::NFC, 64);
+constexpr Result InvalidArgument(ErrorModule::NFC, 65);
+constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
+constexpr Result NfcDisabled(ErrorModule::NFC, 80);
+constexpr Result TagRemoved(ErrorModule::NFC, 97);
+constexpr Result CorruptedData(ErrorModule::NFC, 144);
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp
new file mode 100644
index 000000000..0753333bf
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_user.cpp
@@ -0,0 +1,365 @@
+// 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/nfc_device.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_user.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+IUser::IUser(Core::System& system_)
+ : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
+ static const FunctionInfo functions[] = {
+ {0, &IUser::Initialize, "InitializeOld"},
+ {1, &IUser::Finalize, "FinalizeOld"},
+ {2, &IUser::GetState, "GetStateOld"},
+ {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
+ {400, &IUser::Initialize, "Initialize"},
+ {401, &IUser::Finalize, "Finalize"},
+ {402, &IUser::GetState, "GetState"},
+ {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
+ {404, &IUser::ListDevices, "ListDevices"},
+ {405, &IUser::GetDeviceState, "GetDeviceState"},
+ {406, &IUser::GetNpadId, "GetNpadId"},
+ {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {408, &IUser::StartDetection, "StartDetection"},
+ {409, &IUser::StopDetection, "StopDetection"},
+ {410, &IUser::GetTagInfo, "GetTagInfo"},
+ {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
+ {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {1000, nullptr, "ReadMifare"},
+ {1001, nullptr, "WriteMifare"},
+ {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ RegisterHandlers(functions);
+
+ availability_change_event = service_context.CreateEvent("IUser: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);
+ }
+}
+
+IUser ::~IUser() {
+ availability_change_event->Close();
+}
+
+void IUser::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 IUser::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 IUser::GetState(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(state);
+}
+
+void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(state != State::NonInitialized);
+}
+
+void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ if (!ctx.CanWriteBuffer()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(InvalidArgument);
+ return;
+ }
+
+ if (ctx.GetWriteBufferSize() == 0) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(InvalidArgument);
+ return;
+ }
+
+ std::vector<u64> nfp_devices;
+ const std::size_t max_allowed_devices = ctx.GetWriteBufferSize() / sizeof(u64);
+
+ for (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(DeviceNotFound);
+ return;
+ }
+
+ ctx.WriteBuffer(nfp_devices);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<s32>(nfp_devices.size()));
+}
+
+void IUser::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(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(device.value()->GetCurrentState());
+}
+
+void IUser::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(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(device.value()->GetNpadId());
+}
+
+void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(availability_change_event->GetReadableEvent());
+}
+
+void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto nfp_protocol{rp.Pop<s32>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ const auto result = device.value()->StartDetection(nfp_protocol);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::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(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ const auto result = device.value()->StopDetection();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::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(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ NFP::TagInfo tag_info{};
+ const auto result = device.value()->GetTagInfo(tag_info);
+ ctx.WriteBuffer(tag_info);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::AttachActivateEvent(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(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(device.value()->GetActivateEvent());
+}
+
+void IUser::AttachDeactivateEvent(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(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(device.value()->GetDeactivateEvent());
+}
+
+void IUser::SendCommandByPassThrough(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
+ const auto command_data{ctx.ReadBuffer()};
+
+ LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
+ device_handle, timeout.ToSeconds(), command_data.size());
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ std::vector<u8> out_data(1);
+ // TODO: Request data from nfc device
+ ctx.WriteBuffer(out_data);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<u32>(out_data.size()));
+}
+
+std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_user.h
new file mode 100644
index 000000000..a5a4f12f9
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_user.h
@@ -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 IUser final : public ServiceFramework<IUser> {
+public:
+ explicit IUser(Core::System& system_);
+ ~IUser();
+
+private:
+ enum class State : u32 {
+ NonInitialized,
+ Initialized,
+ };
+
+ void Initialize(Kernel::HLERequestContext& ctx);
+ void Finalize(Kernel::HLERequestContext& ctx);
+ void GetState(Kernel::HLERequestContext& ctx);
+ void IsNfcEnabled(Kernel::HLERequestContext& ctx);
+ void ListDevices(Kernel::HLERequestContext& ctx);
+ void GetDeviceState(Kernel::HLERequestContext& ctx);
+ void GetNpadId(Kernel::HLERequestContext& ctx);
+ void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
+ void StartDetection(Kernel::HLERequestContext& ctx);
+ void StopDetection(Kernel::HLERequestContext& ctx);
+ void GetTagInfo(Kernel::HLERequestContext& ctx);
+ void AttachActivateEvent(Kernel::HLERequestContext& ctx);
+ void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
+ void SendCommandByPassThrough(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
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp
index 167e29572..ffb2f959c 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfp/amiibo_crypto.cpp
@@ -12,7 +12,6 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
-#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfp/amiibo_crypto.h"
namespace Service::NFP::AmiiboCrypto {
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
index e1bf90d7c..c860fd1a1 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfp/nfp_device.cpp
@@ -2,10 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
-#include <atomic>
-#include "common/fs/file.h"
-#include "common/fs/path_util.h"
#include "common/input.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -19,7 +16,6 @@
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/mii/types.h"
#include "core/hle/service/nfp/amiibo_crypto.h"
-#include "core/hle/service/nfp/nfp.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"
@@ -49,6 +45,8 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
}
NfpDevice::~NfpDevice() {
+ activate_event->Close();
+ deactivate_event->Close();
if (!is_controller_set) {
return;
}
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
index 3d1cb4609..b6a46f2ac 100644
--- a/src/core/hle/service/nfp/nfp_device.h
+++ b/src/core/hle/service/nfp/nfp_device.h
@@ -3,11 +3,10 @@
#pragma once
-#include <array>
#include <span>
#include <vector>
-#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index ac492cc27..2fe3c0ea0 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <array>
-#include <atomic>
-
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hid/hid_types.h"
@@ -55,8 +52,12 @@ IUser::IUser(Core::System& system_)
}
}
+IUser ::~IUser() {
+ availability_change_event->Close();
+}
+
void IUser::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
+ LOG_INFO(Service_NFP, "called");
state = State::Initialized;
@@ -64,7 +65,7 @@ void IUser::Initialize(Kernel::HLERequestContext& ctx) {
device->Initialize();
}
- IPC::ResponseBuilder rb{ctx, 2, 0};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
@@ -551,9 +552,9 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
}
void IUser::GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
+ LOG_DEBUG(Service_NFP, "called");
- IPC::ResponseBuilder rb{ctx, 3, 0};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 47aff3695..7e9a90af8 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -3,6 +3,10 @@
#pragma once
+#include <array>
+#include <memory>
+#include <optional>
+
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
@@ -12,6 +16,7 @@ class NfpDevice;
class IUser final : public ServiceFramework<IUser> {
public:
explicit IUser(Core::System& system_);
+ ~IUser();
private:
enum class State : u32 {