summaryrefslogtreecommitdiff
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
530 hle/service/ncm/ncm.h 530 hle/service/ncm/ncm.h
531 hle/service/nfc/nfc.cpp 531 hle/service/nfc/nfc.cpp
532 hle/service/nfc/nfc.h 532 hle/service/nfc/nfc.h
533 hle/service/nfc/nfc_device.cpp
534 hle/service/nfc/nfc_device.h
535 hle/service/nfc/nfc_result.h
536 hle/service/nfc/nfc_user.cpp
537 hle/service/nfc/nfc_user.h
533 hle/service/nfp/amiibo_crypto.cpp 538 hle/service/nfp/amiibo_crypto.cpp
534 hle/service/nfp/amiibo_crypto.h 539 hle/service/nfp/amiibo_crypto.h
535 hle/service/nfp/nfp.cpp 540 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 @@
7#include "common/settings.h" 7#include "common/settings.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/service/nfc/nfc.h" 9#include "core/hle/service/nfc/nfc.h"
10#include "core/hle/service/nfc/nfc_user.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h" 12#include "core/hle/service/sm/sm.h"
12 13
@@ -97,76 +98,6 @@ private:
97 } 98 }
98}; 99};
99 100
100class IUser final : public ServiceFramework<IUser> {
101public:
102 explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} {
103 // clang-format off
104 static const FunctionInfo functions[] = {
105 {0, &IUser::InitializeOld, "InitializeOld"},
106 {1, &IUser::FinalizeOld, "FinalizeOld"},
107 {2, &IUser::GetStateOld, "GetStateOld"},
108 {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"},
109 {400, &IUser::InitializeOld, "Initialize"},
110 {401, &IUser::FinalizeOld, "Finalize"},
111 {402, &IUser::GetStateOld, "GetState"},
112 {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"},
113 {404, nullptr, "ListDevices"},
114 {405, nullptr, "GetDeviceState"},
115 {406, nullptr, "GetNpadId"},
116 {407, nullptr, "AttachAvailabilityChangeEvent"},
117 {408, nullptr, "StartDetection"},
118 {409, nullptr, "StopDetection"},
119 {410, nullptr, "GetTagInfo"},
120 {411, nullptr, "AttachActivateEvent"},
121 {412, nullptr, "AttachDeactivateEvent"},
122 {1000, nullptr, "ReadMifare"},
123 {1001, nullptr, "WriteMifare"},
124 {1300, nullptr, "SendCommandByPassThrough"},
125 {1301, nullptr, "KeepPassThroughSession"},
126 {1302, nullptr, "ReleasePassThroughSession"},
127 };
128 // clang-format on
129
130 RegisterHandlers(functions);
131 }
132
133private:
134 enum class NfcStates : u32 {
135 Finalized = 6,
136 };
137
138 void InitializeOld(Kernel::HLERequestContext& ctx) {
139 LOG_DEBUG(Service_NFC, "called");
140
141 IPC::ResponseBuilder rb{ctx, 2, 0};
142 rb.Push(ResultSuccess);
143 // We don't deal with hardware initialization so we can just stub this.
144 }
145
146 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
147 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
148
149 IPC::ResponseBuilder rb{ctx, 3};
150 rb.Push(ResultSuccess);
151 rb.PushRaw<u8>(true);
152 }
153
154 void GetStateOld(Kernel::HLERequestContext& ctx) {
155 LOG_WARNING(Service_NFC, "(STUBBED) called");
156
157 IPC::ResponseBuilder rb{ctx, 3};
158 rb.Push(ResultSuccess);
159 rb.PushEnum(NfcStates::Finalized); // TODO(ogniK): Figure out if this matches nfp
160 }
161
162 void FinalizeOld(Kernel::HLERequestContext& ctx) {
163 LOG_WARNING(Service_NFC, "(STUBBED) called");
164
165 IPC::ResponseBuilder rb{ctx, 2};
166 rb.Push(ResultSuccess);
167 }
168};
169
170class NFC_U final : public ServiceFramework<NFC_U> { 101class NFC_U final : public ServiceFramework<NFC_U> {
171public: 102public:
172 explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} { 103 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/input.h"
5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/hid/emulated_controller.h"
8#include "core/hid/hid_core.h"
9#include "core/hid/hid_types.h"
10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/service/nfc/nfc_device.h"
13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/nfc/nfc_user.h"
15
16namespace Service::NFC {
17NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
18 KernelHelpers::ServiceContext& service_context_,
19 Kernel::KEvent* availability_change_event_)
20 : npad_id{npad_id_}, system{system_}, service_context{service_context_},
21 availability_change_event{availability_change_event_} {
22 activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
23 deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
24 npad_device = system.HIDCore().GetEmulatedController(npad_id);
25
26 Core::HID::ControllerUpdateCallback engine_callback{
27 .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
28 .is_npad_service = false,
29 };
30 is_controller_set = true;
31 callback_key = npad_device->SetCallback(engine_callback);
32}
33
34NfcDevice::~NfcDevice() {
35 activate_event->Close();
36 deactivate_event->Close();
37 if (!is_controller_set) {
38 return;
39 }
40 npad_device->DeleteCallback(callback_key);
41 is_controller_set = false;
42};
43
44void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
45 if (type == Core::HID::ControllerTriggerType::Connected ||
46 type == Core::HID::ControllerTriggerType::Disconnected) {
47 availability_change_event->Signal();
48 return;
49 }
50
51 if (type != Core::HID::ControllerTriggerType::Nfc) {
52 return;
53 }
54
55 if (!npad_device->IsConnected()) {
56 return;
57 }
58
59 const auto nfc_status = npad_device->GetNfc();
60 switch (nfc_status.state) {
61 case Common::Input::NfcState::NewAmiibo:
62 LoadNfcTag(nfc_status.data);
63 break;
64 case Common::Input::NfcState::AmiiboRemoved:
65 if (device_state != NFP::DeviceState::SearchingForTag) {
66 CloseNfcTag();
67 }
68 break;
69 default:
70 break;
71 }
72}
73
74bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
75 if (device_state != NFP::DeviceState::SearchingForTag) {
76 LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
77 return false;
78 }
79
80 if (data.size() != sizeof(NFP::EncryptedNTAG215File)) {
81 LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
82 return false;
83 }
84
85 memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
86
87 device_state = NFP::DeviceState::TagFound;
88 deactivate_event->GetReadableEvent().Clear();
89 activate_event->Signal();
90 return true;
91}
92
93void NfcDevice::CloseNfcTag() {
94 LOG_INFO(Service_NFC, "Remove nfc tag");
95
96 device_state = NFP::DeviceState::TagRemoved;
97 encrypted_tag_data = {};
98 activate_event->GetReadableEvent().Clear();
99 deactivate_event->Signal();
100}
101
102Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
103 return activate_event->GetReadableEvent();
104}
105
106Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
107 return deactivate_event->GetReadableEvent();
108}
109
110void NfcDevice::Initialize() {
111 device_state =
112 npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
113 encrypted_tag_data = {};
114}
115
116void NfcDevice::Finalize() {
117 if (device_state == NFP::DeviceState::SearchingForTag ||
118 device_state == NFP::DeviceState::TagRemoved) {
119 StopDetection();
120 }
121 device_state = NFP::DeviceState::Unavailable;
122}
123
124Result NfcDevice::StartDetection(s32 protocol_) {
125 if (device_state != NFP::DeviceState::Initialized &&
126 device_state != NFP::DeviceState::TagRemoved) {
127 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
128 return WrongDeviceState;
129 }
130
131 if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) {
132 LOG_ERROR(Service_NFC, "Nfc not supported");
133 return NfcDisabled;
134 }
135
136 device_state = NFP::DeviceState::SearchingForTag;
137 protocol = protocol_;
138 return ResultSuccess;
139}
140
141Result NfcDevice::StopDetection() {
142 npad_device->SetPollingMode(Common::Input::PollingMode::Active);
143
144 if (device_state == NFP::DeviceState::Initialized) {
145 return ResultSuccess;
146 }
147
148 if (device_state == NFP::DeviceState::TagFound ||
149 device_state == NFP::DeviceState::TagMounted) {
150 CloseNfcTag();
151 return ResultSuccess;
152 }
153 if (device_state == NFP::DeviceState::SearchingForTag ||
154 device_state == NFP::DeviceState::TagRemoved) {
155 device_state = NFP::DeviceState::Initialized;
156 return ResultSuccess;
157 }
158
159 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
160 return WrongDeviceState;
161}
162
163Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
164 if (device_state != NFP::DeviceState::TagFound &&
165 device_state != NFP::DeviceState::TagMounted) {
166 LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
167 if (device_state == NFP::DeviceState::TagRemoved) {
168 return TagRemoved;
169 }
170 return WrongDeviceState;
171 }
172
173 // Protocol and tag type may change here
174 tag_info = {
175 .uuid = encrypted_tag_data.uuid.uid,
176 .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
177 .protocol = NFP::TagProtocol::TypeA,
178 .tag_type = NFP::TagType::Type2,
179 };
180
181 return ResultSuccess;
182}
183
184u64 NfcDevice::GetHandle() const {
185 // Generate a handle based of the npad id
186 return static_cast<u64>(npad_id);
187}
188
189NFP::DeviceState NfcDevice::GetCurrentState() const {
190 return device_state;
191}
192
193Core::HID::NpadIdType NfcDevice::GetNpadId() const {
194 return npad_id;
195}
196
197} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/nfp/nfp_types.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KEvent;
13class KReadableEvent;
14} // namespace Kernel
15
16namespace Core {
17class System;
18} // namespace Core
19
20namespace Core::HID {
21class EmulatedController;
22enum class ControllerTriggerType;
23enum class NpadIdType : u32;
24} // namespace Core::HID
25
26namespace Service::NFC {
27class NfcDevice {
28public:
29 NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
30 KernelHelpers::ServiceContext& service_context_,
31 Kernel::KEvent* availability_change_event_);
32 ~NfcDevice();
33
34 void Initialize();
35 void Finalize();
36
37 Result StartDetection(s32 protocol_);
38 Result StopDetection();
39
40 Result GetTagInfo(NFP::TagInfo& tag_info) const;
41
42 u64 GetHandle() const;
43 NFP::DeviceState GetCurrentState() const;
44 Core::HID::NpadIdType GetNpadId() const;
45
46 Kernel::KReadableEvent& GetActivateEvent() const;
47 Kernel::KReadableEvent& GetDeactivateEvent() const;
48
49private:
50 void NpadUpdate(Core::HID::ControllerTriggerType type);
51 bool LoadNfcTag(std::span<const u8> data);
52 void CloseNfcTag();
53
54 bool is_controller_set{};
55 int callback_key;
56 const Core::HID::NpadIdType npad_id;
57 Core::System& system;
58 Core::HID::EmulatedController* npad_device = nullptr;
59 KernelHelpers::ServiceContext& service_context;
60 Kernel::KEvent* activate_event = nullptr;
61 Kernel::KEvent* deactivate_event = nullptr;
62 Kernel::KEvent* availability_change_event = nullptr;
63
64 s32 protocol{};
65 NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
66
67 NFP::EncryptedNTAG215File encrypted_tag_data{};
68};
69
70} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::NFC {
9
10constexpr Result DeviceNotFound(ErrorModule::NFC, 64);
11constexpr Result InvalidArgument(ErrorModule::NFC, 65);
12constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
13constexpr Result NfcDisabled(ErrorModule::NFC, 80);
14constexpr Result TagRemoved(ErrorModule::NFC, 97);
15constexpr Result CorruptedData(ErrorModule::NFC, 144);
16
17} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hid/hid_types.h"
7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/nfc/nfc_device.h"
10#include "core/hle/service/nfc/nfc_result.h"
11#include "core/hle/service/nfc/nfc_user.h"
12#include "core/hle/service/time/clock_types.h"
13
14namespace Service::NFC {
15
16IUser::IUser(Core::System& system_)
17 : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
18 static const FunctionInfo functions[] = {
19 {0, &IUser::Initialize, "InitializeOld"},
20 {1, &IUser::Finalize, "FinalizeOld"},
21 {2, &IUser::GetState, "GetStateOld"},
22 {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
23 {400, &IUser::Initialize, "Initialize"},
24 {401, &IUser::Finalize, "Finalize"},
25 {402, &IUser::GetState, "GetState"},
26 {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
27 {404, &IUser::ListDevices, "ListDevices"},
28 {405, &IUser::GetDeviceState, "GetDeviceState"},
29 {406, &IUser::GetNpadId, "GetNpadId"},
30 {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
31 {408, &IUser::StartDetection, "StartDetection"},
32 {409, &IUser::StopDetection, "StopDetection"},
33 {410, &IUser::GetTagInfo, "GetTagInfo"},
34 {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
35 {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
36 {1000, nullptr, "ReadMifare"},
37 {1001, nullptr, "WriteMifare"},
38 {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
39 {1301, nullptr, "KeepPassThroughSession"},
40 {1302, nullptr, "ReleasePassThroughSession"},
41 };
42 RegisterHandlers(functions);
43
44 availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
45
46 for (u32 device_index = 0; device_index < 10; device_index++) {
47 devices[device_index] =
48 std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
49 service_context, availability_change_event);
50 }
51}
52
53IUser ::~IUser() {
54 availability_change_event->Close();
55}
56
57void IUser::Initialize(Kernel::HLERequestContext& ctx) {
58 LOG_INFO(Service_NFC, "called");
59
60 state = State::Initialized;
61
62 for (auto& device : devices) {
63 device->Initialize();
64 }
65
66 IPC::ResponseBuilder rb{ctx, 2, 0};
67 rb.Push(ResultSuccess);
68}
69
70void IUser::Finalize(Kernel::HLERequestContext& ctx) {
71 LOG_INFO(Service_NFC, "called");
72
73 state = State::NonInitialized;
74
75 for (auto& device : devices) {
76 device->Finalize();
77 }
78
79 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(ResultSuccess);
81}
82
83void IUser::GetState(Kernel::HLERequestContext& ctx) {
84 LOG_DEBUG(Service_NFC, "called");
85
86 IPC::ResponseBuilder rb{ctx, 3};
87 rb.Push(ResultSuccess);
88 rb.PushEnum(state);
89}
90
91void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) {
92 LOG_DEBUG(Service_NFC, "called");
93
94 IPC::ResponseBuilder rb{ctx, 3};
95 rb.Push(ResultSuccess);
96 rb.Push(state != State::NonInitialized);
97}
98
99void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
100 LOG_INFO(Service_NFC, "called");
101
102 if (state == State::NonInitialized) {
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(NfcDisabled);
105 return;
106 }
107
108 if (!ctx.CanWriteBuffer()) {
109 IPC::ResponseBuilder rb{ctx, 2};
110 rb.Push(InvalidArgument);
111 return;
112 }
113
114 if (ctx.GetWriteBufferSize() == 0) {
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(InvalidArgument);
117 return;
118 }
119
120 std::vector<u64> nfp_devices;
121 const std::size_t max_allowed_devices = ctx.GetWriteBufferSize() / sizeof(u64);
122
123 for (auto& device : devices) {
124 if (nfp_devices.size() >= max_allowed_devices) {
125 continue;
126 }
127 if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
128 nfp_devices.push_back(device->GetHandle());
129 }
130 }
131
132 if (nfp_devices.empty()) {
133 IPC::ResponseBuilder rb{ctx, 2};
134 rb.Push(DeviceNotFound);
135 return;
136 }
137
138 ctx.WriteBuffer(nfp_devices);
139
140 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(ResultSuccess);
142 rb.Push(static_cast<s32>(nfp_devices.size()));
143}
144
145void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
146 IPC::RequestParser rp{ctx};
147 const auto device_handle{rp.Pop<u64>()};
148 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
149
150 auto device = GetNfcDevice(device_handle);
151
152 if (!device.has_value()) {
153 IPC::ResponseBuilder rb{ctx, 2};
154 rb.Push(DeviceNotFound);
155 return;
156 }
157
158 IPC::ResponseBuilder rb{ctx, 3};
159 rb.Push(ResultSuccess);
160 rb.PushEnum(device.value()->GetCurrentState());
161}
162
163void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
164 IPC::RequestParser rp{ctx};
165 const auto device_handle{rp.Pop<u64>()};
166 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
167
168 if (state == State::NonInitialized) {
169 IPC::ResponseBuilder rb{ctx, 2};
170 rb.Push(NfcDisabled);
171 return;
172 }
173
174 auto device = GetNfcDevice(device_handle);
175
176 if (!device.has_value()) {
177 IPC::ResponseBuilder rb{ctx, 2};
178 rb.Push(DeviceNotFound);
179 return;
180 }
181
182 IPC::ResponseBuilder rb{ctx, 3};
183 rb.Push(ResultSuccess);
184 rb.PushEnum(device.value()->GetNpadId());
185}
186
187void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
188 LOG_INFO(Service_NFC, "called");
189
190 if (state == State::NonInitialized) {
191 IPC::ResponseBuilder rb{ctx, 2};
192 rb.Push(NfcDisabled);
193 return;
194 }
195
196 IPC::ResponseBuilder rb{ctx, 2, 1};
197 rb.Push(ResultSuccess);
198 rb.PushCopyObjects(availability_change_event->GetReadableEvent());
199}
200
201void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
202 IPC::RequestParser rp{ctx};
203 const auto device_handle{rp.Pop<u64>()};
204 const auto nfp_protocol{rp.Pop<s32>()};
205 LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
206
207 if (state == State::NonInitialized) {
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(NfcDisabled);
210 return;
211 }
212
213 auto device = GetNfcDevice(device_handle);
214
215 if (!device.has_value()) {
216 IPC::ResponseBuilder rb{ctx, 2};
217 rb.Push(DeviceNotFound);
218 return;
219 }
220
221 const auto result = device.value()->StartDetection(nfp_protocol);
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(result);
224}
225
226void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
227 IPC::RequestParser rp{ctx};
228 const auto device_handle{rp.Pop<u64>()};
229 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
230
231 if (state == State::NonInitialized) {
232 IPC::ResponseBuilder rb{ctx, 2};
233 rb.Push(NfcDisabled);
234 return;
235 }
236
237 auto device = GetNfcDevice(device_handle);
238
239 if (!device.has_value()) {
240 IPC::ResponseBuilder rb{ctx, 2};
241 rb.Push(DeviceNotFound);
242 return;
243 }
244
245 const auto result = device.value()->StopDetection();
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(result);
248}
249
250void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
251 IPC::RequestParser rp{ctx};
252 const auto device_handle{rp.Pop<u64>()};
253 LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
254
255 if (state == State::NonInitialized) {
256 IPC::ResponseBuilder rb{ctx, 2};
257 rb.Push(NfcDisabled);
258 return;
259 }
260
261 auto device = GetNfcDevice(device_handle);
262
263 if (!device.has_value()) {
264 IPC::ResponseBuilder rb{ctx, 2};
265 rb.Push(DeviceNotFound);
266 return;
267 }
268
269 NFP::TagInfo tag_info{};
270 const auto result = device.value()->GetTagInfo(tag_info);
271 ctx.WriteBuffer(tag_info);
272 IPC::ResponseBuilder rb{ctx, 2};
273 rb.Push(result);
274}
275
276void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
277 IPC::RequestParser rp{ctx};
278 const auto device_handle{rp.Pop<u64>()};
279 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
280
281 if (state == State::NonInitialized) {
282 IPC::ResponseBuilder rb{ctx, 2};
283 rb.Push(NfcDisabled);
284 return;
285 }
286
287 auto device = GetNfcDevice(device_handle);
288
289 if (!device.has_value()) {
290 IPC::ResponseBuilder rb{ctx, 2};
291 rb.Push(DeviceNotFound);
292 return;
293 }
294
295 IPC::ResponseBuilder rb{ctx, 2, 1};
296 rb.Push(ResultSuccess);
297 rb.PushCopyObjects(device.value()->GetActivateEvent());
298}
299
300void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
301 IPC::RequestParser rp{ctx};
302 const auto device_handle{rp.Pop<u64>()};
303 LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
304
305 if (state == State::NonInitialized) {
306 IPC::ResponseBuilder rb{ctx, 2};
307 rb.Push(NfcDisabled);
308 return;
309 }
310
311 auto device = GetNfcDevice(device_handle);
312
313 if (!device.has_value()) {
314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(DeviceNotFound);
316 return;
317 }
318
319 IPC::ResponseBuilder rb{ctx, 2, 1};
320 rb.Push(ResultSuccess);
321 rb.PushCopyObjects(device.value()->GetDeactivateEvent());
322}
323
324void IUser::SendCommandByPassThrough(Kernel::HLERequestContext& ctx) {
325 IPC::RequestParser rp{ctx};
326 const auto device_handle{rp.Pop<u64>()};
327 const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
328 const auto command_data{ctx.ReadBuffer()};
329
330 LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
331 device_handle, timeout.ToSeconds(), command_data.size());
332
333 if (state == State::NonInitialized) {
334 IPC::ResponseBuilder rb{ctx, 2};
335 rb.Push(NfcDisabled);
336 return;
337 }
338
339 auto device = GetNfcDevice(device_handle);
340
341 if (!device.has_value()) {
342 IPC::ResponseBuilder rb{ctx, 2};
343 rb.Push(DeviceNotFound);
344 return;
345 }
346
347 std::vector<u8> out_data(1);
348 // TODO: Request data from nfc device
349 ctx.WriteBuffer(out_data);
350
351 IPC::ResponseBuilder rb{ctx, 3};
352 rb.Push(ResultSuccess);
353 rb.Push(static_cast<u32>(out_data.size()));
354}
355
356std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
357 for (auto& device : devices) {
358 if (device->GetHandle() == handle) {
359 return device;
360 }
361 }
362 return std::nullopt;
363}
364
365} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <optional>
9
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h"
12
13namespace Service::NFC {
14class NfcDevice;
15
16class IUser final : public ServiceFramework<IUser> {
17public:
18 explicit IUser(Core::System& system_);
19 ~IUser();
20
21private:
22 enum class State : u32 {
23 NonInitialized,
24 Initialized,
25 };
26
27 void Initialize(Kernel::HLERequestContext& ctx);
28 void Finalize(Kernel::HLERequestContext& ctx);
29 void GetState(Kernel::HLERequestContext& ctx);
30 void IsNfcEnabled(Kernel::HLERequestContext& ctx);
31 void ListDevices(Kernel::HLERequestContext& ctx);
32 void GetDeviceState(Kernel::HLERequestContext& ctx);
33 void GetNpadId(Kernel::HLERequestContext& ctx);
34 void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
35 void StartDetection(Kernel::HLERequestContext& ctx);
36 void StopDetection(Kernel::HLERequestContext& ctx);
37 void GetTagInfo(Kernel::HLERequestContext& ctx);
38 void AttachActivateEvent(Kernel::HLERequestContext& ctx);
39 void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
40 void SendCommandByPassThrough(Kernel::HLERequestContext& ctx);
41
42 std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
43
44 KernelHelpers::ServiceContext service_context;
45
46 std::array<std::shared_ptr<NfcDevice>, 10> devices{};
47
48 State state{State::NonInitialized};
49 Kernel::KEvent* availability_change_event;
50};
51
52} // 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 @@
12#include "common/fs/fs.h" 12#include "common/fs/fs.h"
13#include "common/fs/path_util.h" 13#include "common/fs/path_util.h"
14#include "common/logging/log.h" 14#include "common/logging/log.h"
15#include "core/hle/service/mii/mii_manager.h"
16#include "core/hle/service/nfp/amiibo_crypto.h" 15#include "core/hle/service/nfp/amiibo_crypto.h"
17 16
18namespace Service::NFP::AmiiboCrypto { 17namespace 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 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <array> 4#include <array>
5#include <atomic>
6 5
7#include "common/fs/file.h"
8#include "common/fs/path_util.h"
9#include "common/input.h" 6#include "common/input.h"
10#include "common/logging/log.h" 7#include "common/logging/log.h"
11#include "common/string_util.h" 8#include "common/string_util.h"
@@ -19,7 +16,6 @@
19#include "core/hle/service/mii/mii_manager.h" 16#include "core/hle/service/mii/mii_manager.h"
20#include "core/hle/service/mii/types.h" 17#include "core/hle/service/mii/types.h"
21#include "core/hle/service/nfp/amiibo_crypto.h" 18#include "core/hle/service/nfp/amiibo_crypto.h"
22#include "core/hle/service/nfp/nfp.h"
23#include "core/hle/service/nfp/nfp_device.h" 19#include "core/hle/service/nfp/nfp_device.h"
24#include "core/hle/service/nfp/nfp_result.h" 20#include "core/hle/service/nfp/nfp_result.h"
25#include "core/hle/service/nfp/nfp_user.h" 21#include "core/hle/service/nfp/nfp_user.h"
@@ -49,6 +45,8 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
49} 45}
50 46
51NfpDevice::~NfpDevice() { 47NfpDevice::~NfpDevice() {
48 activate_event->Close();
49 deactivate_event->Close();
52 if (!is_controller_set) { 50 if (!is_controller_set) {
53 return; 51 return;
54 } 52 }
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 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <array>
7#include <span> 6#include <span>
8#include <vector> 7#include <vector>
9 8
10#include "common/common_funcs.h" 9#include "common/common_types.h"
11#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
12#include "core/hle/service/nfp/nfp_types.h" 11#include "core/hle/service/nfp/nfp_types.h"
13#include "core/hle/service/service.h" 12#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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <array>
5#include <atomic>
6
7#include "common/logging/log.h" 4#include "common/logging/log.h"
8#include "core/core.h" 5#include "core/core.h"
9#include "core/hid/hid_types.h" 6#include "core/hid/hid_types.h"
@@ -55,8 +52,12 @@ IUser::IUser(Core::System& system_)
55 } 52 }
56} 53}
57 54
55IUser ::~IUser() {
56 availability_change_event->Close();
57}
58
58void IUser::Initialize(Kernel::HLERequestContext& ctx) { 59void IUser::Initialize(Kernel::HLERequestContext& ctx) {
59 LOG_INFO(Service_NFC, "called"); 60 LOG_INFO(Service_NFP, "called");
60 61
61 state = State::Initialized; 62 state = State::Initialized;
62 63
@@ -64,7 +65,7 @@ void IUser::Initialize(Kernel::HLERequestContext& ctx) {
64 device->Initialize(); 65 device->Initialize();
65 } 66 }
66 67
67 IPC::ResponseBuilder rb{ctx, 2, 0}; 68 IPC::ResponseBuilder rb{ctx, 2};
68 rb.Push(ResultSuccess); 69 rb.Push(ResultSuccess);
69} 70}
70 71
@@ -551,9 +552,9 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
551} 552}
552 553
553void IUser::GetState(Kernel::HLERequestContext& ctx) { 554void IUser::GetState(Kernel::HLERequestContext& ctx) {
554 LOG_DEBUG(Service_NFC, "called"); 555 LOG_DEBUG(Service_NFP, "called");
555 556
556 IPC::ResponseBuilder rb{ctx, 3, 0}; 557 IPC::ResponseBuilder rb{ctx, 3};
557 rb.Push(ResultSuccess); 558 rb.Push(ResultSuccess);
558 rb.PushEnum(state); 559 rb.PushEnum(state);
559} 560}
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 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <array>
7#include <memory>
8#include <optional>
9
6#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
8 12
@@ -12,6 +16,7 @@ class NfpDevice;
12class IUser final : public ServiceFramework<IUser> { 16class IUser final : public ServiceFramework<IUser> {
13public: 17public:
14 explicit IUser(Core::System& system_); 18 explicit IUser(Core::System& system_);
19 ~IUser();
15 20
16private: 21private:
17 enum class State : u32 { 22 enum class State : u32 {