summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/AndroidManifest.xml3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt9
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt219
-rw-r--r--src/android/app/src/main/jni/native.cpp16
-rw-r--r--src/android/app/src/main/res/values/strings.xml10
-rw-r--r--src/android/app/src/main/res/xml/game_mode_config.xml7
-rw-r--r--src/core/file_sys/savedata_factory.cpp9
-rw-r--r--src/core/file_sys/savedata_factory.h1
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp60
-rw-r--r--src/core/hle/service/hid/hid_system_server.h6
-rw-r--r--src/hid_core/resource_manager.cpp1
-rw-r--r--src/hid_core/resources/applet_resource.cpp34
-rw-r--r--src/hid_core/resources/npad/npad.cpp5
-rw-r--r--src/hid_core/resources/npad/npad_resource.cpp4
14 files changed, 357 insertions, 27 deletions
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index f10131b24..f011bd696 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -31,6 +31,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:dataExtractionRules="@xml/data_extraction_rules_api_31"
android:enableOnBackInvokedCallback="true">
+ <meta-data android:name="android.game_mode_config"
+ android:resource="@xml/game_mode_config" />
+
<activity
android:name="org.yuzu.yuzu_emu.ui.main.MainActivity"
android:exported="true"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 010c44951..b7556e353 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -548,6 +548,15 @@ object NativeLibrary {
external fun getSavePath(programId: String): String
/**
+ * Gets the root save directory for the default profile as either
+ * /user/save/account/<user id raw string> or /user/save/000...000/<user id>
+ *
+ * @param future If true, returns the /user/save/account/... directory
+ * @return Save data path that may not exist yet
+ */
+ external fun getDefaultProfileSaveDataRoot(future: Boolean): String
+
+ /**
* Adds a file to the manual filesystem provider in our EmulationSession instance
* @param path Path to the file we're adding. Can be a string representation of a [Uri] or
* a normal path
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
index 569727b90..5b4bf2c9f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
@@ -7,20 +7,39 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
+import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.InstallableAdapter
import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.Installable
+import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.ui.main.MainActivity
+import org.yuzu.yuzu_emu.utils.DirectoryInitialization
+import org.yuzu.yuzu_emu.utils.FileUtil
+import java.io.BufferedInputStream
+import java.io.BufferedOutputStream
+import java.io.File
+import java.math.BigInteger
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
class InstallableFragment : Fragment() {
private var _binding: FragmentInstallablesBinding? = null
@@ -56,6 +75,17 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack()
}
+ viewLifecycleOwner.lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ homeViewModel.openImportSaves.collect {
+ if (it) {
+ importSaves.launch(arrayOf("application/zip"))
+ homeViewModel.setOpenImportSaves(false)
+ }
+ }
+ }
+ }
+
val installables = listOf(
Installable(
R.string.user_data,
@@ -64,6 +94,43 @@ class InstallableFragment : Fragment() {
export = { mainActivity.exportUserData.launch("export.zip") }
),
Installable(
+ R.string.manage_save_data,
+ R.string.manage_save_data_description,
+ install = {
+ MessageDialogFragment.newInstance(
+ requireActivity(),
+ titleId = R.string.import_save_warning,
+ descriptionId = R.string.import_save_warning_description,
+ positiveAction = { homeViewModel.setOpenImportSaves(true) }
+ ).show(parentFragmentManager, MessageDialogFragment.TAG)
+ },
+ export = {
+ val oldSaveDataFolder = File(
+ "${DirectoryInitialization.userDirectory}/nand" +
+ NativeLibrary.getDefaultProfileSaveDataRoot(false)
+ )
+ val futureSaveDataFolder = File(
+ "${DirectoryInitialization.userDirectory}/nand" +
+ NativeLibrary.getDefaultProfileSaveDataRoot(true)
+ )
+ if (!oldSaveDataFolder.exists() && !futureSaveDataFolder.exists()) {
+ Toast.makeText(
+ YuzuApplication.appContext,
+ R.string.no_save_data_found,
+ Toast.LENGTH_SHORT
+ ).show()
+ return@Installable
+ } else {
+ exportSaves.launch(
+ "${getString(R.string.save_data)} " +
+ LocalDateTime.now().format(
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
+ )
+ )
+ }
+ }
+ ),
+ Installable(
R.string.install_game_content,
R.string.install_game_content_description,
install = { mainActivity.installGameUpdate.launch(arrayOf("*/*")) }
@@ -121,4 +188,156 @@ class InstallableFragment : Fragment() {
windowInsets
}
+
+ private val importSaves =
+ registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
+ if (result == null) {
+ return@registerForActivityResult
+ }
+
+ val inputZip = requireContext().contentResolver.openInputStream(result)
+ val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
+ cacheSaveDir.mkdir()
+
+ if (inputZip == null) {
+ Toast.makeText(
+ YuzuApplication.appContext,
+ getString(R.string.fatal_error),
+ Toast.LENGTH_LONG
+ ).show()
+ return@registerForActivityResult
+ }
+
+ IndeterminateProgressDialogFragment.newInstance(
+ requireActivity(),
+ R.string.save_files_importing,
+ false
+ ) {
+ try {
+ FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir)
+ val files = cacheSaveDir.listFiles()
+ var successfulImports = 0
+ var failedImports = 0
+ if (files != null) {
+ for (file in files) {
+ if (file.isDirectory) {
+ val baseSaveDir =
+ NativeLibrary.getSavePath(BigInteger(file.name, 16).toString())
+ if (baseSaveDir.isEmpty()) {
+ failedImports++
+ continue
+ }
+
+ val internalSaveFolder = File(
+ "${DirectoryInitialization.userDirectory}/nand$baseSaveDir"
+ )
+ internalSaveFolder.deleteRecursively()
+ internalSaveFolder.mkdir()
+ file.copyRecursively(target = internalSaveFolder, overwrite = true)
+ successfulImports++
+ }
+ }
+ }
+
+ withContext(Dispatchers.Main) {
+ if (successfulImports == 0) {
+ MessageDialogFragment.newInstance(
+ requireActivity(),
+ titleId = R.string.save_file_invalid_zip_structure,
+ descriptionId = R.string.save_file_invalid_zip_structure_description
+ ).show(parentFragmentManager, MessageDialogFragment.TAG)
+ return@withContext
+ }
+ val successString = if (failedImports > 0) {
+ """
+ ${
+ requireContext().resources.getQuantityString(
+ R.plurals.saves_import_success,
+ successfulImports,
+ successfulImports
+ )
+ }
+ ${
+ requireContext().resources.getQuantityString(
+ R.plurals.saves_import_failed,
+ failedImports,
+ failedImports
+ )
+ }
+ """
+ } else {
+ requireContext().resources.getQuantityString(
+ R.plurals.saves_import_success,
+ successfulImports,
+ successfulImports
+ )
+ }
+ MessageDialogFragment.newInstance(
+ requireActivity(),
+ titleId = R.string.import_complete,
+ descriptionString = successString
+ ).show(parentFragmentManager, MessageDialogFragment.TAG)
+ }
+
+ cacheSaveDir.deleteRecursively()
+ } catch (e: Exception) {
+ Toast.makeText(
+ YuzuApplication.appContext,
+ getString(R.string.fatal_error),
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
+ }
+
+ private val exportSaves = registerForActivityResult(
+ ActivityResultContracts.CreateDocument("application/zip")
+ ) { result ->
+ if (result == null) {
+ return@registerForActivityResult
+ }
+
+ IndeterminateProgressDialogFragment.newInstance(
+ requireActivity(),
+ R.string.save_files_exporting,
+ false
+ ) {
+ val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/")
+ cacheSaveDir.mkdir()
+
+ val oldSaveDataFolder = File(
+ "${DirectoryInitialization.userDirectory}/nand" +
+ NativeLibrary.getDefaultProfileSaveDataRoot(false)
+ )
+ if (oldSaveDataFolder.exists()) {
+ oldSaveDataFolder.copyRecursively(cacheSaveDir)
+ }
+
+ val futureSaveDataFolder = File(
+ "${DirectoryInitialization.userDirectory}/nand" +
+ NativeLibrary.getDefaultProfileSaveDataRoot(true)
+ )
+ if (futureSaveDataFolder.exists()) {
+ futureSaveDataFolder.copyRecursively(cacheSaveDir)
+ }
+
+ val saveFilesTotal = cacheSaveDir.listFiles()?.size ?: 0
+ if (saveFilesTotal == 0) {
+ cacheSaveDir.deleteRecursively()
+ return@newInstance getString(R.string.no_save_data_found)
+ }
+
+ val zipResult = FileUtil.zipFromInternalStorage(
+ cacheSaveDir,
+ cacheSaveDir.path,
+ BufferedOutputStream(requireContext().contentResolver.openOutputStream(result))
+ )
+ cacheSaveDir.deleteRecursively()
+
+ return@newInstance when (zipResult) {
+ TaskState.Completed -> getString(R.string.export_success)
+ TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
+ }
+ }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG)
+ }
}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 056920a4a..136c8dee6 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -862,6 +862,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env,
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId);
+ if (program_id == 0) {
+ return ToJString(env, "");
+ }
auto& system = EmulationSession::GetInstance().System();
@@ -880,6 +883,19 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
return ToJString(env, user_save_data_path);
}
+jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env,
+ jobject jobj,
+ jboolean jfuture) {
+ Service::Account::ProfileManager manager;
+ // TODO: Pass in a selected user once we get the relevant UI working
+ const auto user_id = manager.GetUser(static_cast<std::size_t>(0));
+ ASSERT(user_id);
+
+ const auto user_save_data_root =
+ FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture);
+ return ToJString(env, user_save_data_root);
+}
+
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj,
jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath));
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 83aa1b781..3bb92ad67 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -133,6 +133,15 @@
<string name="add_game_folder">Add game folder</string>
<string name="folder_already_added">This folder was already added!</string>
<string name="game_folder_properties">Game folder properties</string>
+ <plurals name="saves_import_failed">
+ <item quantity="one">Failed to import %d save</item>
+ <item quantity="other">Failed to import %d saves</item>
+ </plurals>
+ <plurals name="saves_import_success">
+ <item quantity="one">Successfully imported %d save</item>
+ <item quantity="other">Successfully imported %d saves</item>
+ </plurals>
+ <string name="no_save_data_found">No save data found</string>
<!-- Applet launcher strings -->
<string name="applets">Applet launcher</string>
@@ -276,6 +285,7 @@
<string name="global">Global</string>
<string name="custom">Custom</string>
<string name="notice">Notice</string>
+ <string name="import_complete">Import complete</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</string>
diff --git a/src/android/app/src/main/res/xml/game_mode_config.xml b/src/android/app/src/main/res/xml/game_mode_config.xml
new file mode 100644
index 000000000..b28dd3a11
--- /dev/null
+++ b/src/android/app/src/main/res/xml/game_mode_config.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<game-mode-config
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:supportsBatteryGameMode="true"
+ android:supportsPerformanceGameMode="true"
+ android:allowGameDownscaling="false"
+ android:allowGameFpsOverride="false"/>
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 8d5d593e8..12b3bd797 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -189,6 +189,15 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
}
}
+std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) {
+ if (future) {
+ Common::UUID uuid;
+ std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID));
+ return fmt::format("/user/save/account/{}", uuid.RawString());
+ }
+ return fmt::format("/user/save/{:016X}/{:016X}{:016X}", 0, user_id[1], user_id[0]);
+}
+
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path =
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index e3a0f8cef..fd4887e99 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -101,6 +101,7 @@ public:
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space,
SaveDataType type, u64 title_id, u128 user_id, u64 save_id);
+ static std::string GetUserGameSaveDataRoot(u128 user_id, bool future);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 027c56025..2a65615e8 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -81,7 +81,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{522, nullptr, "SetJoyConRailEnabled"},
{523, nullptr, "IsJoyConRailEnabled"},
{524, nullptr, "IsHandheldHidsEnabled"},
- {525, nullptr, "IsJoyConAttachedOnAllRail"},
+ {525, &IHidSystemServer::IsJoyConAttachedOnAllRail, "IsJoyConAttachedOnAllRail"},
{540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
{541, nullptr, "GetPlayReportControllerUsages"},
{542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
@@ -131,7 +131,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1001, nullptr, "GetFirmwareVersion"},
{1002, nullptr, "GetAvailableFirmwareVersion"},
{1003, nullptr, "IsFirmwareUpdateAvailable"},
- {1004, nullptr, "CheckFirmwareUpdateRequired"},
+ {1004, &IHidSystemServer::CheckFirmwareUpdateRequired, "CheckFirmwareUpdateRequired"},
{1005, nullptr, "StartFirmwareUpdate"},
{1006, nullptr, "AbortFirmwareUpdate"},
{1007, nullptr, "GetFirmwareUpdateState"},
@@ -144,9 +144,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
{1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
{1100, nullptr, "GetHidbusSystemServiceObject"},
- {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
- {1130, nullptr, "InitializeUsbFirmwareUpdate"},
- {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
+ {1120, &IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled, "SetFirmwareHotfixUpdateSkipEnabled"},
+ {1130, &IHidSystemServer::InitializeUsbFirmwareUpdate, "InitializeUsbFirmwareUpdate"},
+ {1131, &IHidSystemServer::FinalizeUsbFirmwareUpdate, "FinalizeUsbFirmwareUpdate"},
{1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
{1133, nullptr, "StartUsbFirmwareUpdate"},
{1134, nullptr, "GetUsbFirmwareUpdateState"},
@@ -196,7 +196,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1268, nullptr, "DeleteButtonConfigStorageFull"},
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
{1270, nullptr, "DeleteButtonConfigStorageRight"},
- {1271, nullptr, "IsUsingCustomButtonConfig"},
+ {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"},
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
{1274, nullptr, "SetDefaultButtonConfig"},
@@ -555,6 +555,16 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
+void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) {
+ const bool is_attached = true;
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, is_attached={}", is_attached);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_attached);
+}
+
void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "(STUBBED) called");
@@ -641,6 +651,34 @@ void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
+void IHidSystemServer::CheckFirmwareUpdateRequired(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::InitializeUsbFirmwareUpdate(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::FinalizeUsbFirmwareUpdate(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
@@ -665,6 +703,16 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx
rb.PushRaw(touchscreen_config);
}
+void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
+ const bool is_enabled = false;
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+}
+
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
resource_manager->Initialize();
return resource_manager;
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 1e623dfc2..f467e2aa8 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -44,6 +44,7 @@ private:
void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
void EnableAppletToGetPadInput(HLERequestContext& ctx);
void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
+ void IsJoyConAttachedOnAllRail(HLERequestContext& ctx);
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
void GetRegisteredDevices(HLERequestContext& ctx);
@@ -53,8 +54,13 @@ private:
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx);
void InitializeFirmwareUpdate(HLERequestContext& ctx);
+ void CheckFirmwareUpdateRequired(HLERequestContext& ctx);
+ void SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx);
+ void InitializeUsbFirmwareUpdate(HLERequestContext& ctx);
+ void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);
void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
+ void IsUsingCustomButtonConfig(HLERequestContext& ctx);
std::shared_ptr<ResourceManager> GetResourceManager();
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp
index 17dacef6e..2c5fe6d51 100644
--- a/src/hid_core/resource_manager.cpp
+++ b/src/hid_core/resource_manager.cpp
@@ -224,6 +224,7 @@ Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value)
void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) {
std::scoped_lock lock{shared_mutex};
applet_resource->UnregisterAppletResourceUserId(aruid);
+ npad->UnregisterAppletResourceUserId(aruid);
}
Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
diff --git a/src/hid_core/resources/applet_resource.cpp b/src/hid_core/resources/applet_resource.cpp
index d16cff1a4..d09a525c6 100644
--- a/src/hid_core/resources/applet_resource.cpp
+++ b/src/hid_core/resources/applet_resource.cpp
@@ -87,7 +87,9 @@ Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input
data_index = i;
break;
}
- if (registration_list.flag[i] == RegistrationStatus::None) {
+ // TODO: Don't Handle pending delete here
+ if (registration_list.flag[i] == RegistrationStatus::None ||
+ registration_list.flag[i] == RegistrationStatus::PendingDelete) {
data_index = i;
break;
}
@@ -104,30 +106,22 @@ Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input
}
void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
- u64 index = GetIndexFromAruid(aruid);
+ const u64 index = GetIndexFromAruid(aruid);
- if (index < AruidIndexMax) {
- if (data[index].flag.is_assigned) {
- data[index].shared_memory_format = nullptr;
- data[index].flag.is_assigned.Assign(false);
- }
+ if (index >= AruidIndexMax) {
+ return;
}
- index = GetIndexFromAruid(aruid);
- if (index < AruidIndexMax) {
- DestroySevenSixAxisTransferMemory();
- data[index].flag.raw = 0;
- data[index].aruid = 0;
+ FreeAppletResourceId(aruid);
+ DestroySevenSixAxisTransferMemory();
+ data[index].flag.raw = 0;
+ data[index].aruid = 0;
- index = GetIndexFromAruid(aruid);
- if (index < AruidIndexMax) {
- registration_list.flag[index] = RegistrationStatus::PendingDelete;
- }
- }
+ registration_list.flag[index] = RegistrationStatus::PendingDelete;
}
void AppletResource::FreeAppletResourceId(u64 aruid) {
- u64 index = GetIndexFromAruid(aruid);
+ const u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return;
}
@@ -144,7 +138,7 @@ u64 AppletResource::GetActiveAruid() {
}
Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
- u64 index = GetIndexFromAruid(aruid);
+ const u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return ResultAruidNotRegistered;
}
@@ -155,7 +149,7 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle,
Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
u64 aruid) {
- u64 index = GetIndexFromAruid(aruid);
+ const u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return ResultAruidNotRegistered;
}
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index e6c035628..97f31d26e 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -870,6 +870,11 @@ void NPad::InitializeVibrationDevice(
const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
+
+ if (aruid == 0) {
+ return;
+ }
+
InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index);
}
diff --git a/src/hid_core/resources/npad/npad_resource.cpp b/src/hid_core/resources/npad/npad_resource.cpp
index b0255a05c..ea9fc14ed 100644
--- a/src/hid_core/resources/npad/npad_resource.cpp
+++ b/src/hid_core/resources/npad/npad_resource.cpp
@@ -46,7 +46,9 @@ Result NPadResource::RegisterAppletResourceUserId(u64 aruid) {
data_index = i;
break;
}
- if (registration_list.flag[i] == RegistrationStatus::None) {
+ // TODO: Don't Handle pending delete here
+ if (registration_list.flag[i] == RegistrationStatus::None ||
+ registration_list.flag[i] == RegistrationStatus::PendingDelete) {
data_index = i;
break;
}