From af1183a9938d885a643efaf28397235a4d1bd2ef Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Wed, 4 Nov 2020 11:21:17 -0500
Subject: [PATCH] applets/controller: Introduce additional checks for mode and
 caller

Some games like Cave Story+ set invalid values in the ControllerPrivateArg's mode and caller fields.
Use other fields to determine the appropriate mode and caller should either or both fields be invalid.
---
 .../hle/service/am/applets/controller.cpp     | 30 +++++++++++++++++++
 src/core/hle/service/am/applets/controller.h  | 14 +++++----
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index 2151da783..6b8eeabf4 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -75,6 +75,36 @@ void Controller::Initialize() {
                "Unknown ControllerSupportArgPrivate revision={} with size={}",
                library_applet_version, controller_private_arg.arg_private_size);
 
+    // Some games such as Cave Story+ set invalid values for the ControllerSupportMode.
+    // Defer to arg_size to set the ControllerSupportMode.
+    if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) {
+        switch (controller_private_arg.arg_size) {
+        case sizeof(ControllerSupportArgOld):
+        case sizeof(ControllerSupportArgNew):
+            controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
+            break;
+        case sizeof(ControllerUpdateFirmwareArg):
+            controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate;
+            break;
+        default:
+            UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}",
+                              controller_private_arg.mode, controller_private_arg.arg_size);
+            controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
+            break;
+        }
+    }
+
+    // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller.
+    // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem.
+    if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) {
+        if (controller_private_arg.flag_1 &&
+            controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) {
+            controller_private_arg.caller = ControllerSupportCaller::System;
+        } else {
+            controller_private_arg.caller = ControllerSupportCaller::Application;
+        }
+    }
+
     switch (controller_private_arg.mode) {
     case ControllerSupportMode::ShowControllerSupport: {
         const auto user_arg_storage = broker.PopNormalDataToApplet();
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
index 86269190b..05788966e 100644
--- a/src/core/hle/service/am/applets/controller.h
+++ b/src/core/hle/service/am/applets/controller.h
@@ -29,14 +29,18 @@ enum class LibraryAppletVersion : u32_le {
 };
 
 enum class ControllerSupportMode : u8 {
-    ShowControllerSupport = 0,
-    ShowControllerStrapGuide = 1,
-    ShowControllerFirmwareUpdate = 2,
+    ShowControllerSupport,
+    ShowControllerStrapGuide,
+    ShowControllerFirmwareUpdate,
+
+    MaxControllerSupportMode,
 };
 
 enum class ControllerSupportCaller : u8 {
-    Application = 0,
-    System = 1,
+    Application,
+    System,
+
+    MaxControllerSupportCaller,
 };
 
 struct ControllerSupportArgPrivate {