From 9cd698e8ad584a199048f072ed65986ee10ba31a Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sun, 2 Jul 2023 19:21:16 -0600
Subject: [PATCH] service: nfc: Ensure controller is in the correct mode

---
 src/core/hid/emulated_controller.cpp       | 12 ++++++++
 src/core/hid/emulated_controller.h         |  8 ++++++
 src/core/hle/service/nfc/common/device.cpp | 32 ++++++++++++++--------
 3 files changed, 41 insertions(+), 11 deletions(-)

diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 1ebc32c1e7..94bd656fe9 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1243,10 +1243,12 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
     auto& nfc_output_device = output_devices[3];
 
     if (device_index == EmulatedDeviceIndex::LeftIndex) {
+        controller.left_polling_mode = polling_mode;
         return left_output_device->SetPollingMode(polling_mode);
     }
 
     if (device_index == EmulatedDeviceIndex::RightIndex) {
+        controller.right_polling_mode = polling_mode;
         const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
         const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
 
@@ -1261,12 +1263,22 @@ Common::Input::DriverResult EmulatedController::SetPollingMode(
         return mapped_nfc_result;
     }
 
+    controller.left_polling_mode = polling_mode;
+    controller.right_polling_mode = polling_mode;
     left_output_device->SetPollingMode(polling_mode);
     right_output_device->SetPollingMode(polling_mode);
     nfc_output_device->SetPollingMode(polling_mode);
     return Common::Input::DriverResult::Success;
 }
 
+Common::Input::PollingMode EmulatedController::GetPollingMode(
+    EmulatedDeviceIndex device_index) const {
+    if (device_index == EmulatedDeviceIndex::LeftIndex) {
+        return controller.left_polling_mode;
+    }
+    return controller.right_polling_mode;
+}
+
 bool EmulatedController::SetCameraFormat(
     Core::IrSensor::ImageTransferProcessorFormat camera_format) {
     LOG_INFO(Service_HID, "Set camera format {}", camera_format);
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index d511e5facb..88d77db8de 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -143,6 +143,8 @@ struct ControllerStatus {
     CameraState camera_state{};
     RingSensorForce ring_analog_state{};
     NfcState nfc_state{};
+    Common::Input::PollingMode left_polling_mode{};
+    Common::Input::PollingMode right_polling_mode{};
 };
 
 enum class ControllerTriggerType {
@@ -370,6 +372,12 @@ public:
      */
     Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
                                                Common::Input::PollingMode polling_mode);
+    /**
+     * Get the current polling mode from a controller
+     * @param device_index index of the controller to set the polling mode
+     * @return current polling mode
+     */
+    Common::Input::PollingMode GetPollingMode(EmulatedDeviceIndex device_index) const;
 
     /**
      * Sets the desired camera format to be polled from a controller
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 5bf2898183..2d633b03fa 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -66,10 +66,6 @@ NfcDevice::~NfcDevice() {
 };
 
 void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
-    if (!is_initalized) {
-        return;
-    }
-
     if (type == Core::HID::ControllerTriggerType::Connected) {
         Initialize();
         availability_change_event->Signal();
@@ -77,12 +73,12 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
     }
 
     if (type == Core::HID::ControllerTriggerType::Disconnected) {
-        device_state = DeviceState::Unavailable;
+        Finalize();
         availability_change_event->Signal();
         return;
     }
 
-    if (type != Core::HID::ControllerTriggerType::Nfc) {
+    if (!is_initalized) {
         return;
     }
 
@@ -90,6 +86,17 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
         return;
     }
 
+    // Ensure nfc mode is always active
+    if (npad_device->GetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex) ==
+        Common::Input::PollingMode::Active) {
+        npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+                                    Common::Input::PollingMode::NFC);
+    }
+
+    if (type != Core::HID::ControllerTriggerType::Nfc) {
+        return;
+    }
+
     const auto nfc_status = npad_device->GetNfc();
     switch (nfc_status.state) {
     case Common::Input::NfcState::NewAmiibo:
@@ -207,11 +214,14 @@ void NfcDevice::Initialize() {
 }
 
 void NfcDevice::Finalize() {
-    if (device_state == DeviceState::TagMounted) {
-        Unmount();
-    }
-    if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
-        StopDetection();
+    if (npad_device->IsConnected()) {
+        if (device_state == DeviceState::TagMounted) {
+            Unmount();
+        }
+        if (device_state == DeviceState::SearchingForTag ||
+            device_state == DeviceState::TagRemoved) {
+            StopDetection();
+        }
     }
 
     if (device_state != DeviceState::Unavailable) {