From a3fa64fcc489d2cc1776807a37db3464dcc32686 Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Fri, 14 Apr 2023 17:46:20 -0600
Subject: [PATCH 1/4] service: nfc: Create interface

---
 src/core/hle/service/nfc/nfc.cpp              | 110 ++++++++++++------
 src/core/hle/service/nfc/nfc_device.cpp       |   1 -
 .../nfc/{nfc_user.cpp => nfc_interface.cpp}   |  66 ++++-------
 .../nfc/{nfc_user.h => nfc_interface.h}       |  18 +--
 src/core/hle/service/nfp/nfp.cpp              |  24 +---
 5 files changed, 104 insertions(+), 115 deletions(-)
 rename src/core/hle/service/nfc/{nfc_user.cpp => nfc_interface.cpp} (77%)
 rename src/core/hle/service/nfc/{nfc_user.h => nfc_interface.h} (91%)

diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 6595e34ed..7a8f59725 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -8,12 +8,83 @@
 #include "core/hle/service/ipc_helpers.h"
 #include "core/hle/service/nfc/mifare_user.h"
 #include "core/hle/service/nfc/nfc.h"
-#include "core/hle/service/nfc/nfc_user.h"
+#include "core/hle/service/nfc/nfc_interface.h"
 #include "core/hle/service/server_manager.h"
 #include "core/hle/service/service.h"
 
 namespace Service::NFC {
 
+class IUser final : public Interface {
+public:
+    explicit IUser(Core::System& system_) : Interface(system_, "IUser") {
+        // clang-format off
+        static const FunctionInfo functions[] = {
+            {0, &Interface::Initialize, "InitializeOld"},
+            {1, &Interface::Finalize, "FinalizeOld"},
+            {2, &Interface::GetState, "GetStateOld"},
+            {3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"},
+            {400, &Interface::Initialize, "Initialize"},
+            {401, &Interface::Finalize, "Finalize"},
+            {402, &Interface::GetState, "GetState"},
+            {403, &Interface::IsNfcEnabled, "IsNfcEnabled"},
+            {404, &Interface::ListDevices, "ListDevices"},
+            {405, &Interface::GetDeviceState, "GetDeviceState"},
+            {406, &Interface::GetNpadId, "GetNpadId"},
+            {407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+            {408, &Interface::StartDetection, "StartDetection"},
+            {409, &Interface::StopDetection, "StopDetection"},
+            {410, &Interface::GetTagInfo, "GetTagInfo"},
+            {411, &Interface::AttachActivateEvent, "AttachActivateEvent"},
+            {412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+            {1000, nullptr, "ReadMifare"},
+            {1001, nullptr, "WriteMifare"},
+            {1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+            {1301, nullptr, "KeepPassThroughSession"},
+            {1302, nullptr, "ReleasePassThroughSession"},
+        };
+        // clang-format on
+
+        RegisterHandlers(functions);
+    }
+};
+
+class ISystem final : public Interface {
+public:
+    explicit ISystem(Core::System& system_) : Interface{system_, "ISystem"} {
+        // clang-format off
+        static const FunctionInfo functions[] = {
+            {0, &Interface::Initialize, "InitializeOld"},
+            {1, &Interface::Finalize, "FinalizeOld"},
+            {2, &Interface::GetState, "GetStateOld"},
+            {3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"},
+            {100, nullptr, "SetNfcEnabledOld"},
+            {400, &Interface::Initialize, "Initialize"},
+            {401, &Interface::Finalize, "Finalize"},
+            {402, &Interface::GetState, "GetState"},
+            {403, &Interface::IsNfcEnabled, "IsNfcEnabled"},
+            {404, &Interface::ListDevices, "ListDevices"},
+            {405, &Interface::GetDeviceState, "GetDeviceState"},
+            {406, &Interface::GetNpadId, "GetNpadId"},
+            {407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+            {408, &Interface::StartDetection, "StartDetection"},
+            {409, &Interface::StopDetection, "StopDetection"},
+            {410, &Interface::GetTagInfo, "GetTagInfo"},
+            {411, &Interface::AttachActivateEvent, "AttachActivateEvent"},
+            {412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+            {500, nullptr, "SetNfcEnabled"},
+            {510, nullptr, "OutputTestWave"},
+            {1000, nullptr, "ReadMifare"},
+            {1001, nullptr, "WriteMifare"},
+            {1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+            {1301, nullptr, "KeepPassThroughSession"},
+            {1302, nullptr, "ReleasePassThroughSession"},
+        };
+        // clang-format on
+
+        RegisterHandlers(functions);
+    }
+};
+
 class IAm final : public ServiceFramework<IAm> {
 public:
     explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
@@ -95,43 +166,6 @@ private:
     }
 };
 
-class ISystem final : public ServiceFramework<ISystem> {
-public:
-    explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
-        // clang-format off
-        static const FunctionInfo functions[] = {
-            {0, nullptr, "Initialize"},
-            {1, nullptr, "Finalize"},
-            {2, nullptr, "GetStateOld"},
-            {3, nullptr, "IsNfcEnabledOld"},
-            {100, nullptr, "SetNfcEnabledOld"},
-            {400, nullptr, "InitializeSystem"},
-            {401, nullptr, "FinalizeSystem"},
-            {402, nullptr, "GetState"},
-            {403, nullptr, "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"},
-            {500, nullptr, "SetNfcEnabled"},
-            {510, nullptr, "OutputTestWave"},
-            {1000, nullptr, "ReadMifare"},
-            {1001, nullptr, "WriteMifare"},
-            {1300, nullptr, "SendCommandByPassThrough"},
-            {1301, nullptr, "KeepPassThroughSession"},
-            {1302, nullptr, "ReleasePassThroughSession"},
-        };
-        // clang-format on
-
-        RegisterHandlers(functions);
-    }
-};
-
 class NFC_SYS final : public ServiceFramework<NFC_SYS> {
 public:
     explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
index c7db74d14..47bc1a05d 100644
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ b/src/core/hle/service/nfc/nfc_device.cpp
@@ -11,7 +11,6 @@
 #include "core/hle/service/ipc_helpers.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_,
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
similarity index 77%
rename from src/core/hle/service/nfc/nfc_user.cpp
rename to src/core/hle/service/nfc/nfc_interface.cpp
index 7c162a4f3..be96d0cbc 100644
--- a/src/core/hle/service/nfc/nfc_user.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -7,41 +7,15 @@
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/service/ipc_helpers.h"
 #include "core/hle/service/nfc/nfc_device.h"
+#include "core/hle/service/nfc/nfc_interface.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");
+Interface::Interface(Core::System& system_, const char* name)
+    : ServiceFramework{system_, name}, service_context{system_, service_name} {
+    availability_change_event = service_context.CreateEvent("Interface:AvailabilityChangeEvent");
 
     for (u32 device_index = 0; device_index < 10; device_index++) {
         devices[device_index] =
@@ -50,11 +24,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_NFC, "called");
 
     state = State::Initialized;
@@ -67,7 +41,7 @@ void IUser::Initialize(HLERequestContext& ctx) {
     rb.Push(ResultSuccess);
 }
 
-void IUser::Finalize(HLERequestContext& ctx) {
+void Interface::Finalize(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
     state = State::NonInitialized;
@@ -80,7 +54,7 @@ void IUser::Finalize(HLERequestContext& ctx) {
     rb.Push(ResultSuccess);
 }
 
-void IUser::GetState(HLERequestContext& ctx) {
+void Interface::GetState(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     IPC::ResponseBuilder rb{ctx, 3};
@@ -88,7 +62,7 @@ void IUser::GetState(HLERequestContext& ctx) {
     rb.PushEnum(state);
 }
 
-void IUser::IsNfcEnabled(HLERequestContext& ctx) {
+void Interface::IsNfcEnabled(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     IPC::ResponseBuilder rb{ctx, 3};
@@ -96,7 +70,7 @@ void IUser::IsNfcEnabled(HLERequestContext& ctx) {
     rb.Push(state != State::NonInitialized);
 }
 
-void IUser::ListDevices(HLERequestContext& ctx) {
+void Interface::ListDevices(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     if (state == State::NonInitialized) {
@@ -142,7 +116,7 @@ void IUser::ListDevices(HLERequestContext& ctx) {
     rb.Push(static_cast<s32>(nfp_devices.size()));
 }
 
-void IUser::GetDeviceState(HLERequestContext& ctx) {
+void Interface::GetDeviceState(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
@@ -160,7 +134,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_NFC, "called, device_handle={}", device_handle);
@@ -184,7 +158,7 @@ void IUser::GetNpadId(HLERequestContext& ctx) {
     rb.PushEnum(device.value()->GetNpadId());
 }
 
-void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
+void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
     if (state == State::NonInitialized) {
@@ -198,7 +172,7 @@ void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
     rb.PushCopyObjects(availability_change_event->GetReadableEvent());
 }
 
-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<NFP::TagProtocol>()};
@@ -223,7 +197,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_NFC, "called, device_handle={}", device_handle);
@@ -247,7 +221,7 @@ void IUser::StopDetection(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_NFC, "called, device_handle={}", device_handle);
@@ -273,7 +247,7 @@ void IUser::GetTagInfo(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_NFC, "called, device_handle={}", device_handle);
@@ -297,7 +271,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_NFC, "called, device_handle={}", device_handle);
@@ -321,7 +295,7 @@ void IUser::AttachDeactivateEvent(HLERequestContext& ctx) {
     rb.PushCopyObjects(device.value()->GetDeactivateEvent());
 }
 
-void IUser::SendCommandByPassThrough(HLERequestContext& ctx) {
+void Interface::SendCommandByPassThrough(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
@@ -353,7 +327,7 @@ void IUser::SendCommandByPassThrough(HLERequestContext& ctx) {
     rb.Push(static_cast<u32>(out_data.size()));
 }
 
-std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
+std::optional<std::shared_ptr<NfcDevice>> Interface::GetNfcDevice(u64 handle) {
     for (auto& device : devices) {
         if (device->GetHandle() == handle) {
             return device;
diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_interface.h
similarity index 91%
rename from src/core/hle/service/nfc/nfc_user.h
rename to src/core/hle/service/nfc/nfc_interface.h
index aee046ae8..8c1bf5a59 100644
--- a/src/core/hle/service/nfc/nfc_user.h
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -13,16 +13,10 @@
 namespace Service::NFC {
 class NfcDevice;
 
-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();
 
     void Initialize(HLERequestContext& ctx);
     void Finalize(HLERequestContext& ctx);
@@ -39,6 +33,12 @@ private:
     void AttachDeactivateEvent(HLERequestContext& ctx);
     void SendCommandByPassThrough(HLERequestContext& ctx);
 
+private:
+    enum class State : u32 {
+        NonInitialized,
+        Initialized,
+    };
+
     std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
 
     KernelHelpers::ServiceContext service_context;
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2714f4bea..2559fe598 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -152,16 +152,10 @@ private:
     void CreateUserInterface(HLERequestContext& ctx) {
         LOG_DEBUG(Service_NFP, "called");
 
-        if (user_interface == nullptr) {
-            user_interface = std::make_shared<IUser>(system);
-        }
-
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
         rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IUser>(user_interface);
+        rb.PushIpcInterface<IUser>(system);
     }
-
-    std::shared_ptr<IUser> user_interface;
 };
 
 class ISystemManager final : public ServiceFramework<ISystemManager> {
@@ -180,16 +174,10 @@ 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);
+        rb.PushIpcInterface<ISystem>(system);
     }
-
-    std::shared_ptr<ISystem> system_interface;
 };
 
 class IDebugManager final : public ServiceFramework<IDebugManager> {
@@ -208,16 +196,10 @@ 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);
+        rb.PushIpcInterface<IDebug>(system);
     }
-
-    std::shared_ptr<IDebug> system_interface;
 };
 
 void LoopProcess(Core::System& system) {

From 00d76fc5f5276b74f4c14edda579981831808d35 Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Fri, 14 Apr 2023 17:55:13 -0600
Subject: [PATCH 2/4] service: nfc: Create mifare interface

---
 .../{mifare_user.cpp => mifare_interface.cpp} | 58 +++++++------------
 .../nfc/{mifare_user.h => mifare_interface.h} | 18 +++---
 src/core/hle/service/nfc/nfc.cpp              | 32 +++++++++-
 3 files changed, 58 insertions(+), 50 deletions(-)
 rename src/core/hle/service/nfc/{mifare_user.cpp => mifare_interface.cpp} (83%)
 rename src/core/hle/service/nfc/{mifare_user.h => mifare_interface.h} (90%)

diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_interface.cpp
similarity index 83%
rename from src/core/hle/service/nfc/mifare_user.cpp
rename to src/core/hle/service/nfc/mifare_interface.cpp
index e0bbd46e1..7e6635ba2 100644
--- a/src/core/hle/service/nfc/mifare_user.cpp
+++ b/src/core/hle/service/nfc/mifare_interface.cpp
@@ -6,33 +6,15 @@
 #include "core/hid/hid_types.h"
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/mifare_user.h"
+#include "core/hle/service/nfc/mifare_interface.h"
 #include "core/hle/service/nfc/nfc_device.h"
 #include "core/hle/service/nfc/nfc_result.h"
 
 namespace Service::NFC {
 
-MFIUser::MFIUser(Core::System& system_)
-    : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} {
-    static const FunctionInfo functions[] = {
-        {0, &MFIUser::Initialize, "Initialize"},
-        {1, &MFIUser::Finalize, "Finalize"},
-        {2, &MFIUser::ListDevices, "ListDevices"},
-        {3, &MFIUser::StartDetection, "StartDetection"},
-        {4, &MFIUser::StopDetection, "StopDetection"},
-        {5, &MFIUser::Read, "Read"},
-        {6, &MFIUser::Write, "Write"},
-        {7, &MFIUser::GetTagInfo, "GetTagInfo"},
-        {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
-        {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
-        {10, &MFIUser::GetState, "GetState"},
-        {11, &MFIUser::GetDeviceState, "GetDeviceState"},
-        {12, &MFIUser::GetNpadId, "GetNpadId"},
-        {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
-    };
-    RegisterHandlers(functions);
-
-    availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent");
+MFInterface::MFInterface(Core::System& system_, const char* name)
+    : ServiceFramework{system_, name}, service_context{system_, service_name} {
+    availability_change_event = service_context.CreateEvent("MFInterface:AvailabilityChangeEvent");
 
     for (u32 device_index = 0; device_index < 10; device_index++) {
         devices[device_index] =
@@ -41,11 +23,11 @@ MFIUser::MFIUser(Core::System& system_)
     }
 }
 
-MFIUser ::~MFIUser() {
+MFInterface ::~MFInterface() {
     availability_change_event->Close();
 }
 
-void MFIUser::Initialize(HLERequestContext& ctx) {
+void MFInterface::Initialize(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
     state = State::Initialized;
@@ -58,7 +40,7 @@ void MFIUser::Initialize(HLERequestContext& ctx) {
     rb.Push(ResultSuccess);
 }
 
-void MFIUser::Finalize(HLERequestContext& ctx) {
+void MFInterface::Finalize(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
     state = State::NonInitialized;
@@ -71,7 +53,7 @@ void MFIUser::Finalize(HLERequestContext& ctx) {
     rb.Push(ResultSuccess);
 }
 
-void MFIUser::ListDevices(HLERequestContext& ctx) {
+void MFInterface::ListDevices(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     if (state == State::NonInitialized) {
@@ -117,7 +99,7 @@ void MFIUser::ListDevices(HLERequestContext& ctx) {
     rb.Push(static_cast<s32>(nfp_devices.size()));
 }
 
-void MFIUser::StartDetection(HLERequestContext& ctx) {
+void MFInterface::StartDetection(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
@@ -141,7 +123,7 @@ void MFIUser::StartDetection(HLERequestContext& ctx) {
     rb.Push(result);
 }
 
-void MFIUser::StopDetection(HLERequestContext& ctx) {
+void MFInterface::StopDetection(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
@@ -165,7 +147,7 @@ void MFIUser::StopDetection(HLERequestContext& ctx) {
     rb.Push(result);
 }
 
-void MFIUser::Read(HLERequestContext& ctx) {
+void MFInterface::Read(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     const auto buffer{ctx.ReadBuffer()};
@@ -206,7 +188,7 @@ void MFIUser::Read(HLERequestContext& ctx) {
     rb.Push(result);
 }
 
-void MFIUser::Write(HLERequestContext& ctx) {
+void MFInterface::Write(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     const auto buffer{ctx.ReadBuffer()};
@@ -250,7 +232,7 @@ void MFIUser::Write(HLERequestContext& ctx) {
     rb.Push(result);
 }
 
-void MFIUser::GetTagInfo(HLERequestContext& ctx) {
+void MFInterface::GetTagInfo(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
@@ -276,7 +258,7 @@ void MFIUser::GetTagInfo(HLERequestContext& ctx) {
     rb.Push(result);
 }
 
-void MFIUser::GetActivateEventHandle(HLERequestContext& ctx) {
+void MFInterface::GetActivateEventHandle(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
@@ -300,7 +282,7 @@ void MFIUser::GetActivateEventHandle(HLERequestContext& ctx) {
     rb.PushCopyObjects(device.value()->GetActivateEvent());
 }
 
-void MFIUser::GetDeactivateEventHandle(HLERequestContext& ctx) {
+void MFInterface::GetDeactivateEventHandle(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
@@ -324,7 +306,7 @@ void MFIUser::GetDeactivateEventHandle(HLERequestContext& ctx) {
     rb.PushCopyObjects(device.value()->GetDeactivateEvent());
 }
 
-void MFIUser::GetState(HLERequestContext& ctx) {
+void MFInterface::GetState(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     IPC::ResponseBuilder rb{ctx, 3};
@@ -332,7 +314,7 @@ void MFIUser::GetState(HLERequestContext& ctx) {
     rb.PushEnum(state);
 }
 
-void MFIUser::GetDeviceState(HLERequestContext& ctx) {
+void MFInterface::GetDeviceState(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
@@ -350,7 +332,7 @@ void MFIUser::GetDeviceState(HLERequestContext& ctx) {
     rb.PushEnum(device.value()->GetCurrentState());
 }
 
-void MFIUser::GetNpadId(HLERequestContext& ctx) {
+void MFInterface::GetNpadId(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
     LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
@@ -374,7 +356,7 @@ void MFIUser::GetNpadId(HLERequestContext& ctx) {
     rb.PushEnum(device.value()->GetNpadId());
 }
 
-void MFIUser::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
+void MFInterface::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
     if (state == State::NonInitialized) {
@@ -388,7 +370,7 @@ void MFIUser::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
     rb.PushCopyObjects(availability_change_event->GetReadableEvent());
 }
 
-std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) {
+std::optional<std::shared_ptr<NfcDevice>> MFInterface::GetNfcDevice(u64 handle) {
     for (auto& device : devices) {
         if (device->GetHandle() == handle) {
             return device;
diff --git a/src/core/hle/service/nfc/mifare_user.h b/src/core/hle/service/nfc/mifare_interface.h
similarity index 90%
rename from src/core/hle/service/nfc/mifare_user.h
rename to src/core/hle/service/nfc/mifare_interface.h
index 9701f1d7f..698c8a6b6 100644
--- a/src/core/hle/service/nfc/mifare_user.h
+++ b/src/core/hle/service/nfc/mifare_interface.h
@@ -13,16 +13,10 @@
 namespace Service::NFC {
 class NfcDevice;
 
-class MFIUser final : public ServiceFramework<MFIUser> {
+class MFInterface : public ServiceFramework<MFInterface> {
 public:
-    explicit MFIUser(Core::System& system_);
-    ~MFIUser();
-
-private:
-    enum class State : u32 {
-        NonInitialized,
-        Initialized,
-    };
+    explicit MFInterface(Core::System& system_, const char* name);
+    ~MFInterface();
 
     void Initialize(HLERequestContext& ctx);
     void Finalize(HLERequestContext& ctx);
@@ -39,6 +33,12 @@ private:
     void GetNpadId(HLERequestContext& ctx);
     void GetAvailabilityChangeEventHandle(HLERequestContext& ctx);
 
+private:
+    enum class State : u32 {
+        NonInitialized,
+        Initialized,
+    };
+
     std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
 
     KernelHelpers::ServiceContext service_context;
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 7a8f59725..444d65f07 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -6,7 +6,7 @@
 #include "common/logging/log.h"
 #include "common/settings.h"
 #include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/mifare_user.h"
+#include "core/hle/service/nfc/mifare_interface.h"
 #include "core/hle/service/nfc/nfc.h"
 #include "core/hle/service/nfc/nfc_interface.h"
 #include "core/hle/service/server_manager.h"
@@ -16,7 +16,7 @@ namespace Service::NFC {
 
 class IUser final : public Interface {
 public:
-    explicit IUser(Core::System& system_) : Interface(system_, "IUser") {
+    explicit IUser(Core::System& system_) : Interface(system_, "NFC::IUser") {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &Interface::Initialize, "InitializeOld"},
@@ -50,7 +50,7 @@ public:
 
 class ISystem final : public Interface {
 public:
-    explicit ISystem(Core::System& system_) : Interface{system_, "ISystem"} {
+    explicit ISystem(Core::System& system_) : Interface{system_, "NFC::ISystem"} {
         // clang-format off
         static const FunctionInfo functions[] = {
             {0, &Interface::Initialize, "InitializeOld"},
@@ -85,6 +85,32 @@ public:
     }
 };
 
+class MFIUser final : public MFInterface {
+public:
+    explicit MFIUser(Core::System& system_) : MFInterface{system_, "NFC::MFInterface"} {
+        // clang-format off
+        static const FunctionInfo functions[] = {
+            {0, &MFIUser::Initialize, "Initialize"},
+            {1, &MFIUser::Finalize, "Finalize"},
+            {2, &MFIUser::ListDevices, "ListDevices"},
+            {3, &MFIUser::StartDetection, "StartDetection"},
+            {4, &MFIUser::StopDetection, "StopDetection"},
+            {5, &MFIUser::Read, "Read"},
+            {6, &MFIUser::Write, "Write"},
+            {7, &MFIUser::GetTagInfo, "GetTagInfo"},
+            {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
+            {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
+            {10, &MFIUser::GetState, "GetState"},
+            {11, &MFIUser::GetDeviceState, "GetDeviceState"},
+            {12, &MFIUser::GetNpadId, "GetNpadId"},
+            {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
+        };
+        // clang-format on
+
+        RegisterHandlers(functions);
+    }
+};
+
 class IAm final : public ServiceFramework<IAm> {
 public:
     explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {

From 5e16fe4579e10cf21af9fada603d8d585f683caf Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Tue, 25 Apr 2023 23:33:05 -0600
Subject: [PATCH 3/4] core: service: Add FunctionInfoTyped to allow expanding
 existing interfaces

---
 src/core/hle/service/service.h | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 0f79a1b7e..45b2c43b7 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -142,7 +142,8 @@ template <typename Self>
 class ServiceFramework : public ServiceFrameworkBase {
 protected:
     /// Contains information about a request type which is handled by the service.
-    struct FunctionInfo : FunctionInfoBase {
+    template <typename T>
+    struct FunctionInfoTyped : FunctionInfoBase {
         // TODO(yuriks): This function could be constexpr, but clang is the only compiler that
         // doesn't emit an ICE or a wrong diagnostic because of the static_cast.
 
@@ -155,12 +156,13 @@ protected:
          *     the request
          * @param name_ human-friendly name for the request. Used mostly for logging purposes.
          */
-        FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
+        FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
             : FunctionInfoBase{
                   expected_header_,
                   // Type-erase member function pointer by casting it down to the base class.
                   static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
     };
+    using FunctionInfo = FunctionInfoTyped<Self>;
 
     /**
      * Initializes the handler with no functions installed.
@@ -175,8 +177,8 @@ protected:
         : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
 
     /// Registers handlers in the service.
-    template <std::size_t N>
-    void RegisterHandlers(const FunctionInfo (&functions)[N]) {
+    template <typename T = Self, std::size_t N>
+    void RegisterHandlers(const FunctionInfoTyped<T> (&functions)[N]) {
         RegisterHandlers(functions, N);
     }
 
@@ -184,13 +186,14 @@ protected:
      * Registers handlers in the service. Usually prefer using the other RegisterHandlers
      * overload in order to avoid needing to specify the array size.
      */
-    void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
+    template <typename T = Self>
+    void RegisterHandlers(const FunctionInfoTyped<T>* functions, std::size_t n) {
         RegisterHandlersBase(functions, n);
     }
 
     /// Registers handlers in the service.
-    template <std::size_t N>
-    void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
+    template <typename T = Self, std::size_t N>
+    void RegisterHandlersTipc(const FunctionInfoTyped<T> (&functions)[N]) {
         RegisterHandlersTipc(functions, N);
     }
 
@@ -198,7 +201,8 @@ protected:
      * Registers handlers in the service. Usually prefer using the other RegisterHandlers
      * overload in order to avoid needing to specify the array size.
      */
-    void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
+    template <typename T = Self>
+    void RegisterHandlersTipc(const FunctionInfoTyped<T>* functions, std::size_t n) {
         RegisterHandlersBaseTipc(functions, n);
     }
 

From 94151097b9abadf35c55ea06a31925c9848f4c62 Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Wed, 19 Apr 2023 19:01:23 -0600
Subject: [PATCH 4/4] service: nfc: Merge device interfaces and create the
 device manager

---
 src/core/CMakeLists.txt                       |  21 +-
 src/core/frontend/applets/cabinet.cpp         |   2 +-
 src/core/frontend/applets/cabinet.h           |  10 +-
 .../hle/service/am/applets/applet_cabinet.cpp |  24 +-
 .../hle/service/am/applets/applet_cabinet.h   |   6 +-
 .../{nfp => nfc/common}/amiibo_crypto.cpp     |   4 +-
 .../{nfp => nfc/common}/amiibo_crypto.h       |   4 +-
 .../nfp_device.cpp => nfc/common/device.cpp}  | 702 ++++++++------
 src/core/hle/service/nfc/common/device.h      | 138 +++
 .../hle/service/nfc/common/device_manager.cpp | 695 ++++++++++++++
 .../hle/service/nfc/common/device_manager.h   | 100 ++
 src/core/hle/service/nfc/mifare_interface.cpp | 382 --------
 src/core/hle/service/nfc/mifare_interface.h   |  52 --
 src/core/hle/service/nfc/mifare_result.h      |  17 +
 src/core/hle/service/nfc/mifare_types.h       |  63 ++
 src/core/hle/service/nfc/nfc.cpp              | 125 +--
 src/core/hle/service/nfc/nfc_device.cpp       | 287 ------
 src/core/hle/service/nfc/nfc_device.h         |  78 --
 src/core/hle/service/nfc/nfc_interface.cpp    | 439 +++++----
 src/core/hle/service/nfc/nfc_interface.h      |  33 +-
 src/core/hle/service/nfc/nfc_result.h         |  33 +-
 src/core/hle/service/nfc/nfc_types.h          |  90 ++
 src/core/hle/service/nfp/nfp.cpp              |  12 +-
 src/core/hle/service/nfp/nfp_device.h         | 120 ---
 src/core/hle/service/nfp/nfp_interface.cpp    | 879 +++---------------
 src/core/hle/service/nfp/nfp_interface.h      |  37 +-
 src/core/hle/service/nfp/nfp_result.h         |  29 +-
 src/core/hle/service/nfp/nfp_types.h          | 129 +--
 src/yuzu/applets/qt_amiibo_settings.cpp       |  12 +-
 src/yuzu/applets/qt_amiibo_settings.h         |  14 +-
 src/yuzu/main.cpp                             |   6 +-
 src/yuzu/main.h                               |   8 +-
 32 files changed, 2086 insertions(+), 2465 deletions(-)
 rename src/core/hle/service/{nfp => nfc/common}/amiibo_crypto.cpp (99%)
 rename src/core/hle/service/{nfp => nfc/common}/amiibo_crypto.h (98%)
 rename src/core/hle/service/{nfp/nfp_device.cpp => nfc/common/device.cpp} (61%)
 create mode 100644 src/core/hle/service/nfc/common/device.h
 create mode 100644 src/core/hle/service/nfc/common/device_manager.cpp
 create mode 100644 src/core/hle/service/nfc/common/device_manager.h
 delete mode 100644 src/core/hle/service/nfc/mifare_interface.cpp
 delete mode 100644 src/core/hle/service/nfc/mifare_interface.h
 create mode 100644 src/core/hle/service/nfc/mifare_result.h
 create mode 100644 src/core/hle/service/nfc/mifare_types.h
 delete mode 100644 src/core/hle/service/nfc/nfc_device.cpp
 delete mode 100644 src/core/hle/service/nfc/nfc_device.h
 create mode 100644 src/core/hle/service/nfc/nfc_types.h
 delete mode 100644 src/core/hle/service/nfp/nfp_device.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8817a99c9..45328158f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -555,21 +555,22 @@ add_library(core STATIC
     hle/service/mnpp/mnpp_app.h
     hle/service/ncm/ncm.cpp
     hle/service/ncm/ncm.h
-    hle/service/nfc/mifare_user.cpp
-    hle/service/nfc/mifare_user.h
+    hle/service/nfc/common/amiibo_crypto.cpp
+    hle/service/nfc/common/amiibo_crypto.h
+    hle/service/nfc/common/device.cpp
+    hle/service/nfc/common/device.h
+    hle/service/nfc/common/device_manager.cpp
+    hle/service/nfc/common/device_manager.h
+    hle/service/nfc/mifare_result.h
+    hle/service/nfc/mifare_types.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_interface.cpp
+    hle/service/nfc/nfc_interface.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/nfc/nfc_types.h
     hle/service/nfp/nfp.cpp
     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
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp
index 2d501eeae..c33ce248b 100644
--- a/src/core/frontend/applets/cabinet.cpp
+++ b/src/core/frontend/applets/cabinet.cpp
@@ -14,7 +14,7 @@ void DefaultCabinetApplet::Close() const {}
 
 void DefaultCabinetApplet::ShowCabinetApplet(
     const CabinetCallback& callback, const CabinetParameters& parameters,
-    std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
+    std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
     LOG_WARNING(Service_AM, "(STUBBED) called");
     callback(false, {});
 }
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h
index 74dc5a4f6..af3fc6c3d 100644
--- a/src/core/frontend/applets/cabinet.h
+++ b/src/core/frontend/applets/cabinet.h
@@ -7,9 +7,9 @@
 #include "core/frontend/applets/applet.h"
 #include "core/hle/service/nfp/nfp_types.h"
 
-namespace Service::NFP {
-class NfpDevice;
-} // namespace Service::NFP
+namespace Service::NFC {
+class NfcDevice;
+} // namespace Service::NFC
 
 namespace Core::Frontend {
 
@@ -26,14 +26,14 @@ public:
     virtual ~CabinetApplet();
     virtual void ShowCabinetApplet(const CabinetCallback& callback,
                                    const CabinetParameters& parameters,
-                                   std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
+                                   std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
 };
 
 class DefaultCabinetApplet final : public CabinetApplet {
 public:
     void Close() const override;
     void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
-                           std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
+                           std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
 };
 
 } // namespace Core::Frontend
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index 93c9f2a55..8b754e9d4 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -11,7 +11,7 @@
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/am/applets/applet_cabinet.h"
 #include "core/hle/service/mii/mii_manager.h"
-#include "core/hle/service/nfp/nfp_device.h"
+#include "core/hle/service/nfc/common/device.h"
 
 namespace Service::AM::Applets {
 
@@ -72,10 +72,10 @@ void Cabinet::Execute() {
 
     // TODO: listen on all controllers
     if (nfp_device == nullptr) {
-        nfp_device = std::make_shared<Service::NFP::NfpDevice>(
+        nfp_device = std::make_shared<Service::NFC::NfcDevice>(
             system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
         nfp_device->Initialize();
-        nfp_device->StartDetection(Service::NFP::TagProtocol::All);
+        nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
     }
 
     const Core::Frontend::CabinetParameters parameters{
@@ -106,20 +106,22 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
         Cancel();
     }
 
-    if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
-        nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+    if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
+        nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
         Cancel();
     }
 
-    if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
-        nfp_device->Mount(Service::NFP::MountTarget::All);
+    if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) {
+        nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
     }
 
     switch (applet_input_common.applet_mode) {
     case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
-        Service::NFP::AmiiboName name{};
-        std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
-        nfp_device->SetRegisterInfoPrivate(name);
+        Service::NFP::RegisterInfoPrivate register_info{};
+        std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(),
+                    std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1));
+
+        nfp_device->SetRegisterInfoPrivate(register_info);
         break;
     }
     case Service::NFP::CabinetMode::StartGameDataEraser:
@@ -139,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
     applet_output.device_handle = applet_input_common.device_handle;
     applet_output.result = CabinetResult::Cancel;
     const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
-    const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
+    const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false);
     nfp_device->Finalize();
 
     if (reg_result.IsSuccess()) {
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
index edd295a27..b56427021 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.h
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -19,8 +19,8 @@ namespace Core {
 class System;
 } // namespace Core
 
-namespace Service::NFP {
-class NfpDevice;
+namespace Service::NFC {
+class NfcDevice;
 }
 
 namespace Service::AM::Applets {
@@ -96,7 +96,7 @@ private:
     Core::System& system;
 
     bool is_complete{false};
-    std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+    std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
     Kernel::KEvent* availability_change_event;
     KernelHelpers::ServiceContext service_context;
     StartParamForAmiiboSettings applet_input_common{};
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
similarity index 99%
rename from src/core/hle/service/nfp/amiibo_crypto.cpp
rename to src/core/hle/service/nfc/common/amiibo_crypto.cpp
index a3622e792..f3901ee8d 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -12,7 +12,7 @@
 #include "common/fs/fs.h"
 #include "common/fs/path_util.h"
 #include "common/logging/log.h"
-#include "core/hle/service/nfp/amiibo_crypto.h"
+#include "core/hle/service/nfc/common/amiibo_crypto.h"
 
 namespace Service::NFP::AmiiboCrypto {
 
@@ -55,7 +55,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
     if (amiibo_data.constant_value != 0xA5) {
         return false;
     }
-    if (amiibo_data.model_info.tag_type != PackedTagType::Type2) {
+    if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
         return false;
     }
     if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h
similarity index 98%
rename from src/core/hle/service/nfp/amiibo_crypto.h
rename to src/core/hle/service/nfc/common/amiibo_crypto.h
index f6208ee6b..bf3044ed9 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.h
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.h
@@ -24,9 +24,9 @@ using DrgbOutput = std::array<u8, 0x20>;
 struct HashSeed {
     u16_be magic;
     std::array<u8, 0xE> padding;
-    UniqueSerialNumber uid_1;
+    NFC::UniqueSerialNumber uid_1;
     u8 nintendo_id_1;
-    UniqueSerialNumber uid_2;
+    NFC::UniqueSerialNumber uid_2;
     u8 nintendo_id_2;
     std::array<u8, 0x20> keygen_salt;
 };
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfc/common/device.cpp
similarity index 61%
rename from src/core/hle/service/nfp/nfp_device.cpp
rename to src/core/hle/service/nfc/common/device.cpp
index 3f9af53c8..e5de65ce0 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1,8 +1,6 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
-#include <array>
-
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
@@ -26,21 +24,22 @@
 #include "core/hle/service/ipc_helpers.h"
 #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_device.h"
-#include "core/hle/service/nfp/nfp_result.h"
+#include "core/hle/service/nfc/common/amiibo_crypto.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/mifare_result.h"
+#include "core/hle/service/nfc/nfc_result.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"
 
-namespace Service::NFP {
-NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+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:NFPActivateEvent");
-    deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent");
+    activate_event = service_context.CreateEvent("NFC:ActivateEvent");
+    deactivate_event = service_context.CreateEvent("NFC:DeactivateEvent");
     npad_device = system.HIDCore().GetEmulatedController(npad_id);
 
     Core::HID::ControllerUpdateCallback engine_callback{
@@ -54,9 +53,9 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
     current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
 }
 
-NfpDevice::~NfpDevice() {
-    activate_event->Close();
-    deactivate_event->Close();
+NfcDevice::~NfcDevice() {
+    service_context.CloseEvent(activate_event);
+    service_context.CloseEvent(deactivate_event);
     if (!is_controller_set) {
         return;
     }
@@ -64,7 +63,7 @@ NfpDevice::~NfpDevice() {
     is_controller_set = false;
 };
 
-void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
+void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
     if (!is_initalized) {
         return;
     }
@@ -92,14 +91,14 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
     const auto nfc_status = npad_device->GetNfc();
     switch (nfc_status.state) {
     case Common::Input::NfcState::NewAmiibo:
-        LoadAmiibo(nfc_status.data);
+        LoadNfcTag(nfc_status.data);
         break;
     case Common::Input::NfcState::AmiiboRemoved:
         if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
             break;
         }
         if (device_state != DeviceState::SearchingForTag) {
-            CloseAmiibo();
+            CloseNfcTag();
         }
         break;
     default:
@@ -107,28 +106,29 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
     }
 }
 
-bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
+bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
     if (device_state != DeviceState::SearchingForTag) {
-        LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state);
+        LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
         return false;
     }
 
-    if (data.size() != sizeof(EncryptedNTAG215File)) {
-        LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size());
+    if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
+        LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
         return false;
     }
 
-    // TODO: Filter by allowed_protocols here
+    mifare_data.resize(data.size());
+    memcpy(mifare_data.data(), data.data(), data.size());
 
-    memcpy(&tag_data, data.data(), sizeof(EncryptedNTAG215File));
-    is_plain_amiibo = AmiiboCrypto::IsAmiiboValid(tag_data);
+    memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+    is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
 
     if (is_plain_amiibo) {
-        encrypted_tag_data = AmiiboCrypto::EncodedDataToNfcData(tag_data);
+        encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
         LOG_INFO(Service_NFP, "Using plain amiibo");
     } else {
         tag_data = {};
-        memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
+        memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
     }
 
     device_state = DeviceState::TagFound;
@@ -137,8 +137,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
     return true;
 }
 
-void NfpDevice::CloseAmiibo() {
-    LOG_INFO(Service_NFP, "Remove amiibo");
+void NfcDevice::CloseNfcTag() {
+    LOG_INFO(Service_NFC, "Remove nfc tag");
 
     if (device_state == DeviceState::TagMounted) {
         Unmount();
@@ -147,26 +147,28 @@ void NfpDevice::CloseAmiibo() {
     device_state = DeviceState::TagRemoved;
     encrypted_tag_data = {};
     tag_data = {};
+    mifare_data = {};
     activate_event->GetReadableEvent().Clear();
     deactivate_event->Signal();
 }
 
-Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const {
+Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
     return activate_event->GetReadableEvent();
 }
 
-Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const {
+Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
     return deactivate_event->GetReadableEvent();
 }
 
-void NfpDevice::Initialize() {
+void NfcDevice::Initialize() {
     device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
     encrypted_tag_data = {};
     tag_data = {};
+    mifare_data = {};
     is_initalized = true;
 }
 
-void NfpDevice::Finalize() {
+void NfcDevice::Finalize() {
     if (device_state == DeviceState::TagMounted) {
         Unmount();
     }
@@ -177,17 +179,17 @@ void NfpDevice::Finalize() {
     is_initalized = false;
 }
 
-Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
+Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
     if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
-        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
-        return WrongDeviceState;
+        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+        return ResultWrongDeviceState;
     }
 
     if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
                                     Common::Input::PollingMode::NFC) !=
         Common::Input::DriverResult::Success) {
-        LOG_ERROR(Service_NFP, "Nfc not supported");
-        return NfcDisabled;
+        LOG_ERROR(Service_NFC, "Nfc not supported");
+        return ResultNfcDisabled;
     }
 
     device_state = DeviceState::SearchingForTag;
@@ -195,7 +197,7 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
     return ResultSuccess;
 }
 
-Result NfpDevice::StopDetection() {
+Result NfcDevice::StopDetection() {
     npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
                                 Common::Input::PollingMode::Active);
 
@@ -204,7 +206,7 @@ Result NfpDevice::StopDetection() {
     }
 
     if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
-        CloseAmiibo();
+        CloseNfcTag();
     }
 
     if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
@@ -212,22 +214,194 @@ Result NfpDevice::StopDetection() {
         return ResultSuccess;
     }
 
-    LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
-    return WrongDeviceState;
+    LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+    return ResultWrongDeviceState;
 }
 
-Result NfpDevice::Flush() {
+Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
+    if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
+        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+        if (device_state == DeviceState::TagRemoved) {
+            return ResultTagRemoved;
+        }
+        return ResultWrongDeviceState;
+    }
+
+    if (is_mifare) {
+        tag_info = {
+            .uuid = encrypted_tag_data.uuid.uid,
+            .uuid_extension = {},
+            .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
+            .protocol = NfcProtocol::TypeA,
+            .tag_type = TagType::Type4,
+        };
+        return ResultSuccess;
+    }
+
+    // Protocol and tag type may change here
+    tag_info = {
+        .uuid = encrypted_tag_data.uuid.uid,
+        .uuid_extension = {},
+        .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
+        .protocol = NfcProtocol::TypeA,
+        .tag_type = TagType::Type2,
+    };
+
+    return ResultSuccess;
+}
+
+Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
+                             std::span<MifareReadBlockData> read_block_data) const {
+    Result result = ResultSuccess;
+
+    for (std::size_t i = 0; i < parameters.size(); i++) {
+        result = ReadMifare(parameters[i], read_block_data[i]);
+        if (result.IsError()) {
+            break;
+        }
+    }
+
+    return result;
+}
+
+Result NfcDevice::ReadMifare(const MifareReadBlockParameter& parameter,
+                             MifareReadBlockData& read_block_data) const {
+    const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
+    read_block_data.sector_number = parameter.sector_number;
+
+    if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
+        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+        if (device_state == DeviceState::TagRemoved) {
+            return ResultTagRemoved;
+        }
+        return ResultWrongDeviceState;
+    }
+
+    if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
+        return Mifare::ResultReadError;
+    }
+
+    // TODO: Use parameter.sector_key to read encrypted data
+    memcpy(read_block_data.data.data(), mifare_data.data() + sector_index, sizeof(DataBlock));
+
+    return ResultSuccess;
+}
+
+Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
+    Result result = ResultSuccess;
+
+    for (std::size_t i = 0; i < parameters.size(); i++) {
+        result = WriteMifare(parameters[i]);
+        if (result.IsError()) {
+            break;
+        }
+    }
+
+    if (!npad_device->WriteNfc(mifare_data)) {
+        LOG_ERROR(Service_NFP, "Error writing to file");
+        return Mifare::ResultReadError;
+    }
+
+    return result;
+}
+
+Result NfcDevice::WriteMifare(const MifareWriteBlockParameter& parameter) {
+    const std::size_t sector_index = parameter.sector_number * sizeof(DataBlock);
+
+    if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
+        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+        if (device_state == DeviceState::TagRemoved) {
+            return ResultTagRemoved;
+        }
+        return ResultWrongDeviceState;
+    }
+
+    if (mifare_data.size() < sector_index + sizeof(DataBlock)) {
+        return Mifare::ResultReadError;
+    }
+
+    // TODO: Use parameter.sector_key to encrypt the data
+    memcpy(mifare_data.data() + sector_index, parameter.data.data(), sizeof(DataBlock));
+
+    return ResultSuccess;
+}
+
+Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
+                                           std::span<const u8> command_data,
+                                           std::span<u8> out_data) {
+    // Not implemented
+    return ResultSuccess;
+}
+
+Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
+    if (device_state != DeviceState::TagFound) {
+        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+        return ResultWrongDeviceState;
+    }
+
+    // The loaded amiibo is not encrypted
+    if (is_plain_amiibo) {
+        device_state = DeviceState::TagMounted;
+        mount_target = mount_target_;
+        return ResultSuccess;
+    }
+
+    if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
+        LOG_ERROR(Service_NFP, "Not an amiibo");
+        return ResultNotAnAmiibo;
+    }
+
+    // Mark amiibos as read only when keys are missing
+    if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
+        LOG_ERROR(Service_NFP, "No keys detected");
+        device_state = DeviceState::TagMounted;
+        mount_target = NFP::MountTarget::Rom;
+        return ResultSuccess;
+    }
+
+    if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
+        LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
+        return ResultCorruptedData;
+    }
+
+    device_state = DeviceState::TagMounted;
+    mount_target = mount_target_;
+    return ResultSuccess;
+}
+
+Result NfcDevice::Unmount() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    // Save data before unloading the amiibo
+    if (is_data_moddified) {
+        Flush();
+    }
+
+    device_state = DeviceState::TagFound;
+    mount_target = NFP::MountTarget::None;
+    is_app_area_open = false;
+
+    return ResultSuccess;
+}
+
+Result NfcDevice::Flush() {
+    if (device_state != DeviceState::TagMounted) {
+        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+        if (device_state == DeviceState::TagRemoved) {
+            return ResultTagRemoved;
+        }
+        return ResultWrongDeviceState;
+    }
+
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     auto& settings = tag_data.settings;
@@ -240,49 +414,49 @@ Result NfpDevice::Flush() {
 
     tag_data.write_counter++;
 
-    FlushWithBreak(BreakType::Normal);
+    FlushWithBreak(NFP::BreakType::Normal);
 
     is_data_moddified = false;
 
     return ResultSuccess;
 }
 
-Result NfpDevice::FlushDebug() {
+Result NfcDevice::FlushDebug() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     tag_data.write_counter++;
 
-    FlushWithBreak(BreakType::Normal);
+    FlushWithBreak(NFP::BreakType::Normal);
 
     is_data_moddified = false;
 
     return ResultSuccess;
 }
 
-Result NfpDevice::FlushWithBreak(BreakType break_type) {
-    if (break_type != BreakType::Normal) {
+Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
+    if (break_type != NFP::BreakType::Normal) {
         LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    std::vector<u8> data(sizeof(EncryptedNTAG215File));
+    std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
     if (is_plain_amiibo) {
         memcpy(data.data(), &tag_data, sizeof(tag_data));
     } else {
-        if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
+        if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
             LOG_ERROR(Service_NFP, "Failed to encode data");
-            return WriteAmiiboFailed;
+            return ResultWriteAmiiboFailed;
         }
 
         memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
@@ -290,100 +464,43 @@ Result NfpDevice::FlushWithBreak(BreakType break_type) {
 
     if (!npad_device->WriteNfc(data)) {
         LOG_ERROR(Service_NFP, "Error writing to file");
-        return WriteAmiiboFailed;
+        return ResultWriteAmiiboFailed;
     }
 
     return ResultSuccess;
 }
 
-Result NfpDevice::Mount(MountTarget mount_target_) {
-    if (device_state != DeviceState::TagFound) {
-        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
-        return WrongDeviceState;
-    }
-
-    // The loaded amiibo is not encrypted
-    if (is_plain_amiibo) {
-        device_state = DeviceState::TagMounted;
-        mount_target = mount_target_;
-        return ResultSuccess;
-    }
-
-    if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
-        LOG_ERROR(Service_NFP, "Not an amiibo");
-        return NotAnAmiibo;
-    }
-
-    // Mark amiibos as read only when keys are missing
-    if (!AmiiboCrypto::IsKeyAvailable()) {
-        LOG_ERROR(Service_NFP, "No keys detected");
-        device_state = DeviceState::TagMounted;
-        mount_target = MountTarget::Rom;
-        return ResultSuccess;
-    }
-
-    if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
-        LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
-        return CorruptedData;
-    }
-
-    device_state = DeviceState::TagMounted;
-    mount_target = mount_target_;
-    return ResultSuccess;
-}
-
-Result NfpDevice::Unmount() {
+Result NfcDevice::Restore() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    // Save data before unloading the amiibo
-    if (is_data_moddified) {
-        Flush();
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+        LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+        return ResultWrongDeviceState;
     }
 
-    device_state = DeviceState::TagFound;
-    mount_target = MountTarget::None;
-    is_app_area_open = false;
-
+    // TODO: Load amiibo from backup on system
+    LOG_ERROR(Service_NFP, "Not Implemented");
     return ResultSuccess;
 }
 
-Result NfpDevice::GetTagInfo(TagInfo& tag_info) const {
-    if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
-        if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
-        }
-        return WrongDeviceState;
-    }
-
-    tag_info = {
-        .uuid = encrypted_tag_data.uuid.uid,
-        .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
-        .protocol = TagProtocol::TypeA,
-        .tag_type = TagType::Type2,
-    };
-
-    return ResultSuccess;
-}
-
-Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
+Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     const auto& settings = tag_data.settings;
@@ -393,18 +510,18 @@ Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
         .last_write_date = settings.write_date.GetWriteDate(),
         .write_counter = tag_data.write_counter,
         .version = tag_data.amiibo_version,
-        .application_area_size = sizeof(ApplicationArea),
+        .application_area_size = sizeof(NFP::ApplicationArea),
     };
     return ResultSuccess;
 }
 
-Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
+Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
@@ -418,22 +535,22 @@ Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
     return ResultSuccess;
 }
 
-Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
+Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& 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 ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.amiibo_initialized == 0) {
-        return RegistrationIsNotInitialized;
+        return ResultRegistrationIsNotInitialized;
     }
 
     Service::Mii::MiiManager manager;
@@ -450,22 +567,22 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
     return ResultSuccess;
 }
 
-Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const {
+Result NfcDevice::GetRegisterInfoPrivate(NFP::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 ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.amiibo_initialized == 0) {
-        return RegistrationIsNotInitialized;
+        return ResultRegistrationIsNotInitialized;
     }
 
     Service::Mii::MiiManager manager;
@@ -482,18 +599,18 @@ Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) con
     return ResultSuccess;
 }
 
-Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
+Result NfcDevice::GetAdminInfo(NFP::AdminInfo& admin_info) const {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4);
@@ -503,17 +620,18 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
 
     u64 application_id = 0;
     u32 application_area_id = 0;
-    AppAreaVersion app_area_version = AppAreaVersion::NotSet;
+    NFP::AppAreaVersion app_area_version = NFP::AppAreaVersion::NotSet;
     if (tag_data.settings.settings.appdata_initialized != 0) {
         application_id = tag_data.application_id;
-        app_area_version =
-            static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf);
+        app_area_version = static_cast<NFP::AppAreaVersion>(
+            application_id >> NFP::application_id_version_offset & 0xf);
 
         // Restore application id to original value
         if (application_id >> 0x38 != 0) {
             const u8 application_byte = tag_data.application_id_byte & 0xf;
-            application_id = RemoveVersionByte(application_id) |
-                             (static_cast<u64>(application_byte) << application_id_version_offset);
+            application_id =
+                RemoveVersionByte(application_id) |
+                (static_cast<u64>(application_byte) << NFP::application_id_version_offset);
         }
 
         application_area_id = tag_data.application_area_id;
@@ -532,22 +650,22 @@ Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const {
     return ResultSuccess;
 }
 
-Result NfpDevice::DeleteRegisterInfo() {
+Result NfcDevice::DeleteRegisterInfo() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.amiibo_initialized == 0) {
-        return RegistrationIsNotInitialized;
+        return ResultRegistrationIsNotInitialized;
     }
 
     Common::TinyMT rng{};
@@ -564,18 +682,18 @@ Result NfpDevice::DeleteRegisterInfo() {
     return Flush();
 }
 
-Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
+Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     Service::Mii::MiiManager manager;
@@ -587,7 +705,7 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
         settings.write_date.raw_date = 0;
     }
 
-    SetAmiiboName(settings, amiibo_name);
+    SetAmiiboName(settings, register_info.amiibo_name);
     tag_data.owner_mii = manager.BuildFromStoreData(mii);
     tag_data.mii_extension = manager.SetFromStoreData(mii);
     tag_data.unknown = 0;
@@ -601,18 +719,18 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
     return Flush();
 }
 
-Result NfpDevice::RestoreAmiibo() {
+Result NfcDevice::RestoreAmiibo() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     // TODO: Load amiibo from backup on system
@@ -620,7 +738,7 @@ Result NfpDevice::RestoreAmiibo() {
     return ResultSuccess;
 }
 
-Result NfpDevice::Format() {
+Result NfcDevice::Format() {
     auto result1 = DeleteApplicationArea();
     auto result2 = DeleteRegisterInfo();
 
@@ -635,28 +753,28 @@ Result NfpDevice::Format() {
     return Flush();
 }
 
-Result NfpDevice::OpenApplicationArea(u32 access_id) {
+Result NfcDevice::OpenApplicationArea(u32 access_id) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
         LOG_WARNING(Service_NFP, "Application area is not initialized");
-        return ApplicationAreaIsNotInitialized;
+        return ResultApplicationAreaIsNotInitialized;
     }
 
     if (tag_data.application_area_id != access_id) {
         LOG_WARNING(Service_NFP, "Wrong application area id");
-        return WrongApplicationAreaId;
+        return ResultWrongApplicationAreaId;
     }
 
     is_app_area_open = true;
@@ -664,25 +782,25 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
     return ResultSuccess;
 }
 
-Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
+Result NfcDevice::GetApplicationAreaId(u32& application_area_id) const {
     application_area_id = {};
 
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
         LOG_WARNING(Service_NFP, "Application area is not initialized");
-        return ApplicationAreaIsNotInitialized;
+        return ResultApplicationAreaIsNotInitialized;
     }
 
     application_area_id = tag_data.application_area_id;
@@ -690,64 +808,61 @@ Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
     return ResultSuccess;
 }
 
-Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
+Result NfcDevice::GetApplicationArea(std::span<u8> data) const {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (!is_app_area_open) {
         LOG_ERROR(Service_NFP, "Application area is not open");
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
         LOG_ERROR(Service_NFP, "Application area is not initialized");
-        return ApplicationAreaIsNotInitialized;
+        return ResultApplicationAreaIsNotInitialized;
     }
 
-    if (data.size() > sizeof(ApplicationArea)) {
-        data.resize(sizeof(ApplicationArea));
-    }
-
-    memcpy(data.data(), tag_data.application_area.data(), data.size());
+    memcpy(data.data(), tag_data.application_area.data(),
+           std::min(data.size(), sizeof(NFP::ApplicationArea)));
 
     return ResultSuccess;
 }
 
-Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
+Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (!is_app_area_open) {
         LOG_ERROR(Service_NFP, "Application area is not open");
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
         LOG_ERROR(Service_NFP, "Application area is not initialized");
-        return ApplicationAreaIsNotInitialized;
+        return ResultApplicationAreaIsNotInitialized;
     }
 
-    if (data.size() > sizeof(ApplicationArea)) {
+    if (data.size() > sizeof(NFP::ApplicationArea)) {
         LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
         return ResultUnknown;
     }
@@ -756,9 +871,9 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
     std::memcpy(tag_data.application_area.data(), data.data(), data.size());
     // Fill remaining data with random numbers
     rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
-                            sizeof(ApplicationArea) - data.size());
+                            sizeof(NFP::ApplicationArea) - data.size());
 
-    if (tag_data.application_write_counter != counter_limit) {
+    if (tag_data.application_write_counter != NFP::counter_limit) {
         tag_data.application_write_counter++;
     }
 
@@ -767,64 +882,64 @@ Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
     return ResultSuccess;
 }
 
-Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
+Result NfcDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
         LOG_ERROR(Service_NFP, "Application area already exist");
-        return ApplicationAreaExist;
+        return ResultApplicationAreaExist;
     }
 
     return RecreateApplicationArea(access_id, data);
 }
 
-Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
+Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (is_app_area_open) {
         LOG_ERROR(Service_NFP, "Application area is open");
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (data.size() > sizeof(ApplicationArea)) {
+    if (data.size() > sizeof(NFP::ApplicationArea)) {
         LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
-        return WrongApplicationAreaSize;
+        return ResultWrongApplicationAreaSize;
     }
 
     Common::TinyMT rng{};
     std::memcpy(tag_data.application_area.data(), data.data(), data.size());
     // Fill remaining data with random numbers
     rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
-                            sizeof(ApplicationArea) - data.size());
+                            sizeof(NFP::ApplicationArea) - data.size());
 
-    if (tag_data.application_write_counter != counter_limit) {
+    if (tag_data.application_write_counter != NFP::counter_limit) {
         tag_data.application_write_counter++;
     }
 
     const u64 application_id = system.GetApplicationProcessProgramID();
 
     tag_data.application_id_byte =
-        static_cast<u8>(application_id >> application_id_version_offset & 0xf);
+        static_cast<u8>(application_id >> NFP::application_id_version_offset & 0xf);
     tag_data.application_id =
-        RemoveVersionByte(application_id) |
-        (static_cast<u64>(AppAreaVersion::NintendoSwitch) << application_id_version_offset);
+        RemoveVersionByte(application_id) | (static_cast<u64>(NFP::AppAreaVersion::NintendoSwitch)
+                                             << NFP::application_id_version_offset);
     tag_data.settings.settings.appdata_initialized.Assign(1);
     tag_data.application_area_id = access_id;
     tag_data.unknown = {};
@@ -835,30 +950,30 @@ Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> dat
     return Flush();
 }
 
-Result NfpDevice::DeleteApplicationArea() {
+Result NfcDevice::DeleteApplicationArea() {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     if (tag_data.settings.settings.appdata_initialized == 0) {
-        return ApplicationAreaIsNotInitialized;
+        return ResultApplicationAreaIsNotInitialized;
     }
 
-    if (tag_data.application_write_counter != counter_limit) {
+    if (tag_data.application_write_counter != NFP::counter_limit) {
         tag_data.application_write_counter++;
     }
 
     Common::TinyMT rng{};
-    rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea));
+    rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
     rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
     rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
     rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
@@ -872,18 +987,18 @@ Result NfpDevice::DeleteApplicationArea() {
     return Flush();
 }
 
-Result NfpDevice::ExistApplicationArea(bool& has_application_area) {
+Result NfcDevice::ExistsApplicationArea(bool& has_application_area) const {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
@@ -891,21 +1006,21 @@ Result NfpDevice::ExistApplicationArea(bool& has_application_area) {
     return ResultSuccess;
 }
 
-Result NfpDevice::GetAll(NfpData& data) const {
+Result NfcDevice::GetAll(NFP::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 ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    CommonInfo common_info{};
+    NFP::CommonInfo common_info{};
     Service::Mii::MiiManager manager;
     const u64 application_id = tag_data.application_id;
 
@@ -930,8 +1045,8 @@ Result NfpDevice::GetAll(NfpData& data) const {
         .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),
+        .console_type = static_cast<NFP::AppAreaVersion>(
+            application_id >> NFP::application_id_version_offset & 0xf),
         .application_id_byte = tag_data.application_id_byte,
         .application_area = tag_data.application_area,
     };
@@ -939,18 +1054,18 @@ Result NfpDevice::GetAll(NfpData& data) const {
     return ResultSuccess;
 }
 
-Result NfpDevice::SetAll(const NfpData& data) {
+Result NfcDevice::SetAll(const NFP::NfpData& data) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     tag_data.constant_value = data.magic;
@@ -977,18 +1092,18 @@ Result NfpDevice::SetAll(const NfpData& data) {
     return ResultSuccess;
 }
 
-Result NfpDevice::BreakTag(BreakType break_type) {
+Result NfcDevice::BreakTag(NFP::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 ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     // TODO: Complete this implementation
@@ -996,28 +1111,28 @@ Result NfpDevice::BreakTag(BreakType break_type) {
     return FlushWithBreak(break_type);
 }
 
-Result NfpDevice::ReadBackupData() {
+Result NfcDevice::ReadBackupData(std::span<u8> data) const {
     // Not implemented
     return ResultSuccess;
 }
 
-Result NfpDevice::WriteBackupData() {
+Result NfcDevice::WriteBackupData(std::span<const u8> data) {
     // Not implemented
     return ResultSuccess;
 }
 
-Result NfpDevice::WriteNtf() {
+Result NfcDevice::WriteNtf(std::span<const u8> data) {
     if (device_state != DeviceState::TagMounted) {
         LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
         if (device_state == DeviceState::TagRemoved) {
-            return TagRemoved;
+            return ResultTagRemoved;
         }
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
-    if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+    if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
         LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
-        return WrongDeviceState;
+        return ResultWrongDeviceState;
     }
 
     // Not implemented
@@ -1025,29 +1140,12 @@ Result NfpDevice::WriteNtf() {
     return ResultSuccess;
 }
 
-u64 NfpDevice::GetHandle() const {
-    // Generate a handle based of the npad id
-    return static_cast<u64>(npad_id);
-}
-
-u32 NfpDevice::GetApplicationAreaSize() const {
-    return sizeof(ApplicationArea);
-}
-
-DeviceState NfpDevice::GetCurrentState() const {
-    return device_state;
-}
-
-Core::HID::NpadIdType NfpDevice::GetNpadId() const {
-    return npad_id;
-}
-
-AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
-    std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
-    AmiiboName amiibo_name{};
+NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) const {
+    std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
+    NFP::AmiiboName amiibo_name{};
 
     // Convert from big endian to little endian
-    for (std::size_t i = 0; i < amiibo_name_length; i++) {
+    for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
         settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
     }
 
@@ -1058,8 +1156,8 @@ AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
     return amiibo_name;
 }
 
-void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) {
-    std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
+void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) {
+    std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
 
     // Convert from utf8 to utf16
     const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
@@ -1067,16 +1165,16 @@ void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo
            amiibo_name_utf16.size() * sizeof(char16_t));
 
     // Convert from little endian to big endian
-    for (std::size_t i = 0; i < amiibo_name_length; i++) {
+    for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
         settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
     }
 }
 
-AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
+NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
     const auto& time_zone_manager =
         system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
     Time::TimeZone::CalendarInfo calendar_info{};
-    AmiiboDate amiibo_date{};
+    NFP::AmiiboDate amiibo_date{};
 
     amiibo_date.SetYear(2000);
     amiibo_date.SetMonth(1);
@@ -1091,14 +1189,14 @@ AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
     return amiibo_date;
 }
 
-u64 NfpDevice::RemoveVersionByte(u64 application_id) const {
-    return application_id & ~(0xfULL << application_id_version_offset);
+u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
+    return application_id & ~(0xfULL << NFP::application_id_version_offset);
 }
 
-void NfpDevice::UpdateSettingsCrc() {
+void NfcDevice::UpdateSettingsCrc() {
     auto& settings = tag_data.settings;
 
-    if (settings.crc_counter != counter_limit) {
+    if (settings.crc_counter != NFP::counter_limit) {
         settings.crc_counter++;
     }
 
@@ -1109,7 +1207,7 @@ void NfpDevice::UpdateSettingsCrc() {
     settings.crc = crc.checksum();
 }
 
-void NfpDevice::UpdateRegisterInfoCrc() {
+void NfcDevice::UpdateRegisterInfoCrc() {
 #pragma pack(push, 1)
     struct CrcData {
         Mii::Ver3StoreData mii;
@@ -1134,4 +1232,18 @@ void NfpDevice::UpdateRegisterInfoCrc() {
     tag_data.register_info_crc = crc.checksum();
 }
 
-} // namespace Service::NFP
+u64 NfcDevice::GetHandle() const {
+    // Generate a handle based of the npad id
+    return static_cast<u64>(npad_id);
+}
+
+DeviceState NfcDevice::GetCurrentState() const {
+    return device_state;
+}
+
+Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
+    out_npad_id = npad_id;
+    return ResultSuccess;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
new file mode 100644
index 000000000..654eda98e
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device.h
@@ -0,0 +1,138 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <span>
+
+#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/mifare_types.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/time/clock_types.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(NfcProtocol allowed_protocol);
+    Result StopDetection();
+
+    Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
+
+    Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
+                      std::span<MifareReadBlockData> read_block_data) const;
+    Result ReadMifare(const MifareReadBlockParameter& parameter,
+                      MifareReadBlockData& read_block_data) const;
+
+    Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
+    Result WriteMifare(const MifareWriteBlockParameter& parameter);
+
+    Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
+                                    std::span<const u8> command_data, std::span<u8> out_data);
+
+    Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
+    Result Unmount();
+
+    Result Flush();
+    Result FlushDebug();
+    Result FlushWithBreak(NFP::BreakType break_type);
+    Result Restore();
+
+    Result GetCommonInfo(NFP::CommonInfo& common_info) const;
+    Result GetModelInfo(NFP::ModelInfo& model_info) const;
+    Result GetRegisterInfo(NFP::RegisterInfo& register_info) const;
+    Result GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const;
+    Result GetAdminInfo(NFP::AdminInfo& admin_info) const;
+
+    Result DeleteRegisterInfo();
+    Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
+    Result RestoreAmiibo();
+    Result Format();
+
+    Result OpenApplicationArea(u32 access_id);
+    Result GetApplicationAreaId(u32& application_area_id) const;
+    Result GetApplicationArea(std::span<u8> data) const;
+    Result SetApplicationArea(std::span<const u8> data);
+    Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
+    Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
+    Result DeleteApplicationArea();
+    Result ExistsApplicationArea(bool& has_application_area) const;
+
+    Result GetAll(NFP::NfpData& data) const;
+    Result SetAll(const NFP::NfpData& data);
+    Result BreakTag(NFP::BreakType break_type);
+    Result ReadBackupData(std::span<u8> data) const;
+    Result WriteBackupData(std::span<const u8> data);
+    Result WriteNtf(std::span<const u8> data);
+
+    u64 GetHandle() const;
+    DeviceState GetCurrentState() const;
+    Result GetNpadId(Core::HID::NpadIdType& out_npad_id) 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();
+
+    NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
+    void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
+    NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
+    u64 RemoveVersionByte(u64 application_id) const;
+    void UpdateSettingsCrc();
+    void UpdateRegisterInfoCrc();
+
+    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;
+
+    bool is_initalized{};
+    NfcProtocol allowed_protocols{};
+    DeviceState device_state{DeviceState::Unavailable};
+
+    // NFP data
+    bool is_data_moddified{};
+    bool is_app_area_open{};
+    bool is_plain_amiibo{};
+    s64 current_posix_time{};
+    NFP::MountTarget mount_target{NFP::MountTarget::None};
+
+    NFP::NTAG215File tag_data{};
+    std::vector<u8> mifare_data{};
+    NFP::EncryptedNTAG215File encrypted_tag_data{};
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
new file mode 100644
index 000000000..d5deaaf27
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -0,0 +1,695 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+    : system{system_}, service_context{service_context_} {
+
+    availability_change_event =
+        service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
+
+    for (u32 device_index = 0; device_index < devices.size(); device_index++) {
+        devices[device_index] =
+            std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
+                                        service_context, availability_change_event);
+    }
+
+    is_initialized = false;
+}
+
+DeviceManager ::~DeviceManager() {
+    service_context.CloseEvent(availability_change_event);
+}
+
+Result DeviceManager::Initialize() {
+    for (auto& device : devices) {
+        device->Initialize();
+    }
+    is_initialized = true;
+    return ResultSuccess;
+}
+
+Result DeviceManager::Finalize() {
+    for (auto& device : devices) {
+        device->Finalize();
+    }
+    is_initialized = false;
+    return ResultSuccess;
+}
+
+Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
+                                  std::size_t max_allowed_devices) const {
+    for (auto& device : devices) {
+        if (nfp_devices.size() >= max_allowed_devices) {
+            continue;
+        }
+        if (device->GetCurrentState() != DeviceState::Unavailable) {
+            nfp_devices.push_back(device->GetHandle());
+        }
+    }
+
+    if (nfp_devices.empty()) {
+        return ResultDeviceNotFound;
+    }
+
+    return ResultSuccess;
+}
+
+DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    const auto result = GetDeviceFromHandle(device_handle, device, false);
+
+    if (result.IsSuccess()) {
+        return device->GetCurrentState();
+    }
+
+    return DeviceState::Unavailable;
+}
+
+Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetNpadId(npad_id);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
+    return availability_change_event->GetReadableEvent();
+}
+
+Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->StartDetection(tag_protocol);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::StopDetection(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->StopDetection();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetTagInfo(tag_info, is_mifare);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    GetDeviceFromHandle(device_handle, device, false);
+
+    // TODO: Return proper error code on failure
+    return device->GetActivateEvent();
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    GetDeviceFromHandle(device_handle, device, false);
+
+    // TODO: Return proper error code on failure
+    return device->GetDeactivateEvent();
+}
+
+Result DeviceManager::ReadMifare(u64 device_handle,
+                                 std::span<const MifareReadBlockParameter> read_parameters,
+                                 std::span<MifareReadBlockData> read_data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->ReadMifare(read_parameters, read_data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::WriteMifare(u64 device_handle,
+                                  std::span<const MifareWriteBlockParameter> write_parameters) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->WriteMifare(write_parameters);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
+                                               const Time::Clock::TimeSpanType& timeout,
+                                               std::span<const u8> command_data,
+                                               std::span<u8> out_data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->SendCommandByPassThrough(timeout, command_data, out_data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
+                            NFP::MountTarget mount_target) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->Mount(model_type, mount_target);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::Unmount(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->Unmount();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->OpenApplicationArea(access_id);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetApplicationArea(data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->SetApplicationArea(data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::Flush(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->Flush();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::Restore(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->Restore();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
+                                            std::span<const u8> data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->CreateApplicationArea(access_id, data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetRegisterInfo(register_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetCommonInfo(common_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetModelInfo(model_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+u32 DeviceManager::GetApplicationAreaSize() const {
+    return sizeof(NFP::ApplicationArea);
+}
+
+Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
+                                              std::span<const u8> data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->RecreateApplicationArea(access_id, data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::Format(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->Format();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetAdminInfo(admin_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
+                                             NFP::RegisterInfoPrivate& register_info) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetRegisterInfoPrivate(register_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
+                                             const NFP::RegisterInfoPrivate& register_info) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->SetRegisterInfoPrivate(register_info);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->DeleteRegisterInfo();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->DeleteApplicationArea();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->ExistsApplicationArea(has_application_area);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->GetAll(nfp_data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->SetAll(nfp_data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::FlushDebug(u64 device_handle) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->FlushDebug();
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->BreakTag(break_type);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->ReadBackupData(data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->WriteBackupData(data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
+    std::scoped_lock lock{mutex};
+
+    std::shared_ptr<NfcDevice> device = nullptr;
+    auto result = GetDeviceHandle(device_handle, device);
+
+    if (result.IsSuccess()) {
+        result = device->WriteNtf(data);
+        result = VerifyDeviceResult(device, result);
+    }
+
+    return result;
+}
+
+Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
+                                          bool check_state) const {
+    if (check_state) {
+        const Result is_parameter_set = IsNfcParameterSet();
+        if (is_parameter_set.IsError()) {
+            return is_parameter_set;
+        }
+        const Result is_enabled = IsNfcEnabled();
+        if (is_enabled.IsError()) {
+            return is_enabled;
+        }
+        const Result is_nfc_initialized = IsNfcInitialized();
+        if (is_nfc_initialized.IsError()) {
+            return is_nfc_initialized;
+        }
+    }
+
+    for (auto& device : devices) {
+        if (device->GetHandle() == handle) {
+            nfc_device = device;
+            return ResultSuccess;
+        }
+    }
+
+    return ResultDeviceNotFound;
+}
+
+std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
+    for (auto& device : devices) {
+        if (device->GetHandle() == handle) {
+            return device;
+        }
+    }
+    return std::nullopt;
+}
+
+const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
+    for (auto& device : devices) {
+        if (device->GetHandle() == handle) {
+            return device;
+        }
+    }
+    return std::nullopt;
+}
+
+Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
+    const auto result = GetDeviceFromHandle(handle, device, true);
+    if (result.IsError()) {
+        return result;
+    }
+    return CheckDeviceState(device);
+}
+
+Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
+                                         Result operation_result) const {
+    if (operation_result.IsSuccess()) {
+        return operation_result;
+    }
+
+    const Result is_parameter_set = IsNfcParameterSet();
+    if (is_parameter_set.IsError()) {
+        return is_parameter_set;
+    }
+    const Result is_enabled = IsNfcEnabled();
+    if (is_enabled.IsError()) {
+        return is_enabled;
+    }
+    const Result is_nfc_initialized = IsNfcInitialized();
+    if (is_nfc_initialized.IsError()) {
+        return is_nfc_initialized;
+    }
+    const Result device_state = CheckDeviceState(device);
+    if (device_state.IsError()) {
+        return device_state;
+    }
+
+    return operation_result;
+}
+
+Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
+    if (device == nullptr) {
+        return ResultInvalidArgument;
+    }
+
+    return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcEnabled() const {
+    // TODO: This calls nn::settings::detail::GetNfcEnableFlag
+    const bool is_enabled = true;
+    if (!is_enabled) {
+        return ResultNfcDisabled;
+    }
+    return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcParameterSet() const {
+    // TODO: This calls checks against a bool on offset 0x450
+    const bool is_set = true;
+    if (!is_set) {
+        return ResultUnknown76;
+    }
+    return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcInitialized() const {
+    if (!is_initialized) {
+        return ResultNfcNotInitialized;
+    }
+    return ResultSuccess;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
new file mode 100644
index 000000000..2971e280f
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <optional>
+#include <span>
+
+#include "core/hid/hid_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/mifare_types.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+class NfcDevice;
+
+class DeviceManager {
+public:
+    explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
+    ~DeviceManager();
+
+    // Nfc device manager
+    Result Initialize();
+    Result Finalize();
+    Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
+    DeviceState GetDeviceState(u64 device_handle) const;
+    Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
+    Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
+    Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
+    Result StopDetection(u64 device_handle);
+    Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
+    Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
+    Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
+    Result ReadMifare(u64 device_handle,
+                      const std::span<const MifareReadBlockParameter> read_parameters,
+                      std::span<MifareReadBlockData> read_data);
+    Result WriteMifare(u64 device_handle,
+                       std::span<const MifareWriteBlockParameter> write_parameters);
+    Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
+                                    std::span<const u8> command_data, std::span<u8> out_data);
+
+    // Nfp device manager
+    Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
+    Result Unmount(u64 device_handle);
+    Result OpenApplicationArea(u64 device_handle, u32 access_id);
+    Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
+    Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
+    Result Flush(u64 device_handle);
+    Result Restore(u64 device_handle);
+    Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
+    Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
+    Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
+    Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
+    u32 GetApplicationAreaSize() const;
+    Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
+    Result Format(u64 device_handle);
+    Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
+    Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
+    Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
+    Result DeleteRegisterInfo(u64 device_handle);
+    Result DeleteApplicationArea(u64 device_handle);
+    Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
+    Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
+    Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
+    Result FlushDebug(u64 device_handle);
+    Result BreakTag(u64 device_handle, NFP::BreakType break_type);
+    Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
+    Result WriteBackupData(u64 device_handle, std::span<const u8> data);
+    Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
+
+private:
+    Result IsNfcEnabled() const;
+    Result IsNfcParameterSet() const;
+    Result IsNfcInitialized() const;
+
+    Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
+                               bool check_state) const;
+
+    Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
+    Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
+    Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
+
+    std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
+    const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
+
+    bool is_initialized = false;
+    mutable std::mutex mutex;
+    std::array<std::shared_ptr<NfcDevice>, 10> devices{};
+
+    Core::System& system;
+    KernelHelpers::ServiceContext service_context;
+    Kernel::KEvent* availability_change_event;
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_interface.cpp b/src/core/hle/service/nfc/mifare_interface.cpp
deleted file mode 100644
index 7e6635ba2..000000000
--- a/src/core/hle/service/nfc/mifare_interface.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-// 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/kernel/k_event.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/mifare_interface.h"
-#include "core/hle/service/nfc/nfc_device.h"
-#include "core/hle/service/nfc/nfc_result.h"
-
-namespace Service::NFC {
-
-MFInterface::MFInterface(Core::System& system_, const char* name)
-    : ServiceFramework{system_, name}, service_context{system_, service_name} {
-    availability_change_event = service_context.CreateEvent("MFInterface: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);
-    }
-}
-
-MFInterface ::~MFInterface() {
-    availability_change_event->Close();
-}
-
-void MFInterface::Initialize(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 MFInterface::Finalize(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 MFInterface::ListDevices(HLERequestContext& ctx) {
-    LOG_DEBUG(Service_NFC, "called");
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    if (!ctx.CanWriteBuffer()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareInvalidArgument);
-        return;
-    }
-
-    if (ctx.GetWriteBufferSize() == 0) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareInvalidArgument);
-        return;
-    }
-
-    std::vector<u64> nfp_devices;
-    const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
-
-    for (const auto& device : devices) {
-        if (nfp_devices.size() >= max_allowed_devices) {
-            continue;
-        }
-        if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
-            nfp_devices.push_back(device->GetHandle());
-        }
-    }
-
-    if (nfp_devices.empty()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    ctx.WriteBuffer(nfp_devices);
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.Push(static_cast<s32>(nfp_devices.size()));
-}
-
-void MFInterface::StartDetection(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-void MFInterface::StopDetection(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->StopDetection();
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-void MFInterface::Read(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    const auto buffer{ctx.ReadBuffer()};
-    const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
-    std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
-
-    memcpy(read_commands.data(), buffer.data(),
-           number_of_commands * sizeof(NFP::MifareReadBlockParameter));
-
-    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
-             device_handle, number_of_commands);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    Result result = ResultSuccess;
-    std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
-    for (std::size_t i = 0; i < number_of_commands; i++) {
-        result = device.value()->MifareRead(read_commands[i], out_data[i]);
-        if (result.IsError()) {
-            break;
-        }
-    }
-
-    ctx.WriteBuffer(out_data);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-void MFInterface::Write(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    const auto buffer{ctx.ReadBuffer()};
-    const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
-    std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
-
-    memcpy(write_commands.data(), buffer.data(),
-           number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
-
-    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
-             device_handle, number_of_commands);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    Result result = ResultSuccess;
-    std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
-    for (std::size_t i = 0; i < number_of_commands; i++) {
-        result = device.value()->MifareWrite(write_commands[i]);
-        if (result.IsError()) {
-            break;
-        }
-    }
-
-    if (result.IsSuccess()) {
-        result = device.value()->Flush();
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-void MFInterface::GetTagInfo(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    NFP::TagInfo tag_info{};
-    const auto result = device.value()->GetTagInfo(tag_info, true);
-    ctx.WriteBuffer(tag_info);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-void MFInterface::GetActivateEventHandle(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2, 1};
-    rb.Push(ResultSuccess);
-    rb.PushCopyObjects(device.value()->GetActivateEvent());
-}
-
-void MFInterface::GetDeactivateEventHandle(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2, 1};
-    rb.Push(ResultSuccess);
-    rb.PushCopyObjects(device.value()->GetDeactivateEvent());
-}
-
-void MFInterface::GetState(HLERequestContext& ctx) {
-    LOG_DEBUG(Service_NFC, "called");
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.PushEnum(state);
-}
-
-void MFInterface::GetDeviceState(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.PushEnum(device.value()->GetCurrentState());
-}
-
-void MFInterface::GetNpadId(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    auto device = GetNfcDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareDeviceNotFound);
-        return;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.PushEnum(device.value()->GetNpadId());
-}
-
-void MFInterface::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
-    LOG_INFO(Service_NFC, "called");
-
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(MifareNfcDisabled);
-        return;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2, 1};
-    rb.Push(ResultSuccess);
-    rb.PushCopyObjects(availability_change_event->GetReadableEvent());
-}
-
-std::optional<std::shared_ptr<NfcDevice>> MFInterface::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/mifare_interface.h b/src/core/hle/service/nfc/mifare_interface.h
deleted file mode 100644
index 698c8a6b6..000000000
--- a/src/core/hle/service/nfc/mifare_interface.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// 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 MFInterface : public ServiceFramework<MFInterface> {
-public:
-    explicit MFInterface(Core::System& system_, const char* name);
-    ~MFInterface();
-
-    void Initialize(HLERequestContext& ctx);
-    void Finalize(HLERequestContext& ctx);
-    void ListDevices(HLERequestContext& ctx);
-    void StartDetection(HLERequestContext& ctx);
-    void StopDetection(HLERequestContext& ctx);
-    void Read(HLERequestContext& ctx);
-    void Write(HLERequestContext& ctx);
-    void GetTagInfo(HLERequestContext& ctx);
-    void GetActivateEventHandle(HLERequestContext& ctx);
-    void GetDeactivateEventHandle(HLERequestContext& ctx);
-    void GetState(HLERequestContext& ctx);
-    void GetDeviceState(HLERequestContext& ctx);
-    void GetNpadId(HLERequestContext& ctx);
-    void GetAvailabilityChangeEventHandle(HLERequestContext& ctx);
-
-private:
-    enum class State : u32 {
-        NonInitialized,
-        Initialized,
-    };
-
-    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/nfc/mifare_result.h b/src/core/hle/service/nfc/mifare_result.h
new file mode 100644
index 000000000..4b60048a5
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_result.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::NFC::Mifare {
+
+constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
+constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
+constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
+constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
+
+} // namespace Service::NFC::Mifare
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h
new file mode 100644
index 000000000..75b59f021
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_types.h
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Service::NFC {
+
+enum class MifareCmd : u8 {
+    AuthA = 0x60,
+    AuthB = 0x61,
+    Read = 0x30,
+    Write = 0xA0,
+    Transfer = 0xB0,
+    Decrement = 0xC0,
+    Increment = 0xC1,
+    Store = 0xC2
+};
+
+using DataBlock = std::array<u8, 0x10>;
+using KeyData = std::array<u8, 0x6>;
+
+struct SectorKey {
+    MifareCmd command;
+    u8 unknown; // Usually 1
+    INSERT_PADDING_BYTES(0x6);
+    KeyData sector_key;
+    INSERT_PADDING_BYTES(0x2);
+};
+static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
+
+// This is nn::nfc::MifareReadBlockParameter
+struct MifareReadBlockParameter {
+    u8 sector_number;
+    INSERT_PADDING_BYTES(0x7);
+    SectorKey sector_key;
+};
+static_assert(sizeof(MifareReadBlockParameter) == 0x18,
+              "MifareReadBlockParameter is an invalid size");
+
+// This is nn::nfc::MifareReadBlockData
+struct MifareReadBlockData {
+    DataBlock data;
+    u8 sector_number;
+    INSERT_PADDING_BYTES(0x7);
+};
+static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
+
+// This is nn::nfc::MifareWriteBlockParameter
+struct MifareWriteBlockParameter {
+    DataBlock data;
+    u8 sector_number;
+    INSERT_PADDING_BYTES(0x7);
+    SectorKey sector_key;
+};
+static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
+              "MifareWriteBlockParameter is an invalid size");
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 444d65f07..30ae989b9 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -6,7 +6,6 @@
 #include "common/logging/log.h"
 #include "common/settings.h"
 #include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/mifare_interface.h"
 #include "core/hle/service/nfc/nfc.h"
 #include "core/hle/service/nfc/nfc_interface.h"
 #include "core/hle/service/server_manager.h"
@@ -14,31 +13,31 @@
 
 namespace Service::NFC {
 
-class IUser final : public Interface {
+class IUser final : public NfcInterface {
 public:
-    explicit IUser(Core::System& system_) : Interface(system_, "NFC::IUser") {
+    explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &Interface::Initialize, "InitializeOld"},
-            {1, &Interface::Finalize, "FinalizeOld"},
-            {2, &Interface::GetState, "GetStateOld"},
-            {3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"},
-            {400, &Interface::Initialize, "Initialize"},
-            {401, &Interface::Finalize, "Finalize"},
-            {402, &Interface::GetState, "GetState"},
-            {403, &Interface::IsNfcEnabled, "IsNfcEnabled"},
-            {404, &Interface::ListDevices, "ListDevices"},
-            {405, &Interface::GetDeviceState, "GetDeviceState"},
-            {406, &Interface::GetNpadId, "GetNpadId"},
-            {407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
-            {408, &Interface::StartDetection, "StartDetection"},
-            {409, &Interface::StopDetection, "StopDetection"},
-            {410, &Interface::GetTagInfo, "GetTagInfo"},
-            {411, &Interface::AttachActivateEvent, "AttachActivateEvent"},
-            {412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"},
-            {1000, nullptr, "ReadMifare"},
-            {1001, nullptr, "WriteMifare"},
-            {1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+            {0, &NfcInterface::Initialize, "InitializeOld"},
+            {1, &NfcInterface::Finalize, "FinalizeOld"},
+            {2, &NfcInterface::GetState, "GetStateOld"},
+            {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
+            {400, &NfcInterface::Initialize, "Initialize"},
+            {401, &NfcInterface::Finalize, "Finalize"},
+            {402, &NfcInterface::GetState, "GetState"},
+            {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
+            {404, &NfcInterface::ListDevices, "ListDevices"},
+            {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
+            {406, &NfcInterface::GetNpadId, "GetNpadId"},
+            {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+            {408, &NfcInterface::StartDetection, "StartDetection"},
+            {409, &NfcInterface::StopDetection, "StopDetection"},
+            {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
+            {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
+            {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+            {1000, &NfcInterface::ReadMifare, "ReadMifare"},
+            {1001, &NfcInterface::WriteMifare ,"WriteMifare"},
+            {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
             {1301, nullptr, "KeepPassThroughSession"},
             {1302, nullptr, "ReleasePassThroughSession"},
         };
@@ -48,34 +47,35 @@ public:
     }
 };
 
-class ISystem final : public Interface {
+class ISystem final : public NfcInterface {
 public:
-    explicit ISystem(Core::System& system_) : Interface{system_, "NFC::ISystem"} {
+    explicit ISystem(Core::System& system_)
+        : NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &Interface::Initialize, "InitializeOld"},
-            {1, &Interface::Finalize, "FinalizeOld"},
-            {2, &Interface::GetState, "GetStateOld"},
-            {3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"},
+            {0, &NfcInterface::Initialize, "InitializeOld"},
+            {1, &NfcInterface::Finalize, "FinalizeOld"},
+            {2, &NfcInterface::GetState, "GetStateOld"},
+            {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
             {100, nullptr, "SetNfcEnabledOld"},
-            {400, &Interface::Initialize, "Initialize"},
-            {401, &Interface::Finalize, "Finalize"},
-            {402, &Interface::GetState, "GetState"},
-            {403, &Interface::IsNfcEnabled, "IsNfcEnabled"},
-            {404, &Interface::ListDevices, "ListDevices"},
-            {405, &Interface::GetDeviceState, "GetDeviceState"},
-            {406, &Interface::GetNpadId, "GetNpadId"},
-            {407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
-            {408, &Interface::StartDetection, "StartDetection"},
-            {409, &Interface::StopDetection, "StopDetection"},
-            {410, &Interface::GetTagInfo, "GetTagInfo"},
-            {411, &Interface::AttachActivateEvent, "AttachActivateEvent"},
-            {412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+            {400, &NfcInterface::Initialize, "Initialize"},
+            {401, &NfcInterface::Finalize, "Finalize"},
+            {402, &NfcInterface::GetState, "GetState"},
+            {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
+            {404, &NfcInterface::ListDevices, "ListDevices"},
+            {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
+            {406, &NfcInterface::GetNpadId, "GetNpadId"},
+            {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+            {408, &NfcInterface::StartDetection, "StartDetection"},
+            {409, &NfcInterface::StopDetection, "StopDetection"},
+            {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
+            {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
+            {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
             {500, nullptr, "SetNfcEnabled"},
             {510, nullptr, "OutputTestWave"},
-            {1000, nullptr, "ReadMifare"},
-            {1001, nullptr, "WriteMifare"},
-            {1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+            {1000, &NfcInterface::ReadMifare, "ReadMifare"},
+            {1001, &NfcInterface::WriteMifare, "WriteMifare"},
+            {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
             {1301, nullptr, "KeepPassThroughSession"},
             {1302, nullptr, "ReleasePassThroughSession"},
         };
@@ -85,25 +85,29 @@ public:
     }
 };
 
+// MFInterface has an unique interface but it's identical to NfcInterface so we can keep the code
+// simpler
+using MFInterface = NfcInterface;
 class MFIUser final : public MFInterface {
 public:
-    explicit MFIUser(Core::System& system_) : MFInterface{system_, "NFC::MFInterface"} {
+    explicit MFIUser(Core::System& system_)
+        : MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
         // clang-format off
-        static const FunctionInfo functions[] = {
+        static const FunctionInfoTyped<MFIUser> functions[] = {
             {0, &MFIUser::Initialize, "Initialize"},
             {1, &MFIUser::Finalize, "Finalize"},
             {2, &MFIUser::ListDevices, "ListDevices"},
             {3, &MFIUser::StartDetection, "StartDetection"},
             {4, &MFIUser::StopDetection, "StopDetection"},
-            {5, &MFIUser::Read, "Read"},
-            {6, &MFIUser::Write, "Write"},
+            {5, &MFIUser::ReadMifare, "Read"},
+            {6, &MFIUser::WriteMifare, "Write"},
             {7, &MFIUser::GetTagInfo, "GetTagInfo"},
-            {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
-            {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
+            {8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
+            {9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
             {10, &MFIUser::GetState, "GetState"},
             {11, &MFIUser::GetDeviceState, "GetDeviceState"},
             {12, &MFIUser::GetNpadId, "GetNpadId"},
-            {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
+            {13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
         };
         // clang-format on
 
@@ -131,7 +135,7 @@ public:
     explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
+            {0, &NFC_AM::CreateAmNfcInterface, "CreateAmNfcInterface"},
         };
         // clang-format on
 
@@ -139,7 +143,7 @@ public:
     }
 
 private:
-    void CreateAmInterface(HLERequestContext& ctx) {
+    void CreateAmNfcInterface(HLERequestContext& ctx) {
         LOG_DEBUG(Service_NFC, "called");
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -153,7 +157,7 @@ public:
     explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
+            {0, &NFC_MF_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
         };
         // clang-format on
 
@@ -161,7 +165,7 @@ public:
     }
 
 private:
-    void CreateUserInterface(HLERequestContext& ctx) {
+    void CreateUserNfcInterface(HLERequestContext& ctx) {
         LOG_DEBUG(Service_NFC, "called");
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -175,7 +179,7 @@ public:
     explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
+            {0, &NFC_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
         };
         // clang-format on
 
@@ -183,7 +187,7 @@ public:
     }
 
 private:
-    void CreateUserInterface(HLERequestContext& ctx) {
+    void CreateUserNfcInterface(HLERequestContext& ctx) {
         LOG_DEBUG(Service_NFC, "called");
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -197,7 +201,7 @@ public:
     explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
         // clang-format off
         static const FunctionInfo functions[] = {
-            {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
+            {0, &NFC_SYS::CreateSystemNfcInterface, "CreateSystemNfcInterface"},
         };
         // clang-format on
 
@@ -205,7 +209,7 @@ public:
     }
 
 private:
-    void CreateSystemInterface(HLERequestContext& ctx) {
+    void CreateSystemNfcInterface(HLERequestContext& ctx) {
         LOG_DEBUG(Service_NFC, "called");
 
         IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -221,6 +225,7 @@ void LoopProcess(Core::System& system) {
     server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system));
     server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system));
     server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system));
+
     ServerManager::RunServer(std::move(server_manager));
 }
 
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
deleted file mode 100644
index 47bc1a05d..000000000
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-// 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/kernel/k_event.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/nfc_device.h"
-#include "core/hle/service/nfc/nfc_result.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 (!is_initalized) {
-        return;
-    }
-
-    if (type == Core::HID::ControllerTriggerType::Connected) {
-        Initialize();
-        availability_change_event->Signal();
-        return;
-    }
-
-    if (type == Core::HID::ControllerTriggerType::Disconnected) {
-        device_state = NFP::DeviceState::Unavailable;
-        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;
-    }
-
-    tag_data.resize(data.size());
-    memcpy(tag_data.data(), data.data(), data.size());
-    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 = {};
-    is_initalized = true;
-}
-
-void NfcDevice::Finalize() {
-    if (device_state == NFP::DeviceState::SearchingForTag ||
-        device_state == NFP::DeviceState::TagRemoved) {
-        StopDetection();
-    }
-    device_state = NFP::DeviceState::Unavailable;
-    is_initalized = false;
-}
-
-Result NfcDevice::StartDetection(NFP::TagProtocol allowed_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(Core::HID::EmulatedDeviceIndex::RightIndex,
-                                    Common::Input::PollingMode::NFC) !=
-        Common::Input::DriverResult::Success) {
-        LOG_ERROR(Service_NFC, "Nfc not supported");
-        return NfcDisabled;
-    }
-
-    device_state = NFP::DeviceState::SearchingForTag;
-    allowed_protocols = allowed_protocol;
-    return ResultSuccess;
-}
-
-Result NfcDevice::StopDetection() {
-    npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
-                                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::Flush() {
-    if (device_state != NFP::DeviceState::TagFound &&
-        device_state != NFP::DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
-        if (device_state == NFP::DeviceState::TagRemoved) {
-            return TagRemoved;
-        }
-        return WrongDeviceState;
-    }
-
-    if (!npad_device->WriteNfc(tag_data)) {
-        LOG_ERROR(Service_NFP, "Error writing to file");
-        return MifareReadError;
-    }
-
-    return ResultSuccess;
-}
-
-Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
-    if (device_state != NFP::DeviceState::TagFound &&
-        device_state != NFP::DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
-        if (device_state == NFP::DeviceState::TagRemoved) {
-            return TagRemoved;
-        }
-        return WrongDeviceState;
-    }
-
-    if (is_mifare) {
-        tag_info = {
-            .uuid = encrypted_tag_data.uuid.uid,
-            .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
-            .protocol = NFP::TagProtocol::TypeA,
-            .tag_type = NFP::TagType::Type4,
-        };
-        return ResultSuccess;
-    }
-
-    // Protocol and tag type may change here
-    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;
-}
-
-Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
-                             NFP::MifareReadBlockData& read_block_data) {
-    const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
-    read_block_data.sector_number = parameter.sector_number;
-
-    if (device_state != NFP::DeviceState::TagFound &&
-        device_state != NFP::DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
-        if (device_state == NFP::DeviceState::TagRemoved) {
-            return TagRemoved;
-        }
-        return WrongDeviceState;
-    }
-
-    if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
-        return MifareReadError;
-    }
-
-    // TODO: Use parameter.sector_key to read encrypted data
-    memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
-
-    return ResultSuccess;
-}
-
-Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
-    const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
-
-    if (device_state != NFP::DeviceState::TagFound &&
-        device_state != NFP::DeviceState::TagMounted) {
-        LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
-        if (device_state == NFP::DeviceState::TagRemoved) {
-            return TagRemoved;
-        }
-        return WrongDeviceState;
-    }
-
-    if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
-        return MifareReadError;
-    }
-
-    // TODO: Use parameter.sector_key to encrypt the data
-    memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
-
-    return ResultSuccess;
-}
-
-u64 NfcDevice::GetHandle() const {
-    // 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
deleted file mode 100644
index ea63f0537..000000000
--- a/src/core/hle/service/nfc/nfc_device.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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(NFP::TagProtocol allowed_protocol);
-    Result StopDetection();
-    Result Flush();
-
-    Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
-
-    Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
-                      NFP::MifareReadBlockData& read_block_data);
-
-    Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
-
-    u64 GetHandle() const;
-    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;
-
-    bool is_initalized{};
-    NFP::TagProtocol allowed_protocols{};
-    NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
-
-    NFP::EncryptedNTAG215File encrypted_tag_data{};
-    std::vector<u8> tag_data{};
-};
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index be96d0cbc..0fa29d398 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -6,55 +6,56 @@
 #include "core/hid/hid_types.h"
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nfc/nfc_device.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/mifare_result.h"
+#include "core/hle/service/nfc/mifare_types.h"
 #include "core/hle/service/nfc/nfc_interface.h"
 #include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_result.h"
 #include "core/hle/service/time/clock_types.h"
 
 namespace Service::NFC {
 
-Interface::Interface(Core::System& system_, const char* name)
-    : ServiceFramework{system_, name}, service_context{system_, service_name} {
-    availability_change_event = service_context.CreateEvent("Interface:AvailabilityChangeEvent");
+NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
+    : ServiceFramework{system_, name}, service_context{system_, service_name},
+      backend_type{service_backend} {}
 
-    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);
-    }
-}
+NfcInterface ::~NfcInterface() = default;
 
-Interface ::~Interface() {
-    availability_change_event->Close();
-}
-
-void Interface::Initialize(HLERequestContext& ctx) {
+void NfcInterface::Initialize(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
-    state = State::Initialized;
+    auto manager = GetManager();
+    auto result = manager->Initialize();
 
-    for (auto& device : devices) {
-        device->Initialize();
+    if (result.IsSuccess()) {
+        state = State::Initialized;
+    } else {
+        manager->Finalize();
     }
 
     IPC::ResponseBuilder rb{ctx, 2, 0};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
-void Interface::Finalize(HLERequestContext& ctx) {
+void NfcInterface::Finalize(HLERequestContext& ctx) {
     LOG_INFO(Service_NFC, "called");
 
-    state = State::NonInitialized;
-
-    for (auto& device : devices) {
-        device->Finalize();
+    if (state != State::NonInitialized) {
+        if (GetBackendType() != BackendType::None) {
+            GetManager()->Finalize();
+        }
+        device_manager = nullptr;
+        state = State::NonInitialized;
     }
 
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(ResultSuccess);
 }
 
-void Interface::GetState(HLERequestContext& ctx) {
+void NfcInterface::GetState(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
     IPC::ResponseBuilder rb{ctx, 3};
@@ -62,50 +63,28 @@ void Interface::GetState(HLERequestContext& ctx) {
     rb.PushEnum(state);
 }
 
-void Interface::IsNfcEnabled(HLERequestContext& ctx) {
+void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
     LOG_DEBUG(Service_NFC, "called");
 
+    // TODO: This calls nn::settings::detail::GetNfcEnableFlag
+    const bool is_enabled = true;
+
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(state != State::NonInitialized);
+    rb.Push(is_enabled);
 }
 
-void Interface::ListDevices(HLERequestContext& ctx) {
-    LOG_DEBUG(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;
-    }
-
+void NfcInterface::ListDevices(HLERequestContext& ctx) {
     std::vector<u64> nfp_devices;
     const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
+    LOG_DEBUG(Service_NFC, "called");
 
-    for (auto& device : devices) {
-        if (nfp_devices.size() >= max_allowed_devices) {
-            continue;
-        }
-        if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
-            nfp_devices.push_back(device->GetHandle());
-        }
-    }
+    auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
+    result = TranslateResultToServiceError(result);
 
-    if (nfp_devices.empty()) {
+    if (result.IsError()) {
         IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
+        rb.Push(result);
         return;
     }
 
@@ -116,210 +95,177 @@ void Interface::ListDevices(HLERequestContext& ctx) {
     rb.Push(static_cast<s32>(nfp_devices.size()));
 }
 
-void Interface::GetDeviceState(HLERequestContext& ctx) {
+void NfcInterface::GetDeviceState(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);
+    const auto device_state = GetManager()->GetDeviceState(device_handle);
 
-    if (!device.has_value()) {
+    if (device_state > DeviceState::Finalized) {
+        ASSERT_MSG(false, "Invalid device state");
+    }
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(ResultSuccess);
+    rb.PushEnum(device_state);
+}
+
+void NfcInterface::GetNpadId(HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto device_handle{rp.Pop<u64>()};
+    LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+    Core::HID::NpadIdType npad_id{};
+    auto result = GetManager()->GetNpadId(device_handle, npad_id);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsError()) {
         IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
+        rb.Push(result);
         return;
     }
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.PushEnum(device.value()->GetCurrentState());
+    rb.PushEnum(npad_id);
 }
 
-void Interface::GetNpadId(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 Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
+void NfcInterface::AttachAvailabilityChangeEvent(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());
+    rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
 }
 
-void Interface::StartDetection(HLERequestContext& ctx) {
+void NfcInterface::StartDetection(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
-    LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
+    const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
+    LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->StartDetection(device_handle, tag_protocol);
+    result = TranslateResultToServiceError(result);
 
-    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 Interface::StopDetection(HLERequestContext& ctx) {
+void NfcInterface::StopDetection(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 result = GetManager()->StopDetection(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    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 Interface::GetTagInfo(HLERequestContext& ctx) {
+void NfcInterface::GetTagInfo(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;
+    TagInfo tag_info{};
+    auto result =
+        GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(tag_info);
     }
 
-    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, false);
-    ctx.WriteBuffer(tag_info);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
 
-void Interface::AttachActivateEvent(HLERequestContext& ctx) {
+void NfcInterface::AttachActivateEvent(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());
+    rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
 }
 
-void Interface::AttachDeactivateEvent(HLERequestContext& ctx) {
+void NfcInterface::AttachDeactivateEvent(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());
+    rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
 }
 
-void Interface::SendCommandByPassThrough(HLERequestContext& ctx) {
+void NfcInterface::ReadMifare(HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto device_handle{rp.Pop<u64>()};
+    const auto buffer{ctx.ReadBuffer()};
+    const auto number_of_commands{ctx.GetReadBufferNumElements<MifareReadBlockParameter>()};
+    std::vector<MifareReadBlockParameter> read_commands(number_of_commands);
+
+    memcpy(read_commands.data(), buffer.data(),
+           number_of_commands * sizeof(MifareReadBlockParameter));
+
+    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
+             device_handle, number_of_commands);
+
+    std::vector<MifareReadBlockData> out_data(number_of_commands);
+    auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(out_data);
+    }
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
+void NfcInterface::WriteMifare(HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto device_handle{rp.Pop<u64>()};
+    const auto buffer{ctx.ReadBuffer()};
+    const auto number_of_commands{ctx.GetReadBufferNumElements<MifareWriteBlockParameter>()};
+    std::vector<MifareWriteBlockParameter> write_commands(number_of_commands);
+
+    memcpy(write_commands.data(), buffer.data(),
+           number_of_commands * sizeof(MifareWriteBlockParameter));
+
+    LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
+             device_handle, number_of_commands);
+
+    auto result = GetManager()->WriteMifare(device_handle, write_commands);
+    result = TranslateResultToServiceError(result);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
+void NfcInterface::SendCommandByPassThrough(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
+    auto result =
+        GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsError()) {
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(result);
+        return;
+    }
+
     ctx.WriteBuffer(out_data);
 
     IPC::ResponseBuilder rb{ctx, 3};
@@ -327,13 +273,110 @@ void Interface::SendCommandByPassThrough(HLERequestContext& ctx) {
     rb.Push(static_cast<u32>(out_data.size()));
 }
 
-std::optional<std::shared_ptr<NfcDevice>> Interface::GetNfcDevice(u64 handle) {
-    for (auto& device : devices) {
-        if (device->GetHandle() == handle) {
-            return device;
-        }
+std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
+    if (device_manager == nullptr) {
+        device_manager = std::make_shared<DeviceManager>(system, service_context);
     }
-    return std::nullopt;
+    return device_manager;
+}
+
+BackendType NfcInterface::GetBackendType() const {
+    return backend_type;
+}
+
+Result NfcInterface::TranslateResultToServiceError(Result result) const {
+    const auto backend = GetBackendType();
+
+    if (result.IsSuccess()) {
+        return result;
+    }
+
+    if (result.module != ErrorModule::NFC) {
+        return result;
+    }
+
+    switch (backend) {
+    case BackendType::Mifare:
+        return TranslateResultToNfp(result);
+    case BackendType::Nfp: {
+        return TranslateResultToNfp(result);
+    }
+    default:
+        if (result != ResultUnknown216) {
+            return result;
+        }
+        return ResultUnknown74;
+    }
+}
+
+Result NfcInterface::TranslateResultToNfp(Result result) const {
+    if (result == ResultDeviceNotFound) {
+        return NFP::ResultDeviceNotFound;
+    }
+    if (result == ResultInvalidArgument) {
+        return NFP::ResultInvalidArgument;
+    }
+    if (result == ResultWrongApplicationAreaSize) {
+        return NFP::ResultWrongApplicationAreaSize;
+    }
+    if (result == ResultWrongDeviceState) {
+        return NFP::ResultWrongDeviceState;
+    }
+    if (result == ResultUnknown74) {
+        return NFP::ResultUnknown74;
+    }
+    if (result == ResultNfcDisabled) {
+        return NFP::ResultNfcDisabled;
+    }
+    if (result == ResultNfcNotInitialized) {
+        return NFP::ResultNfcDisabled;
+    }
+    if (result == ResultWriteAmiiboFailed) {
+        return NFP::ResultWriteAmiiboFailed;
+    }
+    if (result == ResultTagRemoved) {
+        return NFP::ResultTagRemoved;
+    }
+    if (result == ResultRegistrationIsNotInitialized) {
+        return NFP::ResultRegistrationIsNotInitialized;
+    }
+    if (result == ResultApplicationAreaIsNotInitialized) {
+        return NFP::ResultApplicationAreaIsNotInitialized;
+    }
+    if (result == ResultCorruptedData) {
+        return NFP::ResultCorruptedData;
+    }
+    if (result == ResultWrongApplicationAreaId) {
+        return NFP::ResultWrongApplicationAreaId;
+    }
+    if (result == ResultApplicationAreaExist) {
+        return NFP::ResultApplicationAreaExist;
+    }
+    if (result == ResultNotAnAmiibo) {
+        return NFP::ResultNotAnAmiibo;
+    }
+    LOG_WARNING(Service_NFC, "Result conversion not handled");
+    return result;
+}
+
+Result NfcInterface::TranslateResultToMifare(Result result) const {
+    if (result == ResultDeviceNotFound) {
+        return Mifare::ResultDeviceNotFound;
+    }
+    if (result == ResultInvalidArgument) {
+        return Mifare::ResultInvalidArgument;
+    }
+    if (result == ResultWrongDeviceState) {
+        return Mifare::ResultWrongDeviceState;
+    }
+    if (result == ResultNfcDisabled) {
+        return Mifare::ResultNfcDisabled;
+    }
+    if (result == ResultTagRemoved) {
+        return Mifare::ResultTagRemoved;
+    }
+    LOG_WARNING(Service_NFC, "Result conversion not handled");
+    return result;
 }
 
 } // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_interface.h b/src/core/hle/service/nfc/nfc_interface.h
index 8c1bf5a59..08be174d8 100644
--- a/src/core/hle/service/nfc/nfc_interface.h
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -3,20 +3,17 @@
 
 #pragma once
 
-#include <array>
-#include <memory>
-#include <optional>
-
 #include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/nfc_types.h"
 #include "core/hle/service/service.h"
 
 namespace Service::NFC {
-class NfcDevice;
+class DeviceManager;
 
-class Interface : public ServiceFramework<Interface> {
+class NfcInterface : public ServiceFramework<NfcInterface> {
 public:
-    explicit Interface(Core::System& system_, const char* name);
-    ~Interface();
+    explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
+    ~NfcInterface();
 
     void Initialize(HLERequestContext& ctx);
     void Finalize(HLERequestContext& ctx);
@@ -31,22 +28,22 @@ public:
     void GetTagInfo(HLERequestContext& ctx);
     void AttachActivateEvent(HLERequestContext& ctx);
     void AttachDeactivateEvent(HLERequestContext& ctx);
+    void ReadMifare(HLERequestContext& ctx);
+    void WriteMifare(HLERequestContext& ctx);
     void SendCommandByPassThrough(HLERequestContext& ctx);
 
-private:
-    enum class State : u32 {
-        NonInitialized,
-        Initialized,
-    };
-
-    std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
+protected:
+    std::shared_ptr<DeviceManager> GetManager();
+    BackendType GetBackendType() const;
+    Result TranslateResultToServiceError(Result result) const;
+    Result TranslateResultToNfp(Result result) const;
+    Result TranslateResultToMifare(Result result) const;
 
     KernelHelpers::ServiceContext service_context;
 
-    std::array<std::shared_ptr<NfcDevice>, 10> devices{};
-
+    BackendType backend_type;
     State state{State::NonInitialized};
-    Kernel::KEvent* availability_change_event;
+    std::shared_ptr<DeviceManager> device_manager = nullptr;
 };
 
 } // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 146b8ba61..917d79ef8 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -1,5 +1,5 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
 
 #pragma once
 
@@ -7,17 +7,22 @@
 
 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 MifareDeviceNotFound(ErrorModule::NFCMifare, 64);
-constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65);
-constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73);
-constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80);
-constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97);
-constexpr Result MifareReadError(ErrorModule::NFCMifare, 288);
+constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
+constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
+constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
+constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
+constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
+constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
+constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
 
 } // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h
new file mode 100644
index 000000000..c7ebd1fdb
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_types.h
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Service::NFC {
+enum class BackendType : u32 {
+    None,
+    Nfc,
+    Nfp,
+    Mifare,
+};
+
+// This is nn::nfc::DeviceState
+enum class DeviceState : u32 {
+    Initialized,
+    SearchingForTag,
+    TagFound,
+    TagRemoved,
+    TagMounted,
+    Unavailable,
+    Finalized,
+};
+
+// This is nn::nfc::State
+enum class State : u32 {
+    NonInitialized,
+    Initialized,
+};
+
+// This is nn::nfc::TagType
+enum class TagType : u32 {
+    None,
+    Type1, // ISO14443A RW 96-2k bytes 106kbit/s
+    Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
+    Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
+    Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
+    Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
+};
+
+enum class PackedTagType : u8 {
+    None,
+    Type1, // ISO14443A RW 96-2k bytes 106kbit/s
+    Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
+    Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
+    Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
+    Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
+};
+
+// This is nn::nfc::NfcProtocol
+// Verify this enum. It might be completely wrong default protocol is 0x48
+enum class NfcProtocol : u32 {
+    None,
+    TypeA = 1U << 0, // ISO14443A
+    TypeB = 1U << 1, // ISO14443B
+    TypeF = 1U << 2, // Sony FeliCa
+    Unknown1 = 1U << 3,
+    Unknown2 = 1U << 5,
+    All = 0xFFFFFFFFU,
+};
+
+// this is nn::nfc::TestWaveType
+enum class TestWaveType : u32 {
+    Unknown,
+};
+
+using UniqueSerialNumber = std::array<u8, 7>;
+using UniqueSerialNumberExtension = std::array<u8, 3>;
+
+// This is nn::nfc::DeviceHandle
+using DeviceHandle = u64;
+
+// This is nn::nfc::TagInfo
+struct TagInfo {
+    UniqueSerialNumber uuid;
+    UniqueSerialNumberExtension uuid_extension;
+    u8 uuid_length;
+    INSERT_PADDING_BYTES(0x15);
+    NfcProtocol protocol;
+    TagType tag_type;
+    INSERT_PADDING_BYTES(0x30);
+};
+static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 2559fe598..2eeabc138 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -13,7 +13,7 @@ class IUser final : public Interface {
 public:
     explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
         // clang-format off
-        static const FunctionInfo functions[] = {
+        static const FunctionInfoTyped<IUser> functions[] = {
             {0, &IUser::Initialize, "Initialize"},
             {1, &IUser::Finalize, "Finalize"},
             {2, &IUser::ListDevices, "ListDevices"},
@@ -50,7 +50,7 @@ class ISystem final : public Interface {
 public:
     explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
         // clang-format off
-        static const FunctionInfo functions[] = {
+        static const FunctionInfoTyped<ISystem> functions[] = {
             {0, &ISystem::InitializeSystem, "InitializeSystem"},
             {1, &ISystem::FinalizeSystem, "FinalizeSystem"},
             {2, &ISystem::ListDevices, "ListDevices"},
@@ -89,7 +89,7 @@ class IDebug final : public Interface {
 public:
     explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
         // clang-format off
-        static const FunctionInfo functions[] = {
+        static const FunctionInfoTyped<IDebug> functions[] = {
             {0, &IDebug::InitializeDebug, "InitializeDebug"},
             {1, &IDebug::FinalizeDebug, "FinalizeDebug"},
             {2, &IDebug::ListDevices, "ListDevices"},
@@ -126,9 +126,9 @@ public:
             {201, &IDebug::SetAll, "SetAll"},
             {202, &IDebug::FlushDebug, "FlushDebug"},
             {203, &IDebug::BreakTag, "BreakTag"},
-            {204, nullptr, "ReadBackupData"},
-            {205, nullptr, "WriteBackupData"},
-            {206, nullptr, "WriteNtf"},
+            {204, &IDebug::ReadBackupData, "ReadBackupData"},
+            {205, &IDebug::WriteBackupData, "WriteBackupData"},
+            {206, &IDebug::WriteNtf, "WriteNtf"},
         };
         // clang-format on
 
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
deleted file mode 100644
index bab05538a..000000000
--- a/src/core/hle/service/nfp/nfp_device.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <span>
-#include <vector>
-
-#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::NFP {
-class NfpDevice {
-public:
-    NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
-              KernelHelpers::ServiceContext& service_context_,
-              Kernel::KEvent* availability_change_event_);
-    ~NfpDevice();
-
-    void Initialize();
-    void Finalize();
-
-    Result StartDetection(TagProtocol allowed_protocol);
-    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();
-    Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name);
-    Result RestoreAmiibo();
-    Result Format();
-
-    Result OpenApplicationArea(u32 access_id);
-    Result GetApplicationAreaId(u32& application_area_id) const;
-    Result GetApplicationArea(std::vector<u8>& data) const;
-    Result SetApplicationArea(std::span<const u8> data);
-    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;
-    DeviceState GetCurrentState() const;
-    Core::HID::NpadIdType GetNpadId() const;
-
-    Kernel::KReadableEvent& GetActivateEvent() const;
-    Kernel::KReadableEvent& GetDeactivateEvent() const;
-
-private:
-    void NpadUpdate(Core::HID::ControllerTriggerType type);
-    bool LoadAmiibo(std::span<const u8> data);
-    void CloseAmiibo();
-
-    AmiiboName GetAmiiboName(const AmiiboSettings& settings) const;
-    void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name);
-    AmiiboDate GetAmiiboDate(s64 posix_time) const;
-    u64 RemoveVersionByte(u64 application_id) const;
-    void UpdateSettingsCrc();
-    void UpdateRegisterInfoCrc();
-
-    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;
-
-    bool is_initalized{};
-    bool is_data_moddified{};
-    bool is_app_area_open{};
-    bool is_plain_amiibo{};
-    TagProtocol allowed_protocols{};
-    s64 current_posix_time{};
-    MountTarget mount_target{MountTarget::None};
-    DeviceState device_state{DeviceState::Unavailable};
-
-    NTAG215File tag_data{};
-    EncryptedNTAG215File encrypted_tag_data{};
-};
-
-} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
index 2ed8bb1ba..21d159154 100644
--- a/src/core/hle/service/nfp/nfp_interface.cpp
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "common/logging/log.h"
@@ -6,198 +6,34 @@
 #include "core/hid/hid_types.h"
 #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/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/nfc_types.h"
 #include "core/hle/service/nfp/nfp_interface.h"
 #include "core/hle/service/nfp/nfp_result.h"
+#include "core/hle/service/nfp/nfp_types.h"
 
 namespace Service::NFP {
 
 Interface::Interface(Core::System& system_, const char* name)
-    : ServiceFramework{system_, name}, service_context{system_, service_name} {
-    availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
+    : NfcInterface{system_, name, NFC::BackendType::Nfp} {}
 
-    for (u32 device_index = 0; device_index < 10; device_index++) {
-        devices[device_index] =
-            std::make_shared<NfpDevice>(Core::HID::IndexToNpadIdType(device_index), system,
-                                        service_context, availability_change_event);
-    }
-}
-
-Interface::~Interface() {
-    availability_change_event->Close();
-}
-
-void Interface::Initialize(HLERequestContext& ctx) {
-    LOG_INFO(Service_NFP, "called");
-
-    state = State::Initialized;
-
-    for (auto& device : devices) {
-        device->Initialize();
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
-}
+Interface::~Interface() = default;
 
 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);
+    Initialize(ctx);
 }
 
 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;
-
-    for (auto& device : devices) {
-        device->Finalize();
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    Initialize(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);
+    Finalize(ctx);
 }
 
 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) {
-        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.GetWriteBufferNumElements<u64>();
-
-    for (const auto& device : devices) {
-        if (nfp_devices.size() >= max_allowed_devices) {
-            continue;
-        }
-        if (device->GetCurrentState() != 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 Interface::StartDetection(HLERequestContext& ctx) {
-    IPC::RequestParser rp{ctx};
-    const auto device_handle{rp.Pop<u64>()};
-    const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
-    LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
-
-    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()->StartDetection(nfp_protocol);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-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);
-
-    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()->StopDetection();
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
+    Finalize(ctx);
 }
 
 void Interface::Mount(HLERequestContext& ctx) {
@@ -208,21 +44,9 @@ void Interface::Mount(HLERequestContext& ctx) {
     LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
              model_type, mount_target);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->Mount(device_handle, model_type, mount_target);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->Mount(mount_target);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -232,21 +56,9 @@ void Interface::Unmount(HLERequestContext& 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 result = GetManager()->Unmount(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->Unmount();
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -257,21 +69,9 @@ void Interface::OpenApplicationArea(HLERequestContext& ctx) {
     const auto access_id{rp.Pop<u32>()};
     LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->OpenApplicationArea(device_handle, access_id);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->OpenApplicationArea(access_id);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -282,28 +82,16 @@ void Interface::GetApplicationArea(HLERequestContext& ctx) {
     const auto data_size = ctx.GetWriteBufferSize();
     LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    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;
-    }
-
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
     std::vector<u8> data(data_size);
-    const auto result = device.value()->GetApplicationArea(data);
+    auto result = GetManager()->GetApplicationArea(device_handle, data);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsError()) {
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(result);
+        return;
+    }
+
     ctx.WriteBuffer(data);
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(result);
@@ -316,27 +104,9 @@ void Interface::SetApplicationArea(HLERequestContext& ctx) {
     const auto data{ctx.ReadBuffer()};
     LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size());
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->SetApplicationArea(device_handle, data);
+    result = TranslateResultToServiceError(result);
 
-    if (!ctx.CanReadBuffer()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(InvalidArgument);
-        return;
-    }
-
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->SetApplicationArea(data);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -346,21 +116,9 @@ void Interface::Flush(HLERequestContext& 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 result = GetManager()->Flush(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->Flush();
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -370,21 +128,9 @@ void Interface::Restore(HLERequestContext& ctx) {
     const auto device_handle{rp.Pop<u64>()};
     LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->Restore(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->RestoreAmiibo();
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -397,53 +143,9 @@ void Interface::CreateApplicationArea(HLERequestContext& ctx) {
     LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
              access_id, data.size());
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->CreateApplicationArea(device_handle, access_id, data);
+    result = TranslateResultToServiceError(result);
 
-    if (!ctx.CanReadBuffer()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(InvalidArgument);
-        return;
-    }
-
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->CreateApplicationArea(access_id, data);
-    IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(result);
-}
-
-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);
-
-    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;
-    }
-
-    TagInfo tag_info{};
-    const auto result = device.value()->GetTagInfo(tag_info);
-    ctx.WriteBuffer(tag_info);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -453,23 +155,14 @@ void Interface::GetRegisterInfo(HLERequestContext& 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;
-    }
-
     RegisterInfo register_info{};
-    const auto result = device.value()->GetRegisterInfo(register_info);
-    ctx.WriteBuffer(register_info);
+    auto result = GetManager()->GetRegisterInfo(device_handle, register_info);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(register_info);
+    }
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -479,23 +172,14 @@ void Interface::GetCommonInfo(HLERequestContext& 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;
-    }
-
     CommonInfo common_info{};
-    const auto result = device.value()->GetCommonInfo(common_info);
-    ctx.WriteBuffer(common_info);
+    auto result = GetManager()->GetCommonInfo(device_handle, common_info);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(common_info);
+    }
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -505,155 +189,26 @@ void Interface::GetModelInfo(HLERequestContext& 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;
-    }
-
     ModelInfo model_info{};
-    const auto result = device.value()->GetModelInfo(model_info);
-    ctx.WriteBuffer(model_info);
+    auto result = GetManager()->GetModelInfo(device_handle, model_info);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(model_info);
+    }
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
 
-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);
-
-    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;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2, 1};
-    rb.Push(ResultSuccess);
-    rb.PushCopyObjects(device.value()->GetActivateEvent());
-}
-
-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);
-
-    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;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 2, 1};
-    rb.Push(ResultSuccess);
-    rb.PushCopyObjects(device.value()->GetDeactivateEvent());
-}
-
-void Interface::GetState(HLERequestContext& ctx) {
-    LOG_DEBUG(Service_NFP, "called");
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.PushEnum(state);
-}
-
-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);
-
-    auto device = GetNfpDevice(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 Interface::GetNpadId(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;
-    }
-
-    IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.PushEnum(device.value()->GetNpadId());
-}
-
 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);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(device.value()->GetApplicationAreaSize());
-}
-
-void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
-    LOG_INFO(Service_NFP, "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());
+    rb.Push(GetManager()->GetApplicationAreaSize());
 }
 
 void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
@@ -664,21 +219,9 @@ void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
     LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
              access_id, data.size());
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->RecreateApplicationArea(device_handle, access_id, data);
+    result = TranslateResultToServiceError(result);
 
-    auto device = GetNfpDevice(device_handle);
-
-    if (!device.has_value()) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(DeviceNotFound);
-        return;
-    }
-
-    const auto result = device.value()->RecreateApplicationArea(access_id, data);
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -686,23 +229,11 @@ void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
 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);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->Format(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -712,23 +243,14 @@ void Interface::GetAdminInfo(HLERequestContext& 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);
+    auto result = GetManager()->GetAdminInfo(device_handle, admin_info);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(admin_info);
+    }
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -738,23 +260,14 @@ void Interface::GetRegisterInfoPrivate(HLERequestContext& 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);
+    auto result = GetManager()->GetRegisterInfoPrivate(device_handle, register_info);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(register_info);
+    }
+
     IPC::ResponseBuilder rb{ctx, 2};
     rb.Push(result);
 }
@@ -762,25 +275,15 @@ void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) {
 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());
+    const auto register_info_buffer{ctx.ReadBuffer()};
+    LOG_INFO(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle,
+             register_info_buffer.size());
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    RegisterInfoPrivate register_info{};
+    memcpy(&register_info, register_info_buffer.data(), sizeof(RegisterInfoPrivate));
+    auto result = GetManager()->SetRegisterInfoPrivate(device_handle, register_info);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -788,23 +291,11 @@ void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) {
 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);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->DeleteRegisterInfo(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -812,23 +303,11 @@ void Interface::DeleteRegisterInfo(HLERequestContext& ctx) {
 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);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->DeleteApplicationArea(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -836,24 +315,18 @@ void Interface::DeleteApplicationArea(HLERequestContext& ctx) {
 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;
-    }
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
     bool has_application_area = false;
-    const auto result = device.value()->ExistApplicationArea(has_application_area);
+    auto result = GetManager()->ExistsApplicationArea(device_handle, has_application_area);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsError()) {
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(result);
+        return;
+    }
+
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(result);
     rb.Push(has_application_area);
@@ -862,27 +335,16 @@ void Interface::ExistsApplicationArea(HLERequestContext& ctx) {
 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);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
+    NfpData nfp_data{};
+    auto result = GetManager()->GetAll(device_handle, nfp_data);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(nfp_data);
     }
 
-    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);
 }
@@ -890,28 +352,15 @@ void Interface::GetAll(HLERequestContext& ctx) {
 void Interface::SetAll(HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto device_handle{rp.Pop<u64>()};
-    const auto nfp_data{ctx.ReadBuffer()};
+    const auto nfp_data_buffer{ctx.ReadBuffer()};
 
-    LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    NfpData nfp_data{};
+    memcpy(&nfp_data, nfp_data_buffer.data(), sizeof(NfpData));
+    auto result = GetManager()->SetAll(device_handle, nfp_data);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -919,23 +368,11 @@ void Interface::SetAll(HLERequestContext& ctx) {
 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);
+    LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->FlushDebug(device_handle);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -944,23 +381,12 @@ 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);
+    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, break_type={}", device_handle,
+                break_type);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->BreakTag(device_handle, break_type);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -968,23 +394,16 @@ void Interface::BreakTag(HLERequestContext& ctx) {
 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);
+    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
+    std::vector<u8> backup_data{};
+    auto result = GetManager()->ReadBackupData(device_handle, backup_data);
+    result = TranslateResultToServiceError(result);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(backup_data);
     }
 
-    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);
 }
@@ -992,23 +411,12 @@ void Interface::ReadBackupData(HLERequestContext& ctx) {
 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);
+    const auto backup_data_buffer{ctx.ReadBuffer()};
+    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
+    result = TranslateResultToServiceError(result);
 
-    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);
 }
@@ -1016,34 +424,15 @@ void Interface::WriteBackupData(HLERequestContext& ctx) {
 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);
+    const auto write_type{rp.PopEnum<WriteType>()};
+    const auto ntf_data_buffer{ctx.ReadBuffer()};
+    LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
 
-    if (state == State::NonInitialized) {
-        IPC::ResponseBuilder rb{ctx, 2};
-        rb.Push(NfcDisabled);
-        return;
-    }
+    auto result = GetManager()->WriteNtf(device_handle, write_type, ntf_data_buffer);
+    result = TranslateResultToServiceError(result);
 
-    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;
-        }
-    }
-    return std::nullopt;
-}
-
 } // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h
index 616c94b06..fa985b068 100644
--- a/src/core/hle/service/nfp/nfp_interface.h
+++ b/src/core/hle/service/nfp/nfp_interface.h
@@ -1,32 +1,23 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 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/nfc/nfc_interface.h"
 #include "core/hle/service/service.h"
 
 namespace Service::NFP {
-class NfpDevice;
 
-class Interface : public ServiceFramework<Interface> {
+class Interface : public NFC::NfcInterface {
 public:
     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);
     void Mount(HLERequestContext& ctx);
     void Unmount(HLERequestContext& ctx);
     void OpenApplicationArea(HLERequestContext& ctx);
@@ -35,17 +26,10 @@ public:
     void Flush(HLERequestContext& ctx);
     void Restore(HLERequestContext& ctx);
     void CreateApplicationArea(HLERequestContext& ctx);
-    void GetTagInfo(HLERequestContext& ctx);
     void GetRegisterInfo(HLERequestContext& ctx);
     void GetCommonInfo(HLERequestContext& ctx);
     void GetModelInfo(HLERequestContext& ctx);
-    void AttachActivateEvent(HLERequestContext& ctx);
-    void AttachDeactivateEvent(HLERequestContext& ctx);
-    void GetState(HLERequestContext& ctx);
-    void GetDeviceState(HLERequestContext& ctx);
-    void GetNpadId(HLERequestContext& ctx);
     void GetApplicationAreaSize(HLERequestContext& ctx);
-    void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
     void RecreateApplicationArea(HLERequestContext& ctx);
     void Format(HLERequestContext& ctx);
     void GetAdminInfo(HLERequestContext& ctx);
@@ -61,21 +45,6 @@ public:
     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);
-
-    KernelHelpers::ServiceContext service_context;
-
-    std::array<std::shared_ptr<NfpDevice>, 10> devices{};
-
-    State state{State::NonInitialized};
-    Kernel::KEvent* availability_change_event;
 };
 
 } // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h
index d8e4cf094..4c126cd81 100644
--- a/src/core/hle/service/nfp/nfp_result.h
+++ b/src/core/hle/service/nfp/nfp_result.h
@@ -1,5 +1,5 @@
 // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
+// SPDX-License-Identifier: GPL-2.0-or-later
 
 #pragma once
 
@@ -7,18 +7,19 @@
 
 namespace Service::NFP {
 
-constexpr Result DeviceNotFound(ErrorModule::NFP, 64);
-constexpr Result InvalidArgument(ErrorModule::NFP, 65);
-constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68);
-constexpr Result WrongDeviceState(ErrorModule::NFP, 73);
-constexpr Result NfcDisabled(ErrorModule::NFP, 80);
-constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88);
-constexpr Result TagRemoved(ErrorModule::NFP, 97);
-constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120);
-constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
-constexpr Result CorruptedData(ErrorModule::NFP, 144);
-constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152);
-constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168);
-constexpr Result NotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73);
+constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
+constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
+constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
+constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
 
 } // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 1ef047cee..7d36d5ee6 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -7,32 +7,19 @@
 
 #include "common/swap.h"
 #include "core/hle/service/mii/types.h"
+#include "core/hle/service/nfc/nfc_types.h"
 
 namespace Service::NFP {
 static constexpr std::size_t amiibo_name_length = 0xA;
 static constexpr std::size_t application_id_version_offset = 0x1c;
 static constexpr std::size_t counter_limit = 0xffff;
 
-enum class ServiceType : u32 {
-    User,
-    Debug,
-    System,
-};
-
-enum class DeviceState : u32 {
-    Initialized,
-    SearchingForTag,
-    TagFound,
-    TagRemoved,
-    TagMounted,
-    Unavailable,
-    Finalized,
-};
-
+// This is nn::nfp::ModelType
 enum class ModelType : u32 {
     Amiibo,
 };
 
+// This is nn::nfp::MountTarget
 enum class MountTarget : u32 {
     None,
     Rom,
@@ -72,35 +59,6 @@ enum class AmiiboSeries : u8 {
     Diablo,
 };
 
-enum class TagType : u32 {
-    None,
-    Type1, // ISO14443A RW 96-2k bytes 106kbit/s
-    Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
-    Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
-    Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
-    Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
-};
-
-enum class PackedTagType : u8 {
-    None,
-    Type1, // ISO14443A RW 96-2k bytes 106kbit/s
-    Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
-    Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
-    Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
-    Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
-};
-
-// Verify this enum. It might be completely wrong default protocol is 0x48
-enum class TagProtocol : u32 {
-    None,
-    TypeA = 1U << 0, // ISO14443A
-    TypeB = 1U << 1, // ISO14443B
-    TypeF = 1U << 2, // Sony Felica
-    Unknown1 = 1U << 3,
-    Unknown2 = 1U << 5,
-    All = 0xFFFFFFFFU,
-};
-
 enum class AppAreaVersion : u8 {
     Nintendo3DS = 0,
     NintendoWiiU = 1,
@@ -115,6 +73,11 @@ enum class BreakType : u32 {
     Unknown2,
 };
 
+enum class WriteType : u32 {
+    Unknown0,
+    Unknown1,
+};
+
 enum class CabinetMode : u8 {
     StartNicknameAndOwnerSettings,
     StartGameDataEraser,
@@ -122,27 +85,16 @@ enum class CabinetMode : u8 {
     StartFormatter,
 };
 
-enum class MifareCmd : u8 {
-    AuthA = 0x60,
-    AuthB = 0x61,
-    Read = 0x30,
-    Write = 0xA0,
-    Transfer = 0xB0,
-    Decrement = 0xC0,
-    Increment = 0xC1,
-    Store = 0xC2
-};
-
-using UniqueSerialNumber = std::array<u8, 7>;
 using LockBytes = std::array<u8, 2>;
 using HashData = std::array<u8, 0x20>;
 using ApplicationArea = std::array<u8, 0xD8>;
 using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
-using DataBlock = std::array<u8, 0x10>;
-using KeyData = std::array<u8, 0x6>;
+
+// This is nn::nfp::TagInfo
+using TagInfo = NFC::TagInfo;
 
 struct TagUuid {
-    UniqueSerialNumber uid;
+    NFC::UniqueSerialNumber uid;
     u8 nintendo_id;
     LockBytes lock_bytes;
 };
@@ -243,7 +195,7 @@ struct AmiiboModelInfo {
     AmiiboType amiibo_type;
     u16_be model_number;
     AmiiboSeries series;
-    PackedTagType tag_type;
+    NFC::PackedTagType tag_type;
     INSERT_PADDING_BYTES(0x4); // Unknown
 };
 static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size");
@@ -298,7 +250,7 @@ struct NTAG215File {
     u32_be register_info_crc;
     ApplicationArea application_area; // Encrypted Game data
     HashData hmac_tag;                // Hash
-    UniqueSerialNumber uid;           // Unique serial number
+    NFC::UniqueSerialNumber uid;      // Unique serial number
     u8 nintendo_id;                   // Tag UUID
     AmiiboModelInfo model_info;
     HashData keygen_salt;     // Salt
@@ -326,17 +278,7 @@ static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File),
 static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>,
               "EncryptedNTAG215File must be trivially copyable.");
 
-struct TagInfo {
-    UniqueSerialNumber uuid;
-    INSERT_PADDING_BYTES(0x3);
-    u8 uuid_length;
-    INSERT_PADDING_BYTES(0x15);
-    TagProtocol protocol;
-    TagType tag_type;
-    INSERT_PADDING_BYTES(0x30);
-};
-static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
-
+// This is nn::nfp::CommonInfo
 struct CommonInfo {
     WriteDate last_write_date;
     u16 write_counter;
@@ -347,6 +289,7 @@ struct CommonInfo {
 };
 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
 
+// This is nn::nfp::ModelInfo
 struct ModelInfo {
     u16 character_id;
     u8 character_variant;
@@ -357,6 +300,7 @@ struct ModelInfo {
 };
 static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
 
+// This is nn::nfp::RegisterInfo
 struct RegisterInfo {
     Service::Mii::CharInfo mii_char_info;
     WriteDate creation_date;
@@ -366,6 +310,7 @@ struct RegisterInfo {
 };
 static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
 
+// This is nn::nfp::RegisterInfoPrivate
 struct RegisterInfoPrivate {
     Service::Mii::MiiStoreData mii_store_data;
     WriteDate creation_date;
@@ -375,12 +320,13 @@ struct RegisterInfoPrivate {
 };
 static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
 
+// This is nn::nfp::AdminInfo
 struct AdminInfo {
     u64 application_id;
     u32 application_area_id;
     u16 crc_change_counter;
     u8 flags;
-    PackedTagType tag_type;
+    NFC::PackedTagType tag_type;
     AppAreaVersion app_area_version;
     INSERT_PADDING_BYTES(0x7);
     INSERT_PADDING_BYTES(0x28);
@@ -411,7 +357,7 @@ struct NfpData {
     u32 access_id;
     u16 settings_crc_counter;
     u8 font_region;
-    PackedTagType tag_type;
+    NFC::PackedTagType tag_type;
     AppAreaVersion console_type;
     u8 application_id_byte;
     INSERT_PADDING_BYTES(0x2E);
@@ -420,37 +366,4 @@ struct NfpData {
 static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
 #pragma pack()
 
-struct SectorKey {
-    MifareCmd command;
-    u8 unknown; // Usually 1
-    INSERT_PADDING_BYTES(0x6);
-    KeyData sector_key;
-    INSERT_PADDING_BYTES(0x2);
-};
-static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
-
-struct MifareReadBlockParameter {
-    u8 sector_number;
-    INSERT_PADDING_BYTES(0x7);
-    SectorKey sector_key;
-};
-static_assert(sizeof(MifareReadBlockParameter) == 0x18,
-              "MifareReadBlockParameter is an invalid size");
-
-struct MifareReadBlockData {
-    DataBlock data;
-    u8 sector_number;
-    INSERT_PADDING_BYTES(0x7);
-};
-static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
-
-struct MifareWriteBlockParameter {
-    DataBlock data;
-    u8 sector_number;
-    INSERT_PADDING_BYTES(0x7);
-    SectorKey sector_key;
-};
-static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
-              "MifareWriteBlockParameter is an invalid size");
-
 } // namespace Service::NFP
diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp
index 4559df5b1..4988fcc83 100644
--- a/src/yuzu/applets/qt_amiibo_settings.cpp
+++ b/src/yuzu/applets/qt_amiibo_settings.cpp
@@ -8,7 +8,7 @@
 
 #include "common/assert.h"
 #include "common/string_util.h"
-#include "core/hle/service/nfp/nfp_device.h"
+#include "core/hle/service/nfc/common/device.h"
 #include "core/hle/service/nfp/nfp_result.h"
 #include "input_common/drivers/virtual_amiibo.h"
 #include "input_common/main.h"
@@ -22,7 +22,7 @@
 QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
                                                Core::Frontend::CabinetParameters parameters_,
                                                InputCommon::InputSubsystem* input_subsystem_,
-                                               std::shared_ptr<Service::NFP::NfpDevice> nfp_device_)
+                                               std::shared_ptr<Service::NFC::NfcDevice> nfp_device_)
     : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()),
       input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)},
       parameters(std::move(parameters_)) {
@@ -52,11 +52,11 @@ void QtAmiiboSettingsDialog::LoadInfo() {
         return;
     }
 
-    if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
-        nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+    if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
+        nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
         return;
     }
-    nfp_device->Mount(Service::NFP::MountTarget::All);
+    nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
 
     LoadAmiiboInfo();
     LoadAmiiboData();
@@ -261,7 +261,7 @@ void QtAmiiboSettings::Close() const {
 void QtAmiiboSettings::ShowCabinetApplet(
     const Core::Frontend::CabinetCallback& callback_,
     const Core::Frontend::CabinetParameters& parameters,
-    std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
+    std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
     callback = std::move(callback_);
     emit MainWindowShowAmiiboSettings(parameters, nfp_device);
 }
diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h
index bc389a33f..ee66a0255 100644
--- a/src/yuzu/applets/qt_amiibo_settings.h
+++ b/src/yuzu/applets/qt_amiibo_settings.h
@@ -23,9 +23,9 @@ namespace Ui {
 class QtAmiiboSettingsDialog;
 }
 
-namespace Service::NFP {
-class NfpDevice;
-} // namespace Service::NFP
+namespace Service::NFC {
+class NfcDevice;
+} // namespace Service::NFC
 
 class QtAmiiboSettingsDialog final : public QDialog {
     Q_OBJECT
@@ -33,7 +33,7 @@ class QtAmiiboSettingsDialog final : public QDialog {
 public:
     explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
                                     InputCommon::InputSubsystem* input_subsystem_,
-                                    std::shared_ptr<Service::NFP::NfpDevice> nfp_device_);
+                                    std::shared_ptr<Service::NFC::NfcDevice> nfp_device_);
     ~QtAmiiboSettingsDialog() override;
 
     int exec() override;
@@ -52,7 +52,7 @@ private:
     std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui;
 
     InputCommon::InputSubsystem* input_subsystem;
-    std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+    std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
 
     // Parameters sent in from the backend HLE applet.
     Core::Frontend::CabinetParameters parameters;
@@ -71,11 +71,11 @@ public:
     void Close() const override;
     void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_,
                            const Core::Frontend::CabinetParameters& parameters,
-                           std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
+                           std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
 
 signals:
     void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters,
-                                      std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const;
+                                      std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const;
     void MainWindowRequestExit() const;
 
 private:
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b79409a68..e051e35df 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -570,8 +570,8 @@ void GMainWindow::RegisterMetaTypes() {
 
     // Cabinet Applet
     qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
-    qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>(
-        "std::shared_ptr<Service::NFP::NfpDevice>");
+    qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
+        "std::shared_ptr<Service::NFC::NfcDevice>");
 
     // Controller Applet
     qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@@ -599,7 +599,7 @@ void GMainWindow::RegisterMetaTypes() {
 }
 
 void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
-                                           std::shared_ptr<Service::NFP::NfpDevice> nfp_device) {
+                                           std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
     cabinet_applet =
         new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
     SCOPE_EXIT({
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 8b5c1d747..ac90bd5ae 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -93,9 +93,9 @@ enum class SwkbdReplyType : u32;
 enum class WebExitReason : u32;
 } // namespace Service::AM::Applets
 
-namespace Service::NFP {
-class NfpDevice;
-} // namespace Service::NFP
+namespace Service::NFC {
+class NfcDevice;
+} // namespace Service::NFC
 
 namespace Ui {
 class MainWindow;
@@ -188,7 +188,7 @@ public slots:
     void OnExit();
     void OnSaveConfig();
     void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
-                                  std::shared_ptr<Service::NFP::NfpDevice> nfp_device);
+                                  std::shared_ptr<Service::NFC::NfcDevice> nfp_device);
     void AmiiboSettingsRequestExit();
     void ControllerSelectorReconfigureControllers(
         const Core::Frontend::ControllerParameters& parameters);