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] 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 00ba23535b..9f76f9bcb6 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 9ce25c6413..1e04ee3f28 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 2e2e1d07f9..0b662b7f88 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 19d12cf514..8a496c38cf 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 726a031dee..ac43330223 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);