From 74d1b9a254baedc91b1b46b14e8f8bf808c7fd9f Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 15:38:17 -0500
Subject: [PATCH 1/8] service: hid: Quick RE fixes and comments

---
 src/core/hle/service/hid/controllers/npad.cpp | 50 +++++++++-------
 src/core/hle/service/hid/controllers/npad.h   | 13 +++--
 src/core/hle/service/hid/errors.h             |  1 +
 src/core/hle/service/hid/hid.cpp              | 58 ++++++++++---------
 4 files changed, 68 insertions(+), 54 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index de06e1735..147021fbd 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -672,6 +672,12 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
 }
 
 void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
+    if (joy_hold_type != NpadJoyHoldType::Horizontal &&
+        joy_hold_type != NpadJoyHoldType::Vertical) {
+        LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}",
+                  joy_hold_type);
+        return;
+    }
     hold_type = joy_hold_type;
 }
 
@@ -957,10 +963,10 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type,
     InitNewlyAddedController(npad_id);
 }
 
-void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
+ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
     if (!IsNpadIdValid(npad_id)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
-        return;
+        return InvalidNpadId;
     }
 
     LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id);
@@ -997,6 +1003,7 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
     controller.device->Disconnect();
     SignalStyleSetChangedEvent(npad_id);
     WriteEmptyEntry(shared_memory);
+    return ResultSuccess;
 }
 
 ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
@@ -1349,17 +1356,17 @@ void Controller_NPad::StopLRAssignmentMode() {
     is_in_lr_assignment_mode = false;
 }
 
-bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
-                                         Core::HID::NpadIdType npad_id_2) {
+ResultCode Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
+                                               Core::HID::NpadIdType npad_id_2) {
     if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
                   npad_id_2);
-        return false;
+        return InvalidNpadId;
     }
     if (npad_id_1 == Core::HID::NpadIdType::Handheld ||
         npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other ||
         npad_id_2 == Core::HID::NpadIdType::Other) {
-        return true;
+        return ResultSuccess;
     }
     const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device;
     const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device;
@@ -1369,46 +1376,49 @@ bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
     const auto is_connected_2 = controller_2->IsConnected();
 
     if (!IsControllerSupported(type_index_1) && is_connected_1) {
-        return false;
+        return NpadNotConnected;
     }
     if (!IsControllerSupported(type_index_2) && is_connected_2) {
-        return false;
+        return NpadNotConnected;
     }
 
     UpdateControllerAt(type_index_2, npad_id_1, is_connected_2);
     UpdateControllerAt(type_index_1, npad_id_2, is_connected_1);
 
-    return true;
+    return ResultSuccess;
 }
 
-Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) {
+ResultCode Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id,
+                                          Core::HID::LedPattern& pattern) const {
     if (!IsNpadIdValid(npad_id)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
-        return Core::HID::LedPattern{0, 0, 0, 0};
+        return InvalidNpadId;
     }
     const auto& controller = GetControllerFromNpadIdType(npad_id).device;
-    return controller->GetLedPattern();
+    pattern = controller->GetLedPattern();
+    return ResultSuccess;
 }
 
-bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(
-    Core::HID::NpadIdType npad_id) const {
+ResultCode Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(
+    Core::HID::NpadIdType npad_id, bool& is_valid) const {
     if (!IsNpadIdValid(npad_id)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
-        // Return the default value
-        return false;
+        return InvalidNpadId;
     }
     const auto& controller = GetControllerFromNpadIdType(npad_id);
-    return controller.unintended_home_button_input_protection;
+    is_valid = controller.unintended_home_button_input_protection;
+    return ResultSuccess;
 }
 
-void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
-                                                                    Core::HID::NpadIdType npad_id) {
+ResultCode Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(
+    bool is_protection_enabled, Core::HID::NpadIdType npad_id) {
     if (!IsNpadIdValid(npad_id)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
-        return;
+        return InvalidNpadId;
     }
     auto& controller = GetControllerFromNpadIdType(npad_id);
     controller.unintended_home_button_input_protection = is_protection_enabled;
+    return ResultSuccess;
 }
 
 void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 0a96825a5..31364a420 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -141,7 +141,7 @@ public:
     void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
                             bool connected);
 
-    void DisconnectNpad(Core::HID::NpadIdType npad_id);
+    ResultCode DisconnectNpad(Core::HID::NpadIdType npad_id);
 
     ResultCode SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
                                          GyroscopeZeroDriftMode drift_mode);
@@ -163,10 +163,11 @@ public:
     ResultCode GetSixAxisFusionParameters(
         Core::HID::SixAxisSensorHandle sixaxis_handle,
         Core::HID::SixAxisSensorFusionParameters& parameters) const;
-    Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id);
-    bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const;
-    void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
-                                                       Core::HID::NpadIdType npad_id);
+    ResultCode GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
+    ResultCode IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
+                                                            bool& is_enabled) const;
+    ResultCode SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
+                                                             Core::HID::NpadIdType npad_id);
     void SetAnalogStickUseCenterClamp(bool use_center_clamp);
     void ClearAllConnectedControllers();
     void DisconnectAllConnectedControllers();
@@ -176,7 +177,7 @@ public:
     void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
     void StartLRAssignmentMode();
     void StopLRAssignmentMode();
-    bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
+    ResultCode SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
 
     // Logical OR for all buttons presses on all controllers
     // Specifically for cheat engine and other features.
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index b31834074..279974ce9 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -9,6 +9,7 @@ namespace Service::HID {
 
 constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100};
 constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423};
+constexpr ResultCode InvalidNpadId{ErrorModule::HID, 709};
 constexpr ResultCode NpadNotConnected{ErrorModule::HID, 710};
 
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 44f892da9..18c02d47d 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -694,11 +694,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
         rb.Push(result1);
         return;
     }
-    if (result2.IsError()) {
-        rb.Push(result2);
-        return;
-    }
-    rb.Push(ResultSuccess);
+    rb.Push(result2);
 }
 
 void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
@@ -948,27 +944,29 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .DisconnectNpad(parameters.npad_id);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.DisconnectNpad(parameters.npad_id);
 
     LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
               parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
 
+    Core::HID::LedPattern pattern{0, 0, 0, 0};
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.GetLedPattern(npad_id, pattern);
+
     LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
 
     IPC::ResponseBuilder rb{ctx, 4};
-    rb.Push(ResultSuccess);
-    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                .GetLedPattern(npad_id)
-                .raw);
+    rb.Push(result);
+    rb.Push(pattern.raw);
 }
 
 void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
@@ -1157,19 +1155,14 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
     const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                         .SwapNpadAssignment(npad_id_1, npad_id_2);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2);
 
     LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
               npad_id_1, npad_id_2, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    if (res) {
-        rb.Push(ResultSuccess);
-    } else {
-        LOG_ERROR(Service_HID, "Npads are not connected!");
-        rb.Push(NpadNotConnected);
-    }
+    rb.Push(result);
 }
 
 void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
@@ -1183,13 +1176,17 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
+    bool is_enabled = false;
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result =
+        controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
+
     LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
                 parameters.npad_id, parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 3};
-    rb.Push(ResultSuccess);
-    rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
-                .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id));
+    rb.Push(result);
+    rb.Push(is_enabled);
 }
 
 void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
@@ -1204,9 +1201,9 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetUnintendedHomeButtonInputProtectionEnabled(
-            parameters.unintended_home_button_input_protection, parameters.npad_id);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
+        parameters.unintended_home_button_input_protection, parameters.npad_id);
 
     LOG_WARNING(Service_HID,
                 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
@@ -1215,7 +1212,7 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
                 parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
@@ -1377,6 +1374,8 @@ void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     const auto can_vibrate{rp.Pop<bool>()};
 
+    // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
+    // by converting it to a bool
     Settings::values.vibration_enabled.SetValue(can_vibrate);
 
     LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
@@ -1388,9 +1387,12 @@ void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
 void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_HID, "called");
 
+    // nnSDK checks if a float is greater than zero. We return the bool we stored earlier
+    const auto is_enabled = Settings::values.vibration_enabled.GetValue();
+
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
-    rb.Push(Settings::values.vibration_enabled.GetValue());
+    rb.Push(is_enabled);
 }
 
 void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {

From 7aa1d10655c769c9d2a32d65a810ad81eefe7ead Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 16:29:41 -0500
Subject: [PATCH 2/8] service: hid: Add error handling to setNpadAssignment and
 variants

---
 src/core/hle/service/hid/controllers/npad.cpp | 22 +++++++++--------
 src/core/hle/service/hid/controllers/npad.h   |  4 ++--
 src/core/hle/service/hid/hid.cpp              | 24 ++++++++++---------
 3 files changed, 27 insertions(+), 23 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 147021fbd..5df49d22f 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -701,11 +701,12 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
     return communication_mode;
 }
 
-void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
-                                  NpadJoyAssignmentMode assignment_mode) {
+ResultCode Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
+                                        NpadJoyDeviceType npad_device_type,
+                                        NpadJoyAssignmentMode assignment_mode) {
     if (!IsNpadIdValid(npad_id)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
-        return;
+        return InvalidNpadId;
     }
 
     auto& controller = GetControllerFromNpadIdType(npad_id);
@@ -714,7 +715,7 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy
     }
 
     if (!controller.device->IsConnected()) {
-        return;
+        return ResultSuccess;
     }
 
     if (assignment_mode == NpadJoyAssignmentMode::Dual) {
@@ -723,34 +724,34 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy
             controller.is_dual_left_connected = true;
             controller.is_dual_right_connected = false;
             UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
-            return;
+            return ResultSuccess;
         }
         if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
             DisconnectNpad(npad_id);
             controller.is_dual_left_connected = false;
             controller.is_dual_right_connected = true;
             UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
-            return;
+            return ResultSuccess;
         }
-        return;
+        return ResultSuccess;
     }
 
     // This is for NpadJoyAssignmentMode::Single
 
     // Only JoyconDual get affected by this function
     if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
-        return;
+        return ResultSuccess;
     }
 
     if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
         DisconnectNpad(npad_id);
         UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
-        return;
+        return ResultSuccess;
     }
     if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
         DisconnectNpad(npad_id);
         UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
-        return;
+        return ResultSuccess;
     }
 
     // We have two controllers connected to the same npad_id we need to split them
@@ -768,6 +769,7 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy
         controller_2.is_dual_right_connected = false;
         UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
     }
+    return ResultSuccess;
 }
 
 bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 31364a420..f03e9294d 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -107,8 +107,8 @@ public:
     void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
     NpadCommunicationMode GetNpadCommunicationMode() const;
 
-    void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
-                     NpadJoyAssignmentMode assignment_mode);
+    ResultCode SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
+                           NpadJoyAssignmentMode assignment_mode);
 
     bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
                                   const Core::HID::VibrationValue& vibration_value);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 18c02d47d..b41fc60d6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1026,15 +1026,16 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
-                     Controller_NPad::NpadJoyAssignmentMode::Single);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result =
+        controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
+                               Controller_NPad::NpadJoyAssignmentMode::Single);
 
     LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
              parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
@@ -1049,16 +1050,16 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
-                     Controller_NPad::NpadJoyAssignmentMode::Single);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
+                                               Controller_NPad::NpadJoyAssignmentMode::Single);
 
     LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
              parameters.npad_id, parameters.applet_resource_user_id,
              parameters.npad_joy_device_type);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
@@ -1072,14 +1073,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
 
     const auto parameters{rp.PopRaw<Parameters>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.SetNpadMode(parameters.npad_id, {},
+                                               Controller_NPad::NpadJoyAssignmentMode::Dual);
 
     LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
              parameters.applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {

From 3cf15af31e20b62dddcb9d9a19fbdc3a56e021e2 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 16:40:11 -0500
Subject: [PATCH 3/8] service: hid: Implement MergeSingleJoyAsDualJoy according
 to RE

---
 src/core/hle/service/hid/controllers/npad.cpp | 107 ++++++++----------
 src/core/hle/service/hid/controllers/npad.h   |   3 +-
 src/core/hle/service/hid/errors.h             |   2 +
 src/core/hle/service/hid/hid.cpp              |   6 +-
 4 files changed, 55 insertions(+), 63 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 5df49d22f..4095a0a3c 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -1275,77 +1275,66 @@ ResultCode Controller_NPad::GetSixAxisFusionParameters(
     return ResultSuccess;
 }
 
-void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
-                                              Core::HID::NpadIdType npad_id_2) {
+ResultCode Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
+                                                    Core::HID::NpadIdType npad_id_2) {
     if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
                   npad_id_2);
-        return;
+        return InvalidNpadId;
     }
     auto& controller_1 = GetControllerFromNpadIdType(npad_id_1);
     auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
-    const auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
-    const auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
-    bool merge_controllers = false;
+    auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
+    auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
 
-    // If the controllers at both npad indices form a pair of left and right joycons, merge them.
-    // Otherwise, do nothing.
+    // Simplify this code by converting dualjoycon with only a side connected to single joycons
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) {
+        if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
+            controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft;
+        }
+        if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
+            controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight;
+        }
+    }
+    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
+        if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
+            controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft;
+        }
+        if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
+            controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight;
+        }
+    }
+
+    // Invalid merge errors
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual ||
+        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
+        return NpadIsDualJoycon;
+    }
     if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) {
+        return NpadIsSameType;
+    }
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
         controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight &&
-        controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
-        controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected &&
-        !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected &&
-        controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
-        merge_controllers = true;
+        return NpadIsSameType;
     }
 
-    if (merge_controllers) {
-        // Disconnect the joycon at the second id and connect the dual joycon at the first index.
-        DisconnectNpad(npad_id_2);
-        controller_1.is_dual_left_connected = true;
-        controller_1.is_dual_right_connected = true;
-        AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
-        return;
+    // These exceptions are handled as if they where dual joycon
+    if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) {
+        return NpadIsDualJoycon;
     }
-    LOG_WARNING(Service_HID,
-                "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, "
-                "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}",
-                npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(),
-                controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected,
-                controller_1.is_dual_right_connected, controller_2.is_dual_left_connected,
-                controller_2.is_dual_right_connected);
+    if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) {
+        return NpadIsDualJoycon;
+    }
+
+    // Disconnect the joycon at the second id and connect the dual joycon at the first index.
+    DisconnectNpad(npad_id_2);
+    controller_1.is_dual_left_connected = true;
+    controller_1.is_dual_right_connected = true;
+    AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
+    return ResultSuccess;
 }
 
 void Controller_NPad::StartLRAssignmentMode() {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index f03e9294d..5305e8cf8 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -174,7 +174,8 @@ public:
     void ConnectAllDisconnectedControllers();
     void ClearAllControllers();
 
-    void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
+    ResultCode MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
+                                       Core::HID::NpadIdType npad_id_2);
     void StartLRAssignmentMode();
     void StopLRAssignmentMode();
     ResultCode SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 279974ce9..d518fd069 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -9,6 +9,8 @@ namespace Service::HID {
 
 constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100};
 constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423};
+constexpr ResultCode NpadIsDualJoycon{ErrorModule::HID, 601};
+constexpr ResultCode NpadIsSameType{ErrorModule::HID, 602};
 constexpr ResultCode InvalidNpadId{ErrorModule::HID, 709};
 constexpr ResultCode NpadNotConnected{ErrorModule::HID, 710};
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index b41fc60d6..0520a8a38 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1090,14 +1090,14 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
     const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
 
     LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
               npad_id_1, npad_id_2, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {

From 390d49c5f17f12f98c80867915bb30991a40ea31 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 16:48:05 -0500
Subject: [PATCH 4/8] service: hid: Refractor sixaxis functions

---
 src/core/hle/service/hid/controllers/npad.cpp | 250 ++++++------------
 src/core/hle/service/hid/controllers/npad.h   |  23 +-
 2 files changed, 88 insertions(+), 185 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 4095a0a3c..8badefdec 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -582,6 +582,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
             UNREACHABLE();
             break;
         case Core::HID::NpadStyleIndex::ProController:
+        case Core::HID::NpadStyleIndex::Pokeball:
             set_motion_state(sixaxis_fullkey_state, motion_state[0]);
             break;
         case Core::HID::NpadStyleIndex::Handheld:
@@ -1007,96 +1008,47 @@ ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
     WriteEmptyEntry(shared_memory);
     return ResultSuccess;
 }
-
-ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
-                                                      GyroscopeZeroDriftMode drift_mode) {
+ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
 
-    auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        controller.sixaxis_fullkey.gyroscope_zero_drift_mode = drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        controller.sixaxis_handheld.gyroscope_zero_drift_mode = drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            controller.sixaxis_dual_left.gyroscope_zero_drift_mode = drift_mode;
-            break;
-        }
-        controller.sixaxis_dual_right.gyroscope_zero_drift_mode = drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        controller.sixaxis_left.gyroscope_zero_drift_mode = drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        controller.sixaxis_right.gyroscope_zero_drift_mode = drift_mode;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    sixaxis.gyroscope_zero_drift_mode = drift_mode;
 
     return ResultSuccess;
 }
 
-ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
-                                                      GyroscopeZeroDriftMode& drift_mode) const {
+ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+    GyroscopeZeroDriftMode& drift_mode) const {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
 
-    auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        drift_mode = controller.sixaxis_fullkey.gyroscope_zero_drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        drift_mode = controller.sixaxis_handheld.gyroscope_zero_drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            drift_mode = controller.sixaxis_dual_left.gyroscope_zero_drift_mode;
-            break;
-        }
-        drift_mode = controller.sixaxis_dual_right.gyroscope_zero_drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        drift_mode = controller.sixaxis_left.gyroscope_zero_drift_mode;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        drift_mode = controller.sixaxis_right.gyroscope_zero_drift_mode;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    drift_mode = sixaxis.gyroscope_zero_drift_mode;
 
     return ResultSuccess;
 }
 
-ResultCode Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle,
-                                                  bool& is_at_rest) const {
+ResultCode Controller_NPad::IsSixAxisSensorAtRest(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_at_rest) const {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
+
     const auto& controller = GetControllerFromHandle(sixaxis_handle);
     is_at_rest = controller.sixaxis_at_rest;
     return ResultSuccess;
 }
 
 ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
-    Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_firmware_available) const {
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
@@ -1107,7 +1059,7 @@ ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
     return ResultSuccess;
 }
 
-ResultCode Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
+ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                               bool sixaxis_status) {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
@@ -1119,82 +1071,32 @@ ResultCode Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle six
 }
 
 ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled(
-    Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_fusion_enabled) const {
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
 
-    auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        is_fusion_enabled = controller.sixaxis_fullkey.is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        is_fusion_enabled = controller.sixaxis_handheld.is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            is_fusion_enabled = controller.sixaxis_dual_left.is_fusion_enabled;
-            break;
-        }
-        is_fusion_enabled = controller.sixaxis_dual_right.is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        is_fusion_enabled = controller.sixaxis_left.is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        is_fusion_enabled = controller.sixaxis_right.is_fusion_enabled;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    is_fusion_enabled = sixaxis.is_fusion_enabled;
 
     return ResultSuccess;
 }
-ResultCode Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
-                                                    bool is_fusion_enabled) {
+ResultCode Controller_NPad::SetSixAxisFusionEnabled(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
 
-    auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        controller.sixaxis_fullkey.is_fusion_enabled = is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        controller.sixaxis_handheld.is_fusion_enabled = is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            controller.sixaxis_dual_left.is_fusion_enabled = is_fusion_enabled;
-            break;
-        }
-        controller.sixaxis_dual_right.is_fusion_enabled = is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        controller.sixaxis_left.is_fusion_enabled = is_fusion_enabled;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        controller.sixaxis_right.is_fusion_enabled = is_fusion_enabled;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    sixaxis.is_fusion_enabled = is_fusion_enabled;
 
     return ResultSuccess;
 }
 
 ResultCode Controller_NPad::SetSixAxisFusionParameters(
-    Core::HID::SixAxisSensorHandle sixaxis_handle,
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle,
     Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
@@ -1205,72 +1107,22 @@ ResultCode Controller_NPad::SetSixAxisFusionParameters(
         return InvalidSixAxisFusionRange;
     }
 
-    auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        controller.sixaxis_fullkey.fusion = sixaxis_fusion_parameters;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        controller.sixaxis_handheld.fusion = sixaxis_fusion_parameters;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            controller.sixaxis_dual_left.fusion = sixaxis_fusion_parameters;
-            break;
-        }
-        controller.sixaxis_dual_right.fusion = sixaxis_fusion_parameters;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        controller.sixaxis_left.fusion = sixaxis_fusion_parameters;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        controller.sixaxis_right.fusion = sixaxis_fusion_parameters;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    sixaxis.fusion = sixaxis_fusion_parameters;
 
     return ResultSuccess;
 }
 
 ResultCode Controller_NPad::GetSixAxisFusionParameters(
-    Core::HID::SixAxisSensorHandle sixaxis_handle,
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle,
     Core::HID::SixAxisSensorFusionParameters& parameters) const {
     if (!IsDeviceHandleValid(sixaxis_handle)) {
         LOG_ERROR(Service_HID, "Invalid handle");
         return NpadInvalidHandle;
     }
 
-    const auto& controller = GetControllerFromHandle(sixaxis_handle);
-    switch (sixaxis_handle.npad_type) {
-    case Core::HID::NpadStyleIndex::ProController:
-        parameters = controller.sixaxis_fullkey.fusion;
-        break;
-    case Core::HID::NpadStyleIndex::Handheld:
-        parameters = controller.sixaxis_handheld.fusion;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconDual:
-    case Core::HID::NpadStyleIndex::GameCube:
-    case Core::HID::NpadStyleIndex::Pokeball:
-        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
-            parameters = controller.sixaxis_dual_left.fusion;
-            break;
-        }
-        parameters = controller.sixaxis_dual_right.fusion;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconLeft:
-        parameters = controller.sixaxis_left.fusion;
-        break;
-    case Core::HID::NpadStyleIndex::JoyconRight:
-        parameters = controller.sixaxis_right.fusion;
-        break;
-    default:
-        LOG_ERROR(Service_HID, "Invalid Npad type {}", sixaxis_handle.npad_type);
-        return NpadInvalidHandle;
-    }
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    parameters = sixaxis.fusion;
 
     return ResultSuccess;
 }
@@ -1547,4 +1399,50 @@ const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpa
     return controller_data[npad_index];
 }
 
+Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
+    auto& controller = GetControllerFromHandle(sixaxis_handle);
+    switch (sixaxis_handle.npad_type) {
+    case Core::HID::NpadStyleIndex::ProController:
+    case Core::HID::NpadStyleIndex::Pokeball:
+        return controller.sixaxis_fullkey;
+    case Core::HID::NpadStyleIndex::Handheld:
+        return controller.sixaxis_handheld;
+    case Core::HID::NpadStyleIndex::JoyconDual:
+        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
+            return controller.sixaxis_dual_left;
+        }
+        return controller.sixaxis_dual_right;
+    case Core::HID::NpadStyleIndex::JoyconLeft:
+        return controller.sixaxis_left;
+    case Core::HID::NpadStyleIndex::JoyconRight:
+        return controller.sixaxis_right;
+    default:
+        return controller.sixaxis_unknown;
+    }
+}
+
+const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
+    const auto& controller = GetControllerFromHandle(sixaxis_handle);
+    switch (sixaxis_handle.npad_type) {
+    case Core::HID::NpadStyleIndex::ProController:
+    case Core::HID::NpadStyleIndex::Pokeball:
+        return controller.sixaxis_fullkey;
+    case Core::HID::NpadStyleIndex::Handheld:
+        return controller.sixaxis_handheld;
+    case Core::HID::NpadStyleIndex::JoyconDual:
+        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
+            return controller.sixaxis_dual_left;
+        }
+        return controller.sixaxis_dual_right;
+    case Core::HID::NpadStyleIndex::JoyconLeft:
+        return controller.sixaxis_left;
+    case Core::HID::NpadStyleIndex::JoyconRight:
+        return controller.sixaxis_right;
+    default:
+        return controller.sixaxis_unknown;
+    }
+}
+
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 5305e8cf8..dfb4de740 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -143,25 +143,25 @@ public:
 
     ResultCode DisconnectNpad(Core::HID::NpadIdType npad_id);
 
-    ResultCode SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
+    ResultCode SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                          GyroscopeZeroDriftMode drift_mode);
-    ResultCode GetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
+    ResultCode GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                          GyroscopeZeroDriftMode& drift_mode) const;
-    ResultCode IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle,
+    ResultCode IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                      bool& is_at_rest) const;
     ResultCode IsFirmwareUpdateAvailableForSixAxisSensor(
-        Core::HID::SixAxisSensorHandle sixaxis_handle, bool& is_firmware_available) const;
-    ResultCode SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const;
+    ResultCode SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                  bool sixaxis_status);
-    ResultCode IsSixAxisSensorFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
+    ResultCode IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                             bool& is_fusion_enabled) const;
-    ResultCode SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
+    ResultCode SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                        bool is_fusion_enabled);
     ResultCode SetSixAxisFusionParameters(
-        Core::HID::SixAxisSensorHandle sixaxis_handle,
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle,
         Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
     ResultCode GetSixAxisFusionParameters(
-        Core::HID::SixAxisSensorHandle sixaxis_handle,
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle,
         Core::HID::SixAxisSensorFusionParameters& parameters) const;
     ResultCode GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
     ResultCode IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@@ -493,6 +493,7 @@ private:
         SixaxisParameters sixaxis_dual_right{};
         SixaxisParameters sixaxis_left{};
         SixaxisParameters sixaxis_right{};
+        SixaxisParameters sixaxis_unknown{};
 
         // Current pad state
         NPadGenericState npad_pad_state{};
@@ -524,6 +525,10 @@ private:
     NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
     const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
 
+    SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
+    const SixaxisParameters& GetSixaxisState(
+        const Core::HID::SixAxisSensorHandle& device_handle) const;
+
     std::atomic<u64> press_state{};
 
     std::array<NpadControllerData, NPAD_COUNT> controller_data{};

From 762a30d0dbb2505c6f2b1691ec7d712a8b58adc7 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 16:56:06 -0500
Subject: [PATCH 5/8] service: hid: Add error handling to sixaxis functions

---
 src/core/hle/service/hid/controllers/npad.cpp | 82 ++++++++++++-------
 src/core/hle/service/hid/controllers/npad.h   |  3 +-
 src/core/hle/service/hid/errors.h             |  1 +
 3 files changed, 55 insertions(+), 31 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 8badefdec..ef6befbd9 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -56,11 +56,22 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle
     return npad_id && npad_type && device_index;
 }
 
-bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) {
+ResultCode Controller_NPad::VerifyValidSixAxisSensorHandle(
+    const Core::HID::SixAxisSensorHandle& device_handle) {
     const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
-    const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
+    if (!npad_id) {
+        return InvalidNpadId;
+    }
     const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
-    return npad_id && npad_type && device_index;
+    if (!device_index) {
+        return NpadDeviceIndexOutOfRange;
+    }
+    // This doesn't get validaded on nnsdk
+    const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
+    if (!npad_type) {
+        return NpadInvalidHandle;
+    }
+    return ResultSuccess;
 }
 
 Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
@@ -1010,9 +1021,10 @@ ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
 }
 ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     auto& sixaxis = GetSixaxisState(sixaxis_handle);
@@ -1024,9 +1036,10 @@ ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(
 ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle,
     GyroscopeZeroDriftMode& drift_mode) const {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     const auto& sixaxis = GetSixaxisState(sixaxis_handle);
@@ -1037,9 +1050,10 @@ ResultCode Controller_NPad::GetGyroscopeZeroDriftMode(
 
 ResultCode Controller_NPad::IsSixAxisSensorAtRest(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_at_rest) const {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     const auto& controller = GetControllerFromHandle(sixaxis_handle);
@@ -1049,9 +1063,10 @@ ResultCode Controller_NPad::IsSixAxisSensorAtRest(
 
 ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     // We don't support joycon firmware updates
@@ -1061,10 +1076,12 @@ ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
 
 ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                               bool sixaxis_status) {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
+
     auto& controller = GetControllerFromHandle(sixaxis_handle);
     controller.sixaxis_sensor_enabled = sixaxis_status;
     return ResultSuccess;
@@ -1072,9 +1089,10 @@ ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHand
 
 ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     const auto& sixaxis = GetSixaxisState(sixaxis_handle);
@@ -1084,9 +1102,10 @@ ResultCode Controller_NPad::IsSixAxisSensorFusionEnabled(
 }
 ResultCode Controller_NPad::SetSixAxisFusionEnabled(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     auto& sixaxis = GetSixaxisState(sixaxis_handle);
@@ -1098,10 +1117,12 @@ ResultCode Controller_NPad::SetSixAxisFusionEnabled(
 ResultCode Controller_NPad::SetSixAxisFusionParameters(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle,
     Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
+
     const auto param1 = sixaxis_fusion_parameters.parameter1;
     if (param1 < 0.0f || param1 > 1.0f) {
         return InvalidSixAxisFusionRange;
@@ -1116,9 +1137,10 @@ ResultCode Controller_NPad::SetSixAxisFusionParameters(
 ResultCode Controller_NPad::GetSixAxisFusionParameters(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle,
     Core::HID::SixAxisSensorFusionParameters& parameters) const {
-    if (!IsDeviceHandleValid(sixaxis_handle)) {
-        LOG_ERROR(Service_HID, "Invalid handle");
-        return NpadInvalidHandle;
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
     }
 
     const auto& sixaxis = GetSixaxisState(sixaxis_handle);
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index dfb4de740..e6125ffcc 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -185,8 +185,9 @@ public:
     Core::HID::NpadButton GetAndResetPressState();
 
     static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
-    static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle);
     static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
+    static ResultCode VerifyValidSixAxisSensorHandle(
+        const Core::HID::SixAxisSensorHandle& device_handle);
 
 private:
     static constexpr std::size_t NPAD_COUNT = 10;
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index d518fd069..6c8ad04af 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -8,6 +8,7 @@
 namespace Service::HID {
 
 constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100};
+constexpr ResultCode NpadDeviceIndexOutOfRange{ErrorModule::HID, 107};
 constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423};
 constexpr ResultCode NpadIsDualJoycon{ErrorModule::HID, 601};
 constexpr ResultCode NpadIsSameType{ErrorModule::HID, 602};

From c889a5805e72dc34527cc99456d0c6727266ef39 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 17:03:08 -0500
Subject: [PATCH 6/8] service: hid: Implement
 EnableSixAxisSensorUnalteredPassthrough and
 IsSixAxisSensorUnalteredPassthroughEnabled

Needed by Nintendo Switch Sports
---
 src/core/hle/service/hid/controllers/npad.cpp | 26 +++++++++
 src/core/hle/service/hid/controllers/npad.h   |  5 ++
 src/core/hle/service/hid/hid.cpp              | 57 ++++++++++++++++++-
 src/core/hle/service/hid/hid.h                |  2 +
 4 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ef6befbd9..c9909ad5a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -1074,6 +1074,32 @@ ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
     return ResultSuccess;
 }
 
+ResultCode Controller_NPad::EnableSixAxisSensorUnalteredPassthrough(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) {
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
+    }
+
+    auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    sixaxis.unaltered_passtrough = is_enabled;
+    return ResultSuccess;
+}
+
+ResultCode Controller_NPad::IsSixAxisSensorUnalteredPassthroughEnabled(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const {
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
+    }
+
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    is_enabled = sixaxis.unaltered_passtrough;
+    return ResultSuccess;
+}
+
 ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                               bool sixaxis_status) {
     const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index e6125ffcc..951f46425 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -151,6 +151,10 @@ public:
                                      bool& is_at_rest) const;
     ResultCode IsFirmwareUpdateAvailableForSixAxisSensor(
         const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const;
+    ResultCode EnableSixAxisSensorUnalteredPassthrough(
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
+    ResultCode IsSixAxisSensorUnalteredPassthroughEnabled(
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
     ResultCode SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                  bool sixaxis_status);
     ResultCode IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
@@ -468,6 +472,7 @@ private:
 
     struct SixaxisParameters {
         bool is_fusion_enabled{true};
+        bool unaltered_passtrough{false};
         Core::HID::SixAxisSensorFusionParameters fusion{};
         GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
     };
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 0520a8a38..1fb3b790c 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -257,8 +257,8 @@ Hid::Hid(Core::System& system_)
         {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
         {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
         {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
-        {84, nullptr, "EnableSixAxisSensorUnalteredPassthrough"},
-        {85, nullptr, "IsSixAxisSensorUnalteredPassthroughEnabled"},
+        {84, &Hid::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
+        {85, &Hid::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
         {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
         {87, nullptr, "LoadSixAxisSensorCalibrationParameter"},
         {88, nullptr, "GetSixAxisSensorIcInformation"},
@@ -817,6 +817,59 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
     rb.Push(is_firmware_available);
 }
 
+void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        bool enabled;
+        Core::HID::SixAxisSensorHandle sixaxis_handle;
+        u64 applet_resource_user_id;
+    };
+    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
+        parameters.sixaxis_handle, parameters.enabled);
+
+    LOG_WARNING(Service_HID,
+                "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
+                "applet_resource_user_id={}",
+                parameters.enabled, parameters.sixaxis_handle.npad_type,
+                parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
+                parameters.applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
+void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        Core::HID::SixAxisSensorHandle sixaxis_handle;
+        INSERT_PADDING_WORDS_NOINIT(1);
+        u64 applet_resource_user_id;
+    };
+    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    bool is_unaltered_sisxaxis_enabled{};
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
+        parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(result);
+    rb.Push(is_unaltered_sisxaxis_enabled);
+}
+
 void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     struct Parameters {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 1be04c22b..b8515a002 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -113,6 +113,8 @@ private:
     void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
     void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
     void IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx);
+    void EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx);
+    void IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx);
     void ActivateGesture(Kernel::HLERequestContext& ctx);
     void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
     void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);

From 240f59a4c8319ec5f0c0e5fd34e8f9c5a458751e Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 17:10:20 -0500
Subject: [PATCH 7/8] service: hid: Implement
 LoadSixAxisSensorCalibrationParameter and GetSixAxisSensorIcInformation

Needed by Nintendo Switch Sports
---
 src/core/hid/hid_types.h                      | 33 ++++++++++
 src/core/hle/service/hid/controllers/npad.cpp | 32 +++++++++-
 src/core/hle/service/hid/controllers/npad.h   |  8 +++
 src/core/hle/service/hid/hid.cpp              | 64 ++++++++++++++++++-
 src/core/hle/service/hid/hid.h                |  2 +
 5 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 26ec1091b..00ba23535 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -498,6 +498,39 @@ struct SixAxisSensorFusionParameters {
 static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
               "SixAxisSensorFusionParameters is an invalid size");
 
+// This is nn::hid::SixAxisSensorCalibrationParameter
+struct SixAxisSensorCalibrationParameter {
+    std::array<u8, 0x744> unknown_data{};
+};
+static_assert(sizeof(SixAxisSensorCalibrationParameter) == 0x744,
+              "SixAxisSensorCalibrationParameter is an invalid size");
+
+// This is nn::hid::SixAxisSensorIcInformation
+struct SixAxisSensorIcInformation {
+    f32 angular_rate{2000.0f}; // dps
+    std::array<f32, 6> unknown_gyro_data1{
+        -10.0f, -10.0f, -10.0f, 10.0f, 10.0f, 10.0f,
+    }; // dps
+    std::array<f32, 9> unknown_gyro_data2{
+        0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
+    };
+    std::array<f32, 9> unknown_gyro_data3{
+        1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
+    };
+    f32 acceleration_range{8.0f}; // g force
+    std::array<f32, 6> unknown_accel_data1{
+        -0.0612f, -0.0612f, -0.0612f, 0.0612f, 0.0612f, 0.0612f,
+    }; // g force
+    std::array<f32, 9> unknown_accel_data2{
+        0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
+    };
+    std::array<f32, 9> unknown_accel_data3{
+        1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
+    };
+};
+static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8,
+              "SixAxisSensorIcInformation is an invalid size");
+
 // This is nn::hid::VibrationDeviceHandle
 struct VibrationDeviceHandle {
     NpadStyleIndex npad_type{NpadStyleIndex::None};
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index c9909ad5a..9ce25c641 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -66,7 +66,7 @@ ResultCode Controller_NPad::VerifyValidSixAxisSensorHandle(
     if (!device_index) {
         return NpadDeviceIndexOutOfRange;
     }
-    // This doesn't get validaded on nnsdk
+    // This doesn't get validated on nnsdk
     const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
     if (!npad_type) {
         return NpadInvalidHandle;
@@ -1100,6 +1100,36 @@ ResultCode Controller_NPad::IsSixAxisSensorUnalteredPassthroughEnabled(
     return ResultSuccess;
 }
 
+ResultCode Controller_NPad::LoadSixAxisSensorCalibrationParameter(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+    Core::HID::SixAxisSensorCalibrationParameter& calibration) const {
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
+    }
+
+    // TODO: Request this data to the controller. On error return 0xd8ca
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    calibration = sixaxis.calibration;
+    return ResultSuccess;
+}
+
+ResultCode Controller_NPad::GetSixAxisSensorIcInformation(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+    Core::HID::SixAxisSensorIcInformation& ic_information) const {
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
+    }
+
+    // TODO: Request this data to the controller. On error return 0xd8ca
+    const auto& sixaxis = GetSixaxisState(sixaxis_handle);
+    ic_information = sixaxis.ic_information;
+    return ResultSuccess;
+}
+
 ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                               bool sixaxis_status) {
     const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 951f46425..2e2e1d07f 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -155,6 +155,12 @@ public:
         const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
     ResultCode IsSixAxisSensorUnalteredPassthroughEnabled(
         const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
+    ResultCode LoadSixAxisSensorCalibrationParameter(
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+        Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
+    ResultCode GetSixAxisSensorIcInformation(
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+        Core::HID::SixAxisSensorIcInformation& ic_information) const;
     ResultCode SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                  bool sixaxis_status);
     ResultCode IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
@@ -474,6 +480,8 @@ private:
         bool is_fusion_enabled{true};
         bool unaltered_passtrough{false};
         Core::HID::SixAxisSensorFusionParameters fusion{};
+        Core::HID::SixAxisSensorCalibrationParameter calibration{};
+        Core::HID::SixAxisSensorIcInformation ic_information{};
         GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
     };
 
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1fb3b790c..19d12cf51 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -260,8 +260,8 @@ Hid::Hid(Core::System& system_)
         {84, &Hid::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
         {85, &Hid::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
         {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
-        {87, nullptr, "LoadSixAxisSensorCalibrationParameter"},
-        {88, nullptr, "GetSixAxisSensorIcInformation"},
+        {87, &Hid::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
+        {88, &Hid::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
         {89, nullptr, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
         {91, &Hid::ActivateGesture, "ActivateGesture"},
         {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
@@ -870,6 +870,66 @@ void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext&
     rb.Push(is_unaltered_sisxaxis_enabled);
 }
 
+void Hid::LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        Core::HID::SixAxisSensorHandle sixaxis_handle;
+        INSERT_PADDING_WORDS_NOINIT(1);
+        u64 applet_resource_user_id;
+    };
+    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    Core::HID::SixAxisSensorCalibrationParameter calibration{};
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result =
+        controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(calibration);
+    }
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
+void Hid::GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        Core::HID::SixAxisSensorHandle sixaxis_handle;
+        INSERT_PADDING_WORDS_NOINIT(1);
+        u64 applet_resource_user_id;
+    };
+    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    Core::HID::SixAxisSensorIcInformation ic_information{};
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result =
+        controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+    if (result.IsSuccess()) {
+        ctx.WriteBuffer(ic_information);
+    }
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
 void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     struct Parameters {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index b8515a002..726a031de 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -115,6 +115,8 @@ private:
     void IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx);
     void EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx);
     void IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx);
+    void LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx);
+    void GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx);
     void ActivateGesture(Kernel::HLERequestContext& ctx);
     void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
     void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);

From a1f2610522dd7d66f370dacc821f2b30029a218e Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sat, 21 May 2022 17:21:45 -0500
Subject: [PATCH 8/8] service: hid: Implement
 ResetIsSixAxisSensorDeviceNewlyAssigned

Needed by Nintendo Switch Sports
---
 src/core/hid/hid_types.h                      | 10 +++
 src/core/hle/service/hid/controllers/npad.cpp | 77 ++++++++++++++++++-
 src/core/hle/service/hid/controllers/npad.h   | 16 +++-
 src/core/hle/service/hid/hid.cpp              | 27 ++++++-
 src/core/hle/service/hid/hid.h                |  1 +
 5 files changed, 125 insertions(+), 6 deletions(-)

diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 00ba23535..9f76f9bcb 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -498,6 +498,16 @@ struct SixAxisSensorFusionParameters {
 static_assert(sizeof(SixAxisSensorFusionParameters) == 8,
               "SixAxisSensorFusionParameters is an invalid size");
 
+// This is nn::hid::server::SixAxisSensorProperties
+struct SixAxisSensorProperties {
+    union {
+        u8 raw{};
+        BitField<0, 1, u8> is_newly_assigned;
+        BitField<1, 1, u8> is_firmware_update_available;
+    };
+};
+static_assert(sizeof(SixAxisSensorProperties) == 1, "SixAxisSensorProperties is an invalid size");
+
 // This is nn::hid::SixAxisSensorCalibrationParameter
 struct SixAxisSensorCalibrationParameter {
     std::array<u8, 0x744> unknown_data{};
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 9ce25c641..1e04ee3f2 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -169,6 +169,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
         shared_memory->system_properties.use_plus.Assign(1);
         shared_memory->system_properties.use_minus.Assign(1);
         shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
+        shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
         break;
     case Core::HID::NpadStyleIndex::Handheld:
         shared_memory->style_tag.handheld.Assign(1);
@@ -181,16 +182,19 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
         shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
         shared_memory->applet_nfc_xcd.applet_footer.type =
             AppletFooterUiType::HandheldJoyConLeftJoyConRight;
+        shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
         break;
     case Core::HID::NpadStyleIndex::JoyconDual:
         shared_memory->style_tag.joycon_dual.Assign(1);
         if (controller.is_dual_left_connected) {
             shared_memory->device_type.joycon_left.Assign(1);
             shared_memory->system_properties.use_minus.Assign(1);
+            shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
         }
         if (controller.is_dual_right_connected) {
             shared_memory->device_type.joycon_right.Assign(1);
             shared_memory->system_properties.use_plus.Assign(1);
+            shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
         }
         shared_memory->system_properties.use_directional_buttons.Assign(1);
         shared_memory->system_properties.is_vertical.Assign(1);
@@ -209,6 +213,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
         shared_memory->system_properties.is_horizontal.Assign(1);
         shared_memory->system_properties.use_minus.Assign(1);
         shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
+        shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
         break;
     case Core::HID::NpadStyleIndex::JoyconRight:
         shared_memory->style_tag.joycon_right.Assign(1);
@@ -216,6 +221,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
         shared_memory->system_properties.is_horizontal.Assign(1);
         shared_memory->system_properties.use_plus.Assign(1);
         shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
+        shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
         break;
     case Core::HID::NpadStyleIndex::GameCube:
         shared_memory->style_tag.gamecube.Assign(1);
@@ -226,6 +232,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
     case Core::HID::NpadStyleIndex::Pokeball:
         shared_memory->style_tag.palma.Assign(1);
         shared_memory->device_type.palma.Assign(1);
+        shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
         break;
     case Core::HID::NpadStyleIndex::NES:
         shared_memory->style_tag.lark.Assign(1);
@@ -997,6 +1004,12 @@ ResultCode Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
     shared_memory->device_type.raw = 0;
     shared_memory->system_properties.raw = 0;
     shared_memory->button_properties.raw = 0;
+    shared_memory->sixaxis_fullkey_properties.raw = 0;
+    shared_memory->sixaxis_handheld_properties.raw = 0;
+    shared_memory->sixaxis_dual_left_properties.raw = 0;
+    shared_memory->sixaxis_dual_right_properties.raw = 0;
+    shared_memory->sixaxis_left_properties.raw = 0;
+    shared_memory->sixaxis_right_properties.raw = 0;
     shared_memory->battery_level_dual = 0;
     shared_memory->battery_level_left = 0;
     shared_memory->battery_level_right = 0;
@@ -1069,8 +1082,8 @@ ResultCode Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
         return is_valid;
     }
 
-    // We don't support joycon firmware updates
-    is_firmware_available = false;
+    const auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle);
+    is_firmware_available = sixaxis_properties.is_firmware_update_available != 0;
     return ResultSuccess;
 }
 
@@ -1130,6 +1143,20 @@ ResultCode Controller_NPad::GetSixAxisSensorIcInformation(
     return ResultSuccess;
 }
 
+ResultCode Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
+    const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
+    if (is_valid.IsError()) {
+        LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
+        return is_valid;
+    }
+
+    auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle);
+    sixaxis_properties.is_newly_assigned.Assign(0);
+
+    return ResultSuccess;
+}
+
 ResultCode Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                               bool sixaxis_status) {
     const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
@@ -1477,6 +1504,52 @@ const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpa
     return controller_data[npad_index];
 }
 
+Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
+    auto& controller = GetControllerFromHandle(sixaxis_handle);
+    switch (sixaxis_handle.npad_type) {
+    case Core::HID::NpadStyleIndex::ProController:
+    case Core::HID::NpadStyleIndex::Pokeball:
+        return controller.shared_memory->sixaxis_fullkey_properties;
+    case Core::HID::NpadStyleIndex::Handheld:
+        return controller.shared_memory->sixaxis_handheld_properties;
+    case Core::HID::NpadStyleIndex::JoyconDual:
+        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
+            return controller.shared_memory->sixaxis_dual_left_properties;
+        }
+        return controller.shared_memory->sixaxis_dual_right_properties;
+    case Core::HID::NpadStyleIndex::JoyconLeft:
+        return controller.shared_memory->sixaxis_left_properties;
+    case Core::HID::NpadStyleIndex::JoyconRight:
+        return controller.shared_memory->sixaxis_right_properties;
+    default:
+        return controller.shared_memory->sixaxis_fullkey_properties;
+    }
+}
+
+const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties(
+    const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
+    const auto& controller = GetControllerFromHandle(sixaxis_handle);
+    switch (sixaxis_handle.npad_type) {
+    case Core::HID::NpadStyleIndex::ProController:
+    case Core::HID::NpadStyleIndex::Pokeball:
+        return controller.shared_memory->sixaxis_fullkey_properties;
+    case Core::HID::NpadStyleIndex::Handheld:
+        return controller.shared_memory->sixaxis_handheld_properties;
+    case Core::HID::NpadStyleIndex::JoyconDual:
+        if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
+            return controller.shared_memory->sixaxis_dual_left_properties;
+        }
+        return controller.shared_memory->sixaxis_dual_right_properties;
+    case Core::HID::NpadStyleIndex::JoyconLeft:
+        return controller.shared_memory->sixaxis_left_properties;
+    case Core::HID::NpadStyleIndex::JoyconRight:
+        return controller.shared_memory->sixaxis_right_properties;
+    default:
+        return controller.shared_memory->sixaxis_fullkey_properties;
+    }
+}
+
 Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
     const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
     auto& controller = GetControllerFromHandle(sixaxis_handle);
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 2e2e1d07f..0b662b7f8 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -161,6 +161,8 @@ public:
     ResultCode GetSixAxisSensorIcInformation(
         const Core::HID::SixAxisSensorHandle& sixaxis_handle,
         Core::HID::SixAxisSensorIcInformation& ic_information) const;
+    ResultCode ResetIsSixAxisSensorDeviceNewlyAssigned(
+        const Core::HID::SixAxisSensorHandle& sixaxis_handle);
     ResultCode SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
                                  bool sixaxis_status);
     ResultCode IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
@@ -464,9 +466,13 @@ private:
         NpadLuciaType lucia_type{};
         NpadLagonType lagon_type{};
         NpadLagerType lager_type{};
-        // FW 13.x Investigate there is some sort of bitflag related to joycons
-        INSERT_PADDING_BYTES(0x4);
-        INSERT_PADDING_BYTES(0xc08); // Unknown
+        Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
+        Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
+        Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
+        Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
+        Core::HID::SixAxisSensorProperties sixaxis_left_properties;
+        Core::HID::SixAxisSensorProperties sixaxis_right_properties;
+        INSERT_PADDING_BYTES(0xc06); // Unknown
     };
     static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
 
@@ -539,6 +545,10 @@ private:
     NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
     const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
 
+    Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
+        const Core::HID::SixAxisSensorHandle& device_handle);
+    const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
+        const Core::HID::SixAxisSensorHandle& device_handle) const;
     SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
     const SixaxisParameters& GetSixaxisState(
         const Core::HID::SixAxisSensorHandle& device_handle) const;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 19d12cf51..8a496c38c 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -262,7 +262,7 @@ Hid::Hid(Core::System& system_)
         {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
         {87, &Hid::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
         {88, &Hid::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
-        {89, nullptr, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
+        {89, &Hid::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
         {91, &Hid::ActivateGesture, "ActivateGesture"},
         {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
         {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
@@ -930,6 +930,31 @@ void Hid::GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx) {
     rb.Push(result);
 }
 
+void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    struct Parameters {
+        Core::HID::SixAxisSensorHandle sixaxis_handle;
+        INSERT_PADDING_WORDS_NOINIT(1);
+        u64 applet_resource_user_id;
+    };
+    static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+    const auto parameters{rp.PopRaw<Parameters>()};
+
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result =
+        controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
+
+    LOG_WARNING(
+        Service_HID,
+        "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+        parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+        parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(result);
+}
+
 void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp{ctx};
     struct Parameters {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 726a031de..ac4333022 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -117,6 +117,7 @@ private:
     void IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx);
     void LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx);
     void GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx);
+    void ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx);
     void ActivateGesture(Kernel::HLERequestContext& ctx);
     void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
     void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);