summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt22
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt23
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt16
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt45
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt13
-rw-r--r--src/android/app/src/main/jni/native.cpp17
-rw-r--r--src/android/app/src/main/jni/native_input.cpp76
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
-rw-r--r--src/audio_core/audio_in_manager.cpp7
-rw-r--r--src/audio_core/audio_in_manager.h4
-rw-r--r--src/audio_core/device/audio_buffers.h6
-rw-r--r--src/audio_core/opus/decoder.cpp6
-rw-r--r--src/audio_core/opus/decoder.h6
-rw-r--r--src/audio_core/opus/decoder_manager.cpp18
-rw-r--r--src/audio_core/opus/decoder_manager.h16
-rw-r--r--src/audio_core/opus/hardware_opus.cpp13
-rw-r--r--src/audio_core/opus/hardware_opus.h6
-rw-r--r--src/audio_core/opus/parameters.h4
-rw-r--r--src/audio_core/renderer/audio_device.cpp14
-rw-r--r--src/audio_core/renderer/audio_device.h6
-rw-r--r--src/audio_core/renderer/audio_renderer.cpp7
-rw-r--r--src/audio_core/renderer/audio_renderer.h4
-rw-r--r--src/audio_core/renderer/behavior/info_updater.cpp2
-rw-r--r--src/audio_core/renderer/behavior/info_updater.h10
-rw-r--r--src/audio_core/renderer/memory/pool_mapper.cpp18
-rw-r--r--src/audio_core/renderer/memory/pool_mapper.h14
-rw-r--r--src/audio_core/renderer/system.cpp10
-rw-r--r--src/audio_core/renderer/system.h8
-rw-r--r--src/audio_core/sink/cubeb_sink.cpp4
-rw-r--r--src/audio_core/sink/oboe_sink.cpp8
-rw-r--r--src/audio_core/sink/sink_stream.cpp4
-rw-r--r--src/common/demangle.cpp4
-rw-r--r--src/common/host_memory.cpp4
-rw-r--r--src/common/page_table.cpp4
-rw-r--r--src/common/ring_buffer.h1
-rw-r--r--src/common/scope_exit.h66
-rw-r--r--src/common/settings.h6
-rw-r--r--src/common/settings_enums.h2
-rw-r--r--src/common/string_util.cpp4
-rw-r--r--src/common/string_util.h1
-rw-r--r--src/core/CMakeLists.txt214
-rw-r--r--src/core/cpu_manager.cpp4
-rw-r--r--src/core/device_memory_manager.inc16
-rw-r--r--src/core/file_sys/fs_directory.h4
-rw-r--r--src/core/file_sys/fs_filesystem.h27
-rw-r--r--src/core/file_sys/fs_memory_management.h8
-rw-r--r--src/core/file_sys/fs_path.h2
-rw-r--r--src/core/file_sys/fs_path_utility.h19
-rw-r--r--src/core/file_sys/fs_save_data_types.h188
-rw-r--r--src/core/file_sys/fs_string_util.h15
-rw-r--r--src/core/file_sys/fsa/fs_i_directory.h91
-rw-r--r--src/core/file_sys/fsa/fs_i_file.h167
-rw-r--r--src/core/file_sys/fsa/fs_i_filesystem.h206
-rw-r--r--src/core/file_sys/fssrv/fssrv_sf_path.h36
-rw-r--r--src/core/file_sys/fssystem/fssystem_aes_xts_storage.h1
-rw-r--r--src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp4
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/savedata_factory.cpp90
-rw-r--r--src/core/file_sys/savedata_factory.h68
-rw-r--r--src/core/hle/kernel/k_client_session.cpp8
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp40
-rw-r--r--src/core/hle/kernel/k_process.cpp16
-rw-r--r--src/core/hle/kernel/k_server_session.cpp36
-rw-r--r--src/core/hle/kernel/k_thread_local_page.cpp4
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/svc/svc_code_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_device_address_space.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_event.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_resource_limit.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_session.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_synchronization.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp4
-rw-r--r--src/core/hle/service/am/applet_data_broker.cpp4
-rw-r--r--src/core/hle/service/am/process.cpp4
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp393
-rw-r--r--src/core/hle/service/audio/audin_u.h38
-rw-r--r--src/core/hle/service/audio/audio.cpp28
-rw-r--r--src/core/hle/service/audio/audio_controller.cpp33
-rw-r--r--src/core/hle/service/audio/audio_controller.h1
-rw-r--r--src/core/hle/service/audio/audio_device.cpp163
-rw-r--r--src/core/hle/service/audio/audio_device.h58
-rw-r--r--src/core/hle/service/audio/audio_in.cpp146
-rw-r--r--src/core/hle/service/audio/audio_in.h53
-rw-r--r--src/core/hle/service/audio/audio_in_manager.cpp125
-rw-r--r--src/core/hle/service/audio/audio_in_manager.h57
-rw-r--r--src/core/hle/service/audio/audio_out.cpp146
-rw-r--r--src/core/hle/service/audio/audio_out.h58
-rw-r--r--src/core/hle/service/audio/audio_out_manager.cpp101
-rw-r--r--src/core/hle/service/audio/audio_out_manager.h44
-rw-r--r--src/core/hle/service/audio/audio_renderer.cpp139
-rw-r--r--src/core/hle/service/audio/audio_renderer.h54
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.cpp104
-rw-r--r--src/core/hle/service/audio/audio_renderer_manager.h37
-rw-r--r--src/core/hle/service/audio/audout_u.cpp323
-rw-r--r--src/core/hle/service/audio/audout_u.h37
-rw-r--r--src/core/hle/service/audio/audren_u.cpp552
-rw-r--r--src/core/hle/service/audio/audren_u.h35
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.cpp (renamed from src/core/hle/service/audio/audrec_u.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager.h (renamed from src/core/hle/service/audio/audrec_a.h)6
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp (renamed from src/core/hle/service/audio/audrec_a.cpp)7
-rw-r--r--src/core/hle/service/audio/final_output_recorder_manager_for_applet.h (renamed from src/core/hle/service/audio/audrec_u.h)7
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.cpp145
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder.h63
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.cpp156
-rw-r--r--src/core/hle/service/audio/hardware_opus_decoder_manager.h53
-rw-r--r--src/core/hle/service/audio/hwopus.cpp502
-rw-r--r--src/core/hle/service/audio/hwopus.h36
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp32
-rw-r--r--src/core/hle/service/btm/btm.cpp272
-rw-r--r--src/core/hle/service/btm/btm.h4
-rw-r--r--src/core/hle/service/btm/btm_debug.cpp33
-rw-r--r--src/core/hle/service/btm/btm_debug.h21
-rw-r--r--src/core/hle/service/btm/btm_system.cpp31
-rw-r--r--src/core/hle/service/btm/btm_system.h25
-rw-r--r--src/core/hle/service/btm/btm_system_core.cpp127
-rw-r--r--src/core/hle/service/btm/btm_system_core.h60
-rw-r--r--src/core/hle/service/btm/btm_user.cpp30
-rw-r--r--src/core/hle/service/btm/btm_user.h25
-rw-r--r--src/core/hle/service/btm/btm_user_core.cpp103
-rw-r--r--src/core/hle/service/btm/btm_user_core.h47
-rw-r--r--src/core/hle/service/cmif_serialization.h2
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp72
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h13
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp124
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h21
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp283
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp33
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp161
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h50
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp47
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h7
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp609
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h78
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_types.h (renamed from src/core/hle/service/filesystem/fsp/fsp_util.h)12
-rw-r--r--src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp13
-rw-r--r--src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h16
-rw-r--r--src/core/hle/service/friend/friend.cpp91
-rw-r--r--src/core/hle/service/glue/time/static.cpp41
-rw-r--r--src/core/hle/service/glue/time/time_zone.cpp36
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp12
-rw-r--r--src/core/hle/service/hid/hid_system_server.h1
-rw-r--r--src/core/hle/service/lbl/lbl.cpp31
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp8
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h5
-rw-r--r--src/core/hle/service/nfc/nfc.cpp4
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp24
-rw-r--r--src/core/hle/service/nfc/nfc_interface.h6
-rw-r--r--src/core/hle/service/npns/npns.cpp42
-rw-r--r--src/core/hle/service/ns/application_manager_interface.cpp6
-rw-r--r--src/core/hle/service/ns/application_manager_interface.h2
-rw-r--r--src/core/hle/service/ns/ns_types.h5
-rw-r--r--src/core/hle/service/ns/query_service.cpp5
-rw-r--r--src/core/hle/service/ns/query_service.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp4
-rw-r--r--src/core/hle/service/nvnflinger/display.h26
-rw-r--r--src/core/hle/service/nvnflinger/hardware_composer.cpp12
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.cpp39
-rw-r--r--src/core/hle/service/nvnflinger/surface_flinger.h6
-rw-r--r--src/core/hle/service/olsc/daemon_controller.cpp40
-rw-r--r--src/core/hle/service/olsc/daemon_controller.h20
-rw-r--r--src/core/hle/service/olsc/native_handle_holder.cpp28
-rw-r--r--src/core/hle/service/olsc/native_handle_holder.h22
-rw-r--r--src/core/hle/service/olsc/olsc.cpp223
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_application.cpp63
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_application.h23
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_system_service.cpp117
-rw-r--r--src/core/hle/service/olsc/olsc_service_for_system_service.h27
-rw-r--r--src/core/hle/service/olsc/remote_storage_controller.cpp54
-rw-r--r--src/core/hle/service/olsc/remote_storage_controller.h19
-rw-r--r--src/core/hle/service/olsc/transfer_task_list_controller.cpp55
-rw-r--r--src/core/hle/service/olsc/transfer_task_list_controller.h20
-rw-r--r--src/core/hle/service/pctl/parental_control_service.cpp434
-rw-r--r--src/core/hle/service/pctl/parental_control_service.h86
-rw-r--r--src/core/hle/service/pctl/parental_control_service_factory.cpp40
-rw-r--r--src/core/hle/service/pctl/parental_control_service_factory.h31
-rw-r--r--src/core/hle/service/pctl/pctl.cpp27
-rw-r--r--src/core/hle/service/pctl/pctl.h9
-rw-r--r--src/core/hle/service/pctl/pctl_module.cpp550
-rw-r--r--src/core/hle/service/pctl/pctl_module.h47
-rw-r--r--src/core/hle/service/pctl/pctl_results.h15
-rw-r--r--src/core/hle/service/pctl/pctl_types.h43
-rw-r--r--src/core/hle/service/psc/ovln/ovln_types.h21
-rw-r--r--src/core/hle/service/psc/ovln/receiver.cpp24
-rw-r--r--src/core/hle/service/psc/ovln/receiver.h16
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.cpp28
-rw-r--r--src/core/hle/service/psc/ovln/receiver_service.h22
-rw-r--r--src/core/hle/service/psc/ovln/sender.cpp32
-rw-r--r--src/core/hle/service/psc/ovln/sender.h21
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.cpp30
-rw-r--r--src/core/hle/service/psc/ovln/sender_service.h23
-rw-r--r--src/core/hle/service/psc/pm_control.cpp28
-rw-r--r--src/core/hle/service/psc/pm_control.h16
-rw-r--r--src/core/hle/service/psc/pm_module.cpp24
-rw-r--r--src/core/hle/service/psc/pm_module.h16
-rw-r--r--src/core/hle/service/psc/pm_service.cpp28
-rw-r--r--src/core/hle/service/psc/pm_service.h22
-rw-r--r--src/core/hle/service/psc/psc.cpp71
-rw-r--r--src/core/hle/service/psc/psc.h4
-rw-r--r--src/core/hle/service/psc/time/static.cpp33
-rw-r--r--src/core/hle/service/psc/time/steady_clock.cpp25
-rw-r--r--src/core/hle/service/psc/time/system_clock.cpp8
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.cpp32
-rw-r--r--src/core/hle/service/server_manager.cpp8
-rw-r--r--src/core/hle/service/services.cpp2
-rw-r--r--src/core/hle/service/set/settings_types.h3
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp14
-rw-r--r--src/core/hle/service/vi/conductor.h3
-rw-r--r--src/core/hle/service/vi/container.cpp52
-rw-r--r--src/core/hle/service/vi/container.h3
-rw-r--r--src/core/hle/service/vi/layer.h16
-rw-r--r--src/core/hle/service/vi/layer_list.h6
-rw-r--r--src/core/hle/service/vi/shared_buffer_manager.cpp10
-rw-r--r--src/core/loader/nca.cpp4
-rw-r--r--src/core/memory.cpp8
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp4
-rw-r--r--src/hid_core/frontend/emulated_controller.cpp50
-rw-r--r--src/input_common/drivers/android.cpp41
-rw-r--r--src/input_common/drivers/android.h10
-rw-r--r--src/input_common/drivers/sdl_driver.h5
-rw-r--r--src/input_common/helpers/joycon_driver.cpp4
-rw-r--r--src/input_common/input_engine.h5
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv.cpp4
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_special.cpp8
-rw-r--r--src/shader_recompiler/profile.h1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/fence_manager.h4
-rw-r--r--src/video_core/gpu_thread.cpp4
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp4
-rw-r--r--src/video_core/macro/macro_hle.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_vulkan/present/layer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp8
-rw-r--r--src/video_core/surface.cpp14
-rw-r--r--src/video_core/surface.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h6
-rw-r--r--src/video_core/vulkan_common/nsight_aftermath_tracker.cpp4
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp14
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h5
-rw-r--r--src/yuzu/configuration/shared_translation.cpp10
-rw-r--r--src/yuzu/main.cpp231
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui8
-rw-r--r--src/yuzu_cmd/yuzu.cpp4
264 files changed, 6738 insertions, 4844 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index edca221b1..cf05a3fe3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -121,6 +121,7 @@ else()
121 -Wno-attributes 121 -Wno-attributes
122 -Wno-invalid-offsetof 122 -Wno-invalid-offsetof
123 -Wno-unused-parameter 123 -Wno-unused-parameter
124 -Wno-missing-field-initializers
124 ) 125 )
125 126
126 if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang 127 if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
index d35de80c4..a84ac77a2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/input/model/PlayerInput.kt
@@ -64,17 +64,17 @@ data class PlayerInput(
64 fun hasMapping(): Boolean { 64 fun hasMapping(): Boolean {
65 var hasMapping = false 65 var hasMapping = false
66 buttons.forEach { 66 buttons.forEach {
67 if (it != "[empty]") { 67 if (it != "[empty]" && it.isNotEmpty()) {
68 hasMapping = true 68 hasMapping = true
69 } 69 }
70 } 70 }
71 analogs.forEach { 71 analogs.forEach {
72 if (it != "[empty]") { 72 if (it != "[empty]" && it.isNotEmpty()) {
73 hasMapping = true 73 hasMapping = true
74 } 74 }
75 } 75 }
76 motions.forEach { 76 motions.forEach {
77 if (it != "[empty]") { 77 if (it != "[empty]" && it.isNotEmpty()) {
78 hasMapping = true 78 hasMapping = true
79 } 79 }
80 } 80 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
index a0d8cfede..6f16cf5b1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt
@@ -6,7 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.model
6import org.yuzu.yuzu_emu.utils.NativeConfig 6import org.yuzu.yuzu_emu.utils.NativeConfig
7 7
8enum class StringSetting(override val key: String) : AbstractStringSetting { 8enum class StringSetting(override val key: String) : AbstractStringSetting {
9 DRIVER_PATH("driver_path"); 9 DRIVER_PATH("driver_path"),
10 DEVICE_NAME("device_name");
10 11
11 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) 12 override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
12 13
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index 8f724835e..5fdf98318 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
16import org.yuzu.yuzu_emu.features.settings.model.IntSetting 16import org.yuzu.yuzu_emu.features.settings.model.IntSetting
17import org.yuzu.yuzu_emu.features.settings.model.LongSetting 17import org.yuzu.yuzu_emu.features.settings.model.LongSetting
18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 18import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
19import org.yuzu.yuzu_emu.features.settings.model.StringSetting
19import org.yuzu.yuzu_emu.utils.NativeConfig 20import org.yuzu.yuzu_emu.utils.NativeConfig
20 21
21/** 22/**
@@ -75,6 +76,9 @@ abstract class SettingsItem(
75 get() = NativeLibrary.isRunning() && !setting.global && 76 get() = NativeLibrary.isRunning() && !setting.global &&
76 !NativeConfig.isPerGameConfigLoaded() 77 !NativeConfig.isPerGameConfigLoaded()
77 78
79 val clearable: Boolean
80 get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
81
78 companion object { 82 companion object {
79 const val TYPE_HEADER = 0 83 const val TYPE_HEADER = 0
80 const val TYPE_SWITCH = 1 84 const val TYPE_SWITCH = 1
@@ -87,6 +91,7 @@ abstract class SettingsItem(
87 const val TYPE_INPUT = 8 91 const val TYPE_INPUT = 8
88 const val TYPE_INT_SINGLE_CHOICE = 9 92 const val TYPE_INT_SINGLE_CHOICE = 9
89 const val TYPE_INPUT_PROFILE = 10 93 const val TYPE_INPUT_PROFILE = 10
94 const val TYPE_STRING_INPUT = 11
90 95
91 const val FASTMEM_COMBINED = "fastmem_combined" 96 const val FASTMEM_COMBINED = "fastmem_combined"
92 97
@@ -105,6 +110,7 @@ abstract class SettingsItem(
105 110
106 // List of all general 111 // List of all general
107 val settingsItems = HashMap<String, SettingsItem>().apply { 112 val settingsItems = HashMap<String, SettingsItem>().apply {
113 put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
108 put( 114 put(
109 SwitchSetting( 115 SwitchSetting(
110 BooleanSetting.RENDERER_USE_SPEED_LIMIT, 116 BooleanSetting.RENDERER_USE_SPEED_LIMIT,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
new file mode 100644
index 000000000..1eb999416
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringInputSetting.kt
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.model.view
5
6import androidx.annotation.StringRes
7import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
8
9class StringInputSetting(
10 setting: AbstractStringSetting,
11 @StringRes titleId: Int = 0,
12 titleString: String = "",
13 @StringRes descriptionId: Int = 0,
14 descriptionString: String = ""
15) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
16 override val type = TYPE_STRING_INPUT
17
18 fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
19
20 fun setSelectedValue(selection: String) =
21 (setting as AbstractStringSetting).setString(selection)
22}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index 45c8faa10..500ac6e66 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -85,6 +85,10 @@ class SettingsAdapter(
85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) 85 InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
86 } 86 }
87 87
88 SettingsItem.TYPE_STRING_INPUT -> {
89 StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
90 }
91
88 else -> { 92 else -> {
89 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) 93 HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
90 } 94 }
@@ -392,6 +396,15 @@ class SettingsAdapter(
392 popup.show() 396 popup.show()
393 } 397 }
394 398
399 fun onStringInputClick(item: StringInputSetting, position: Int) {
400 SettingsDialogFragment.newInstance(
401 settingsViewModel,
402 item,
403 SettingsItem.TYPE_STRING_INPUT,
404 position
405 ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
406 }
407
395 fun onLongClick(item: SettingsItem, position: Int): Boolean { 408 fun onLongClick(item: SettingsItem, position: Int): Boolean {
396 SettingsDialogFragment.newInstance( 409 SettingsDialogFragment.newInstance(
397 settingsViewModel, 410 settingsViewModel,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
index a81ff6b1a..7f562a1f4 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt
@@ -14,6 +14,7 @@ import androidx.fragment.app.activityViewModels
14import com.google.android.material.dialog.MaterialAlertDialogBuilder 14import com.google.android.material.dialog.MaterialAlertDialogBuilder
15import com.google.android.material.slider.Slider 15import com.google.android.material.slider.Slider
16import org.yuzu.yuzu_emu.R 16import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
17import org.yuzu.yuzu_emu.databinding.DialogSliderBinding 18import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
18import org.yuzu.yuzu_emu.features.input.NativeInput 19import org.yuzu.yuzu_emu.features.input.NativeInput
19import org.yuzu.yuzu_emu.features.input.model.AnalogDirection 20import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
23import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 24import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
24import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting 25import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
25import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting 26import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
27import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting 28import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
27import org.yuzu.yuzu_emu.utils.ParamPackage 29import org.yuzu.yuzu_emu.utils.ParamPackage
28import org.yuzu.yuzu_emu.utils.collect 30import org.yuzu.yuzu_emu.utils.collect
@@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
37 private val settingsViewModel: SettingsViewModel by activityViewModels() 39 private val settingsViewModel: SettingsViewModel by activityViewModels()
38 40
39 private lateinit var sliderBinding: DialogSliderBinding 41 private lateinit var sliderBinding: DialogSliderBinding
42 private lateinit var stringInputBinding: DialogEditTextBinding
40 43
41 override fun onCreate(savedInstanceState: Bundle?) { 44 override fun onCreate(savedInstanceState: Bundle?) {
42 super.onCreate(savedInstanceState) 45 super.onCreate(savedInstanceState)
@@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
131 .create() 134 .create()
132 } 135 }
133 136
137 SettingsItem.TYPE_STRING_INPUT -> {
138 stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
139 val item = settingsViewModel.clickedItem as StringInputSetting
140 stringInputBinding.editText.setText(item.getSelectedValue())
141 MaterialAlertDialogBuilder(requireContext())
142 .setTitle(item.title)
143 .setView(stringInputBinding.root)
144 .setPositiveButton(android.R.string.ok, this)
145 .setNegativeButton(android.R.string.cancel, defaultCancelListener)
146 .create()
147 }
148
134 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { 149 SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
135 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting 150 val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
136 MaterialAlertDialogBuilder(requireContext()) 151 MaterialAlertDialogBuilder(requireContext())
@@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
158 ): View? { 173 ): View? {
159 return when (type) { 174 return when (type) {
160 SettingsItem.TYPE_SLIDER -> sliderBinding.root 175 SettingsItem.TYPE_SLIDER -> sliderBinding.root
176 SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
161 else -> super.onCreateView(inflater, container, savedInstanceState) 177 else -> super.onCreateView(inflater, container, savedInstanceState)
162 } 178 }
163 } 179 }
@@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
200 val sliderSetting = settingsViewModel.clickedItem as SliderSetting 216 val sliderSetting = settingsViewModel.clickedItem as SliderSetting
201 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) 217 sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
202 } 218 }
219
220 is StringInputSetting -> {
221 val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
222 stringInputSetting.setSelectedValue(
223 (stringInputBinding.editText.text ?: "").toString()
224 )
225 }
203 } 226 }
204 closeDialog() 227 closeDialog()
205 } 228 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index e491c29a2..3ea5f5008 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
23import org.yuzu.yuzu_emu.features.settings.model.Settings 23import org.yuzu.yuzu_emu.features.settings.model.Settings
24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag 24import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting 25import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
26import org.yuzu.yuzu_emu.features.settings.model.StringSetting
26import org.yuzu.yuzu_emu.features.settings.model.view.* 27import org.yuzu.yuzu_emu.features.settings.model.view.*
27import org.yuzu.yuzu_emu.utils.InputHandler 28import org.yuzu.yuzu_emu.utils.InputHandler
28import org.yuzu.yuzu_emu.utils.NativeConfig 29import org.yuzu.yuzu_emu.utils.NativeConfig
@@ -153,6 +154,7 @@ class SettingsFragmentPresenter(
153 154
154 private fun addSystemSettings(sl: ArrayList<SettingsItem>) { 155 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
155 sl.apply { 156 sl.apply {
157 add(StringSetting.DEVICE_NAME.key)
156 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) 158 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
157 add(ShortSetting.RENDERER_SPEED_LIMIT.key) 159 add(ShortSetting.RENDERER_SPEED_LIMIT.key)
158 add(BooleanSetting.USE_DOCKED_MODE.key) 160 add(BooleanSetting.USE_DOCKED_MODE.key)
@@ -778,7 +780,7 @@ class SettingsFragmentPresenter(
778 playerIndex: Int, 780 playerIndex: Int,
779 paramName: String, 781 paramName: String,
780 stick: NativeAnalog, 782 stick: NativeAnalog,
781 defaultValue: Int 783 defaultValue: Float
782 ): AbstractIntSetting = 784 ): AbstractIntSetting =
783 object : AbstractIntSetting { 785 object : AbstractIntSetting {
784 val params get() = NativeInput.getStickParam(playerIndex, stick) 786 val params get() = NativeInput.getStickParam(playerIndex, stick)
@@ -786,7 +788,7 @@ class SettingsFragmentPresenter(
786 override val key = "" 788 override val key = ""
787 789
788 override fun getInt(needsGlobal: Boolean): Int = 790 override fun getInt(needsGlobal: Boolean): Int =
789 (params.get(paramName, 0.15f) * 100).toInt() 791 (params.get(paramName, defaultValue) * 100).toInt()
790 792
791 override fun setInt(value: Int) { 793 override fun setInt(value: Int) {
792 val tempParams = params 794 val tempParams = params
@@ -794,12 +796,12 @@ class SettingsFragmentPresenter(
794 NativeInput.setStickParam(playerIndex, stick, tempParams) 796 NativeInput.setStickParam(playerIndex, stick, tempParams)
795 } 797 }
796 798
797 override val defaultValue = defaultValue 799 override val defaultValue = (defaultValue * 100).toInt()
798 800
799 override fun getValueAsString(needsGlobal: Boolean): String = 801 override fun getValueAsString(needsGlobal: Boolean): String =
800 getInt(needsGlobal).toString() 802 getInt(needsGlobal).toString()
801 803
802 override fun reset() = setInt(defaultValue) 804 override fun reset() = setInt(this.defaultValue)
803 } 805 }
804 806
805 private fun getExtraStickSettings( 807 private fun getExtraStickSettings(
@@ -809,11 +811,11 @@ class SettingsFragmentPresenter(
809 val stickIsController = 811 val stickIsController =
810 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) 812 NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
811 val modifierRangeSetting = 813 val modifierRangeSetting =
812 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) 814 getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
813 val stickRangeSetting = 815 val stickRangeSetting =
814 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) 816 getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
815 val stickDeadzoneSetting = 817 val stickDeadzoneSetting =
816 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) 818 getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
817 819
818 val out = mutableListOf<SettingsItem>().apply { 820 val out = mutableListOf<SettingsItem>().apply {
819 if (stickIsController) { 821 if (stickIsController) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
index 367db7fd2..0309fad59 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
@@ -13,7 +13,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
13import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting 13import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
14import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 14import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
15import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 15import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
16import org.yuzu.yuzu_emu.utils.NativeConfig
17import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 16import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
18 17
19class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 18class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -32,9 +31,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
32 val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) 31 val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
33 binding.textSettingValue.text = dateFormatter.format(zonedTime) 32 binding.textSettingValue.text = dateFormatter.format(zonedTime)
34 33
35 binding.buttonClear.setVisible( 34 binding.buttonClear.setVisible(setting.clearable)
36 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
37 )
38 binding.buttonClear.setOnClickListener { 35 binding.buttonClear.setOnClickListener {
39 adapter.onClearClick(setting, bindingAdapterPosition) 36 adapter.onClearClick(setting, bindingAdapterPosition)
40 } 37 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
index e2fe0b072..489f55455 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.kt
@@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
11import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting 11import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
12import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 12import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
13import org.yuzu.yuzu_emu.utils.NativeConfig
14import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
15 14
16class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 15class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -48,9 +47,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
48 binding.textSettingValue.setVisible(false) 47 binding.textSettingValue.setVisible(false)
49 } 48 }
50 49
51 binding.buttonClear.setVisible( 50 binding.buttonClear.setVisible(setting.clearable)
52 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
53 )
54 binding.buttonClear.setOnClickListener { 51 binding.buttonClear.setOnClickListener {
55 adapter.onClearClick(setting, bindingAdapterPosition) 52 adapter.onClearClick(setting, bindingAdapterPosition)
56 } 53 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
index a37b59b44..90a7138cb 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SliderViewHolder.kt
@@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
12import org.yuzu.yuzu_emu.utils.NativeConfig
13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 12import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
14 13
15class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 14class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -28,9 +27,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
28 setting.units 27 setting.units
29 ) 28 )
30 29
31 binding.buttonClear.setVisible( 30 binding.buttonClear.setVisible(setting.clearable)
32 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
33 )
34 binding.buttonClear.setOnClickListener { 31 binding.buttonClear.setOnClickListener {
35 adapter.onClearClick(setting, bindingAdapterPosition) 32 adapter.onClearClick(setting, bindingAdapterPosition)
36 } 33 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
new file mode 100644
index 000000000..a4fd36f62
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/StringInputViewHolder.kt
@@ -0,0 +1,45 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5
6import android.view.View
7import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
8import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
9import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
10import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
11import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
12
13class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
14 SettingViewHolder(binding.root, adapter) {
15 private lateinit var setting: StringInputSetting
16
17 override fun bind(item: SettingsItem) {
18 setting = item as StringInputSetting
19 binding.textSettingName.text = setting.title
20 binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
21 binding.textSettingDescription.text = setting.description
22 binding.textSettingValue.setVisible(true)
23 binding.textSettingValue.text = setting.getSelectedValue()
24
25 binding.buttonClear.setVisible(setting.clearable)
26 binding.buttonClear.setOnClickListener {
27 adapter.onClearClick(setting, bindingAdapterPosition)
28 }
29
30 setStyle(setting.isEditable, binding)
31 }
32
33 override fun onClick(clicked: View) {
34 if (setting.isEditable) {
35 adapter.onStringInputClick(setting, bindingAdapterPosition)
36 }
37 }
38
39 override fun onLongClick(clicked: View): Boolean {
40 if (setting.isEditable) {
41 return adapter.onLongClick(setting, bindingAdapterPosition)
42 }
43 return false
44 }
45}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
index 53f7b301f..e5763264a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
@@ -9,7 +9,6 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
12import org.yuzu.yuzu_emu.utils.NativeConfig
13import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible 12import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
14 13
15class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : 14class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
@@ -29,9 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
29 adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) 28 adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
30 } 29 }
31 30
32 binding.buttonClear.setVisible( 31 binding.buttonClear.setVisible(setting.clearable)
33 !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
34 )
35 binding.buttonClear.setOnClickListener { 32 binding.buttonClear.setOnClickListener {
36 adapter.onClearClick(setting, bindingAdapterPosition) 33 adapter.onClearClick(setting, bindingAdapterPosition)
37 } 34 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index c3b2b11f8..bcc880e17 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -810,7 +810,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
810 } 810 }
811 } 811 }
812 } 812 }
813 binding.doneControlConfig.setVisible(false) 813 binding.doneControlConfig.setVisible(true)
814 binding.surfaceInputOverlay.setIsInEditMode(true) 814 binding.surfaceInputOverlay.setIsInEditMode(true)
815 } 815 }
816 816
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index 66907085a..737e03584 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -28,6 +28,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
28import org.yuzu.yuzu_emu.R 28import org.yuzu.yuzu_emu.R
29import org.yuzu.yuzu_emu.features.input.model.NativeAnalog 29import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
30import org.yuzu.yuzu_emu.features.input.model.NativeButton 30import org.yuzu.yuzu_emu.features.input.model.NativeButton
31import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
31import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting 32import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
32import org.yuzu.yuzu_emu.features.settings.model.IntSetting 33import org.yuzu.yuzu_emu.features.settings.model.IntSetting
33import org.yuzu.yuzu_emu.overlay.model.OverlayControl 34import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
99 } 100 }
100 101
101 var shouldUpdateView = false 102 var shouldUpdateView = false
102 val playerIndex = 103 val playerIndex = when (NativeInput.getStyleIndex(0)) {
103 if (NativeInput.isHandheldOnly()) { 104 NpadStyleIndex.Handheld -> 8
104 NativeInput.ConsoleDevice 105 else -> 0
105 } else { 106 }
106 NativeInput.Player1Device
107 }
108 107
109 for (button in overlayButtons) { 108 for (button in overlayButtons) {
110 if (!button.updateStatus(event)) { 109 if (!button.updateStatus(event)) {
@@ -664,7 +663,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
664 663
665 val overlayControlData = NativeConfig.getOverlayControlData() 664 val overlayControlData = NativeConfig.getOverlayControlData()
666 overlayControlData.forEach { 665 overlayControlData.forEach {
667 it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false 666 it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
668 } 667 }
669 NativeConfig.setOverlayControlData(overlayControlData) 668 NativeConfig.setOverlayControlData(overlayControlData)
670 669
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 50cef5d2a..5d484a85e 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
292 // Unload user input. 292 // Unload user input.
293 m_system.HIDCore().UnloadInputDevices(); 293 m_system.HIDCore().UnloadInputDevices();
294 294
295 // Enable all controllers
296 m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
297
295 // Shutdown the main emulated process 298 // Shutdown the main emulated process
296 if (m_load_result == Core::SystemResultStatus::Success) { 299 if (m_load_result == Core::SystemResultStatus::Success) {
297 m_system.DetachDebugger(); 300 m_system.DetachDebugger();
@@ -404,7 +407,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
404 const size_t program_index, 407 const size_t program_index,
405 const bool frontend_initiated) { 408 const bool frontend_initiated) {
406 MicroProfileOnThreadCreate("EmuThread"); 409 MicroProfileOnThreadCreate("EmuThread");
407 SCOPE_EXIT({ MicroProfileShutdown(); }); 410 SCOPE_EXIT {
411 MicroProfileShutdown();
412 };
408 413
409 LOG_INFO(Frontend, "starting"); 414 LOG_INFO(Frontend, "starting");
410 415
@@ -413,7 +418,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
413 return Core::SystemResultStatus::ErrorLoader; 418 return Core::SystemResultStatus::ErrorLoader;
414 } 419 }
415 420
416 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); 421 SCOPE_EXIT {
422 EmulationSession::GetInstance().ShutdownEmulation();
423 };
417 424
418 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, 425 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
419 frontend_initiated); 426 frontend_initiated);
@@ -661,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
661 ASSERT(user_id); 668 ASSERT(user_id);
662 669
663 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 670 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
664 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1, 671 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
665 user_id->AsU128(), 0); 672 user_id->AsU128(), 0);
666 673
667 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 674 const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@@ -829,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
829 FileSys::OpenMode::Read); 836 FileSys::OpenMode::Read);
830 837
831 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 838 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
832 {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 839 {}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
833 program_id, user_id->AsU128(), 0); 840 user_id->AsU128(), 0);
834 return Common::Android::ToJString(env, user_save_data_path); 841 return Common::Android::ToJString(env, user_save_data_path);
835} 842}
836 843
diff --git a/src/android/app/src/main/jni/native_input.cpp b/src/android/app/src/main/jni/native_input.cpp
index 37a65f2b8..4935a4607 100644
--- a/src/android/app/src/main/jni/native_input.cpp
+++ b/src/android/app/src/main/jni/native_input.cpp
@@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
102 } 102 }
103} 103}
104 104
105std::vector<s32> GetSupportedStyles(int player_index) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
107 const auto npad_style_set = hid_core.GetSupportedStyleTag();
108 std::vector<s32> supported_indexes;
109 if (npad_style_set.fullkey == 1) {
110 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
111 }
112
113 if (npad_style_set.joycon_dual == 1) {
114 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
115 }
116
117 if (npad_style_set.joycon_left == 1) {
118 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
119 }
120
121 if (npad_style_set.joycon_right == 1) {
122 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
123 }
124
125 if (player_index == 0 && npad_style_set.handheld == 1) {
126 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
127 }
128
129 if (npad_style_set.gamecube == 1) {
130 supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
131 }
132
133 return supported_indexes;
134}
135
105void ConnectController(size_t player_index, bool connected) { 136void ConnectController(size_t player_index, bool connected) {
106 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 137 auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
138 ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
139 auto supported_styles = GetSupportedStyles(player_index);
140 auto controller_style = controller->GetNpadStyleIndex(true);
141 auto style = std::find(supported_styles.begin(), supported_styles.end(),
142 static_cast<int>(controller_style));
143 if (style == supported_styles.end() && !supported_styles.empty()) {
144 controller->SetNpadStyleIndex(
145 static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
146 }
147 });
148
107 if (player_index == 0) { 149 if (player_index == 0) {
108 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); 150 auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
109 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); 151 auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@@ -522,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
522 564
523jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( 565jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
524 JNIEnv* env, jobject j_obj, jint j_player_index) { 566 JNIEnv* env, jobject j_obj, jint j_player_index) {
525 auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); 567 auto supported_styles = GetSupportedStyles(j_player_index);
526 const auto npad_style_set = hid_core.GetSupportedStyleTag(); 568 jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
527 std::vector<s32> supported_indexes; 569 env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
528 if (npad_style_set.fullkey == 1) { 570 supported_styles.data());
529 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
530 }
531
532 if (npad_style_set.joycon_dual == 1) {
533 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
534 }
535
536 if (npad_style_set.joycon_left == 1) {
537 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
538 }
539
540 if (npad_style_set.joycon_right == 1) {
541 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
542 }
543
544 if (j_player_index == 0 && npad_style_set.handheld == 1) {
545 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
546 }
547
548 if (npad_style_set.gamecube == 1) {
549 supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
550 }
551
552 jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
553 env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
554 supported_indexes.data());
555 return j_supported_indexes; 571 return j_supported_indexes;
556} 572}
557 573
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 6a631f664..f7f19cdad 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -209,6 +209,7 @@
209 <string name="value_with_units">%1$s%2$s</string> 209 <string name="value_with_units">%1$s%2$s</string>
210 210
211 <!-- System settings strings --> 211 <!-- System settings strings -->
212 <string name="device_name">Device name</string>
212 <string name="use_docked_mode">Docked Mode</string> 213 <string name="use_docked_mode">Docked Mode</string>
213 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> 214 <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
214 <string name="emulated_region">Emulated region</string> 215 <string name="emulated_region">Emulated region</string>
diff --git a/src/audio_core/audio_in_manager.cpp b/src/audio_core/audio_in_manager.cpp
index a3667524f..63b064922 100644
--- a/src/audio_core/audio_in_manager.cpp
+++ b/src/audio_core/audio_in_manager.cpp
@@ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() {
73 } 73 }
74} 74}
75 75
76u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, 76u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
77 [[maybe_unused]] const u32 max_count,
78 [[maybe_unused]] const bool filter) { 77 [[maybe_unused]] const bool filter) {
79 std::scoped_lock l{mutex}; 78 std::scoped_lock l{mutex};
80 79
81 LinkToManager(); 80 LinkToManager();
82 81
83 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; 82 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
84 if (input_devices.size() > 1) { 83 if (!input_devices.empty() && !names.empty()) {
85 names.emplace_back("Uac"); 84 names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
86 return 1; 85 return 1;
87 } 86 }
88 return 0; 87 return 0;
diff --git a/src/audio_core/audio_in_manager.h b/src/audio_core/audio_in_manager.h
index 5c4614cd1..2179990e0 100644
--- a/src/audio_core/audio_in_manager.h
+++ b/src/audio_core/audio_in_manager.h
@@ -60,13 +60,11 @@ public:
60 * Get a list of audio in device names. 60 * Get a list of audio in device names.
61 * 61 *
62 * @param names - Output container to write names to. 62 * @param names - Output container to write names to.
63 * @param max_count - Maximum number of device names to write. Unused
64 * @param filter - Should the list be filtered? Unused. 63 * @param filter - Should the list be filtered? Unused.
65 * 64 *
66 * @return Number of names written. 65 * @return Number of names written.
67 */ 66 */
68 u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count, 67 u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
69 bool filter);
70 68
71 /// Core system 69 /// Core system
72 Core::System& system; 70 Core::System& system;
diff --git a/src/audio_core/device/audio_buffers.h b/src/audio_core/device/audio_buffers.h
index 5d8ed0ef7..9e84a9c05 100644
--- a/src/audio_core/device/audio_buffers.h
+++ b/src/audio_core/device/audio_buffers.h
@@ -146,7 +146,11 @@ public:
146 break; 146 break;
147 } 147 }
148 148
149 tags[released++] = tag; 149 if (released < tags.size()) {
150 tags[released] = tag;
151 }
152
153 released++;
150 154
151 if (released >= tags.size()) { 155 if (released >= tags.size()) {
152 break; 156 break;
diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp
index b7fed5304..0c110cbeb 100644
--- a/src/audio_core/opus/decoder.cpp
+++ b/src/audio_core/opus/decoder.cpp
@@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
28 } 28 }
29} 29}
30 30
31Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, 31Result OpusDecoder::Initialize(const OpusParametersEx& params,
32 u64 transfer_memory_size) { 32 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
33 auto frame_size{params.use_large_frame_size ? 5760 : 1920}; 33 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
34 shared_buffer_size = transfer_memory_size; 34 shared_buffer_size = transfer_memory_size;
35 shared_buffer = std::make_unique<u8[]>(shared_buffer_size); 35 shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
59 R_SUCCEED(); 59 R_SUCCEED();
60} 60}
61 61
62Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, 62Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
63 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { 63 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
64 auto frame_size{params.use_large_frame_size ? 5760 : 1920}; 64 auto frame_size{params.use_large_frame_size ? 5760 : 1920};
65 shared_buffer_size = transfer_memory_size; 65 shared_buffer_size = transfer_memory_size;
diff --git a/src/audio_core/opus/decoder.h b/src/audio_core/opus/decoder.h
index fd728958a..1b8c257d4 100644
--- a/src/audio_core/opus/decoder.h
+++ b/src/audio_core/opus/decoder.h
@@ -22,10 +22,10 @@ public:
22 explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); 22 explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
23 ~OpusDecoder(); 23 ~OpusDecoder();
24 24
25 Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, 25 Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
26 u64 transfer_memory_size);
27 Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
28 u64 transfer_memory_size); 26 u64 transfer_memory_size);
27 Result Initialize(const OpusMultiStreamParametersEx& params,
28 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
29 Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, 29 Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
30 std::span<const u8> input_data, std::span<u8> output_data, bool reset); 30 std::span<const u8> input_data, std::span<u8> output_data, bool reset);
31 Result SetContext([[maybe_unused]] std::span<const u8> context); 31 Result SetContext([[maybe_unused]] std::span<const u8> context);
diff --git a/src/audio_core/opus/decoder_manager.cpp b/src/audio_core/opus/decoder_manager.cpp
index 1464880a1..89eec1298 100644
--- a/src/audio_core/opus/decoder_manager.cpp
+++ b/src/audio_core/opus/decoder_manager.cpp
@@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
38 } 38 }
39} 39}
40 40
41Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { 41Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
42 OpusParametersEx ex{ 42 OpusParametersEx ex{
43 .sample_rate = params.sample_rate, 43 .sample_rate = params.sample_rate,
44 .channel_count = params.channel_count, 44 .channel_count = params.channel_count,
@@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
47 R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); 47 R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
48} 48}
49 49
50Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { 50Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
51 R_RETURN(GetWorkBufferSizeExEx(params, out_size)); 51 R_RETURN(GetWorkBufferSizeExEx(params, out_size));
52} 52}
53 53
54Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { 54Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
55 R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); 55 R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
56 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); 56 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
57 57
@@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
63 R_SUCCEED(); 63 R_SUCCEED();
64} 64}
65 65
66Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, 66Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
67 u64& out_size) { 67 u32& out_size) {
68 OpusMultiStreamParametersEx ex{ 68 OpusMultiStreamParametersEx ex{
69 .sample_rate = params.sample_rate, 69 .sample_rate = params.sample_rate,
70 .channel_count = params.channel_count, 70 .channel_count = params.channel_count,
@@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
76 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); 76 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
77} 77}
78 78
79Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, 79Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
80 u64& out_size) { 80 const OpusMultiStreamParametersEx& params, u32& out_size) {
81 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); 81 R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
82} 82}
83 83
84Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, 84Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
85 u64& out_size) { 85 const OpusMultiStreamParametersEx& params, u32& out_size) {
86 R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); 86 R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
87 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); 87 R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
88 R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, 88 R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,
diff --git a/src/audio_core/opus/decoder_manager.h b/src/audio_core/opus/decoder_manager.h
index 70ebc4bab..8f6876d5c 100644
--- a/src/audio_core/opus/decoder_manager.h
+++ b/src/audio_core/opus/decoder_manager.h
@@ -22,17 +22,19 @@ public:
22 return hardware_opus; 22 return hardware_opus;
23 } 23 }
24 24
25 Result GetWorkBufferSize(OpusParameters& params, u64& out_size); 25 Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
26 Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); 26 Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
27 Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); 27 Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
28 Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); 28 Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
29 Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); 29 Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
30 Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); 30 u32& out_size);
31 Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
32 u32& out_size);
31 33
32private: 34private:
33 Core::System& system; 35 Core::System& system;
34 HardwareOpus hardware_opus; 36 HardwareOpus hardware_opus;
35 std::array<u64, MaxChannels> required_workbuffer_sizes{}; 37 std::array<u32, MaxChannels> required_workbuffer_sizes{};
36}; 38};
37 39
38} // namespace AudioCore::OpusDecoder 40} // namespace AudioCore::OpusDecoder
diff --git a/src/audio_core/opus/hardware_opus.cpp b/src/audio_core/opus/hardware_opus.cpp
index 5ff71ab2d..30805f4a3 100644
--- a/src/audio_core/opus/hardware_opus.cpp
+++ b/src/audio_core/opus/hardware_opus.cpp
@@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
42 opus_decoder.SetSharedMemory(shared_memory); 42 opus_decoder.SetSharedMemory(shared_memory);
43} 43}
44 44
45u64 HardwareOpus::GetWorkBufferSize(u32 channel) { 45u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
46 if (!opus_decoder.IsRunning()) { 46 if (!opus_decoder.IsRunning()) {
47 return 0; 47 return 0;
48 } 48 }
@@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
55 ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); 55 ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
56 return 0; 56 return 0;
57 } 57 }
58 return shared_memory.dsp_return_data[0]; 58 return static_cast<u32>(shared_memory.dsp_return_data[0]);
59} 59}
60 60
61u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { 61u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
62 std::scoped_lock l{mutex}; 62 std::scoped_lock l{mutex};
63 shared_memory.host_send_data[0] = total_stream_count; 63 shared_memory.host_send_data[0] = total_stream_count;
64 shared_memory.host_send_data[1] = stereo_stream_count; 64 shared_memory.host_send_data[1] = stereo_stream_count;
@@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
70 ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); 70 ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
71 return 0; 71 return 0;
72 } 72 }
73 return shared_memory.dsp_return_data[0]; 73 return static_cast<u32>(shared_memory.dsp_return_data[0]);
74} 74}
75 75
76Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, 76Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
94 94
95Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, 95Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
96 u32 total_stream_count, 96 u32 total_stream_count,
97 u32 stereo_stream_count, void* mappings, 97 u32 stereo_stream_count,
98 void* buffer, u64 buffer_size) { 98 const void* mappings, void* buffer,
99 u64 buffer_size) {
99 std::scoped_lock l{mutex}; 100 std::scoped_lock l{mutex};
100 shared_memory.host_send_data[0] = (u64)buffer; 101 shared_memory.host_send_data[0] = (u64)buffer;
101 shared_memory.host_send_data[1] = buffer_size; 102 shared_memory.host_send_data[1] = buffer_size;
diff --git a/src/audio_core/opus/hardware_opus.h b/src/audio_core/opus/hardware_opus.h
index b10184baa..caa746840 100644
--- a/src/audio_core/opus/hardware_opus.h
+++ b/src/audio_core/opus/hardware_opus.h
@@ -16,14 +16,14 @@ class HardwareOpus {
16public: 16public:
17 HardwareOpus(Core::System& system); 17 HardwareOpus(Core::System& system);
18 18
19 u64 GetWorkBufferSize(u32 channel); 19 u32 GetWorkBufferSize(u32 channel);
20 u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); 20 u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
21 21
22 Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, 22 Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
23 u64 buffer_size); 23 u64 buffer_size);
24 Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, 24 Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
25 u32 totaL_stream_count, u32 stereo_stream_count, 25 u32 totaL_stream_count, u32 stereo_stream_count,
26 void* mappings, void* buffer, u64 buffer_size); 26 const void* mappings, void* buffer, u64 buffer_size);
27 Result ShutdownDecodeObject(void* buffer, u64 buffer_size); 27 Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
28 Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); 28 Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
29 Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, 29 Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,
diff --git a/src/audio_core/opus/parameters.h b/src/audio_core/opus/parameters.h
index 4c54b2825..47c418b9f 100644
--- a/src/audio_core/opus/parameters.h
+++ b/src/audio_core/opus/parameters.h
@@ -20,7 +20,7 @@ struct OpusParametersEx {
20 /* 0x00 */ u32 sample_rate; 20 /* 0x00 */ u32 sample_rate;
21 /* 0x04 */ u32 channel_count; 21 /* 0x04 */ u32 channel_count;
22 /* 0x08 */ bool use_large_frame_size; 22 /* 0x08 */ bool use_large_frame_size;
23 /* 0x09 */ INSERT_PADDING_BYTES(7); 23 /* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
24}; // size = 0x10 24}; // size = 0x10
25static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!"); 25static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
26 26
@@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
40 /* 0x08 */ u32 total_stream_count; 40 /* 0x08 */ u32 total_stream_count;
41 /* 0x0C */ u32 stereo_stream_count; 41 /* 0x0C */ u32 stereo_stream_count;
42 /* 0x10 */ bool use_large_frame_size; 42 /* 0x10 */ bool use_large_frame_size;
43 /* 0x11 */ INSERT_PADDING_BYTES(7); 43 /* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
44 /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings; 44 /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
45}; // size = 0x118 45}; // size = 0x118
46static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118, 46static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,
diff --git a/src/audio_core/renderer/audio_device.cpp b/src/audio_core/renderer/audio_device.cpp
index 2d9bf82bb..5be5594f6 100644
--- a/src/audio_core/renderer/audio_device.cpp
+++ b/src/audio_core/renderer/audio_device.cpp
@@ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
36 : output_sink{system.AudioCore().GetOutputSink()}, 36 : output_sink{system.AudioCore().GetOutputSink()},
37 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} 37 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
38 38
39u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, 39u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
40 const size_t max_count) const {
41 std::span<const AudioDeviceName> names{}; 40 std::span<const AudioDeviceName> names{};
42 41
43 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { 42 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
46 names = device_names; 45 names = device_names;
47 } 46 }
48 47
49 const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))}; 48 const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
50 for (u32 i = 0; i < out_count; i++) { 49 for (u32 i = 0; i < out_count; i++) {
51 out_buffer.push_back(names[i]); 50 out_buffer[i] = names[i];
52 } 51 }
53 return out_count; 52 return out_count;
54} 53}
55 54
56u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, 55u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
57 const size_t max_count) const { 56 const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
58 const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
59 57
60 for (u32 i = 0; i < out_count; i++) { 58 for (u32 i = 0; i < out_count; i++) {
61 out_buffer.push_back(output_device_names[i]); 59 out_buffer[i] = output_device_names[i];
62 } 60 }
63 return out_count; 61 return out_count;
64} 62}
diff --git a/src/audio_core/renderer/audio_device.h b/src/audio_core/renderer/audio_device.h
index ca4040add..4242dad30 100644
--- a/src/audio_core/renderer/audio_device.h
+++ b/src/audio_core/renderer/audio_device.h
@@ -36,20 +36,18 @@ public:
36 * Get a list of the available output devices. 36 * Get a list of the available output devices.
37 * 37 *
38 * @param out_buffer - Output buffer to write the available device names. 38 * @param out_buffer - Output buffer to write the available device names.
39 * @param max_count - Maximum number of devices to write (count of out_buffer).
40 * @return Number of device names written. 39 * @return Number of device names written.
41 */ 40 */
42 u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; 41 u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
43 42
44 /** 43 /**
45 * Get a list of the available output devices. 44 * Get a list of the available output devices.
46 * Different to above somehow... 45 * Different to above somehow...
47 * 46 *
48 * @param out_buffer - Output buffer to write the available device names. 47 * @param out_buffer - Output buffer to write the available device names.
49 * @param max_count - Maximum number of devices to write (count of out_buffer).
50 * @return Number of device names written. 48 * @return Number of device names written.
51 */ 49 */
52 u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; 50 u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
53 51
54 /** 52 /**
55 * Set the volume of all streams in the backend sink. 53 * Set the volume of all streams in the backend sink.
diff --git a/src/audio_core/renderer/audio_renderer.cpp b/src/audio_core/renderer/audio_renderer.cpp
index df03d03aa..7c728cb86 100644
--- a/src/audio_core/renderer/audio_renderer.cpp
+++ b/src/audio_core/renderer/audio_renderer.cpp
@@ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
17 17
18Result Renderer::Initialize(const AudioRendererParameterInternal& params, 18Result Renderer::Initialize(const AudioRendererParameterInternal& params,
19 Kernel::KTransferMemory* transfer_memory, 19 Kernel::KTransferMemory* transfer_memory,
20 const u64 transfer_memory_size, const u32 process_handle, 20 const u64 transfer_memory_size, Kernel::KProcess* process_handle,
21 Kernel::KProcess& process, const u64 applet_resource_user_id, 21 const u64 applet_resource_user_id, const s32 session_id) {
22 const s32 session_id) {
23 if (params.execution_mode == ExecutionMode::Auto) { 22 if (params.execution_mode == ExecutionMode::Auto) {
24 if (!manager.AddSystem(system)) { 23 if (!manager.AddSystem(system)) {
25 LOG_ERROR(Service_Audio, 24 LOG_ERROR(Service_Audio,
@@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
30 } 29 }
31 30
32 initialized = true; 31 initialized = true;
33 system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, 32 system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
34 applet_resource_user_id, session_id); 33 applet_resource_user_id, session_id);
35 34
36 return ResultSuccess; 35 return ResultSuccess;
diff --git a/src/audio_core/renderer/audio_renderer.h b/src/audio_core/renderer/audio_renderer.h
index 1219f74ca..f16adeda7 100644
--- a/src/audio_core/renderer/audio_renderer.h
+++ b/src/audio_core/renderer/audio_renderer.h
@@ -38,14 +38,14 @@ public:
38 * @param params - Input parameters to initialize the system with. 38 * @param params - Input parameters to initialize the system with.
39 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused. 39 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
40 * @param transfer_memory_size - Size of the transfer memory. Unused. 40 * @param transfer_memory_size - Size of the transfer memory. Unused.
41 * @param process_handle - Process handle, also used for memory. Unused. 41 * @param process_handle - Process handle, also used for memory.
42 * @param applet_resource_user_id - Applet id for this renderer. Unused. 42 * @param applet_resource_user_id - Applet id for this renderer. Unused.
43 * @param session_id - Session id of this renderer. 43 * @param session_id - Session id of this renderer.
44 * @return Result code. 44 * @return Result code.
45 */ 45 */
46 Result Initialize(const AudioRendererParameterInternal& params, 46 Result Initialize(const AudioRendererParameterInternal& params,
47 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 47 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
48 u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, 48 Kernel::KProcess* process_handle, u64 applet_resource_user_id,
49 s32 session_id); 49 s32 session_id);
50 50
51 /** 51 /**
diff --git a/src/audio_core/renderer/behavior/info_updater.cpp b/src/audio_core/renderer/behavior/info_updater.cpp
index 667711e17..3dae6069f 100644
--- a/src/audio_core/renderer/behavior/info_updater.cpp
+++ b/src/audio_core/renderer/behavior/info_updater.cpp
@@ -18,7 +18,7 @@
18namespace AudioCore::Renderer { 18namespace AudioCore::Renderer {
19 19
20InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_, 20InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
21 const u32 process_handle_, BehaviorInfo& behaviour_) 21 Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
22 : input{input_.data() + sizeof(UpdateDataHeader)}, 22 : input{input_.data() + sizeof(UpdateDataHeader)},
23 input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)}, 23 input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
24 output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>( 24 output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(
diff --git a/src/audio_core/renderer/behavior/info_updater.h b/src/audio_core/renderer/behavior/info_updater.h
index fb4b7d25a..4f27a817e 100644
--- a/src/audio_core/renderer/behavior/info_updater.h
+++ b/src/audio_core/renderer/behavior/info_updater.h
@@ -8,6 +8,10 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/service/audio/errors.h" 9#include "core/hle/service/audio/errors.h"
10 10
11namespace Kernel {
12class KProcess;
13}
14
11namespace AudioCore::Renderer { 15namespace AudioCore::Renderer {
12class BehaviorInfo; 16class BehaviorInfo;
13class VoiceContext; 17class VoiceContext;
@@ -39,8 +43,8 @@ class InfoUpdater {
39 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!"); 43 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
40 44
41public: 45public:
42 explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle, 46 explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
43 BehaviorInfo& behaviour); 47 Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
44 48
45 /** 49 /**
46 * Update the voice channel resources. 50 * Update the voice channel resources.
@@ -197,7 +201,7 @@ private:
197 /// Expected output size, see CheckConsumedSize 201 /// Expected output size, see CheckConsumedSize
198 u64 expected_output_size; 202 u64 expected_output_size;
199 /// Unused 203 /// Unused
200 u32 process_handle; 204 Kernel::KProcess* process_handle;
201 /// Behaviour 205 /// Behaviour
202 BehaviorInfo& behaviour; 206 BehaviorInfo& behaviour;
203}; 207};
diff --git a/src/audio_core/renderer/memory/pool_mapper.cpp b/src/audio_core/renderer/memory/pool_mapper.cpp
index 999bb746b..e47eb66d5 100644
--- a/src/audio_core/renderer/memory/pool_mapper.cpp
+++ b/src/audio_core/renderer/memory/pool_mapper.cpp
@@ -8,11 +8,11 @@
8 8
9namespace AudioCore::Renderer { 9namespace AudioCore::Renderer {
10 10
11PoolMapper::PoolMapper(u32 process_handle_, bool force_map_) 11PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
12 : process_handle{process_handle_}, force_map{force_map_} {} 12 : process_handle{process_handle_}, force_map{force_map_} {}
13 13
14PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_, 14PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
15 bool force_map_) 15 u32 pool_count_, bool force_map_)
16 : process_handle{process_handle_}, pool_infos{pool_infos_.data()}, 16 : process_handle{process_handle_}, pool_infos{pool_infos_.data()},
17 pool_count{pool_count_}, force_map{force_map_} {} 17 pool_count{pool_count_}, force_map{force_map_} {}
18 18
@@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
106 return force_map; 106 return force_map;
107} 107}
108 108
109u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { 109Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
110 switch (pool->GetLocation()) { 110 switch (pool->GetLocation()) {
111 case MemoryPoolInfo::Location::CPU: 111 case MemoryPoolInfo::Location::CPU:
112 return process_handle; 112 return process_handle;
113 case MemoryPoolInfo::Location::DSP: 113 case MemoryPoolInfo::Location::DSP:
114 return Kernel::Svc::CurrentProcess; 114 // return Kernel::Svc::CurrentProcess;
115 return nullptr;
115 } 116 }
116 LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); 117 LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
117 return Kernel::Svc::CurrentProcess; 118 // return Kernel::Svc::CurrentProcess;
119 return nullptr;
118} 120}
119 121
120bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, 122bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@@ -147,14 +149,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
147} 149}
148 150
149bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { 151bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
150 [[maybe_unused]] u32 handle{0}; 152 [[maybe_unused]] Kernel::KProcess* handle{};
151 153
152 switch (pool.GetLocation()) { 154 switch (pool.GetLocation()) {
153 case MemoryPoolInfo::Location::CPU: 155 case MemoryPoolInfo::Location::CPU:
154 handle = process_handle; 156 handle = process_handle;
155 break; 157 break;
156 case MemoryPoolInfo::Location::DSP: 158 case MemoryPoolInfo::Location::DSP:
157 handle = Kernel::Svc::CurrentProcess; 159 // handle = Kernel::Svc::CurrentProcess;
158 break; 160 break;
159 } 161 }
160 // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size); 162 // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);
diff --git a/src/audio_core/renderer/memory/pool_mapper.h b/src/audio_core/renderer/memory/pool_mapper.h
index 95ae5d8ea..fb5122b73 100644
--- a/src/audio_core/renderer/memory/pool_mapper.h
+++ b/src/audio_core/renderer/memory/pool_mapper.h
@@ -10,6 +10,10 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/service/audio/errors.h" 11#include "core/hle/service/audio/errors.h"
12 12
13namespace Kernel {
14class KProcess;
15}
16
13namespace AudioCore::Renderer { 17namespace AudioCore::Renderer {
14class AddressInfo; 18class AddressInfo;
15 19
@@ -18,9 +22,9 @@ class AddressInfo;
18 */ 22 */
19class PoolMapper { 23class PoolMapper {
20public: 24public:
21 explicit PoolMapper(u32 process_handle, bool force_map); 25 explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
22 explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count, 26 explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
23 bool force_map); 27 u32 pool_count, bool force_map);
24 28
25 /** 29 /**
26 * Clear the usage state for all given pools. 30 * Clear the usage state for all given pools.
@@ -98,7 +102,7 @@ public:
98 * @return CurrentProcessHandle if location == DSP, 102 * @return CurrentProcessHandle if location == DSP,
99 * the PoolMapper's process_handle if location == CPU 103 * the PoolMapper's process_handle if location == CPU
100 */ 104 */
101 u32 GetProcessHandle(const MemoryPoolInfo* pool) const; 105 Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
102 106
103 /** 107 /**
104 * Map the given region with the given handle. This is a no-op. 108 * Map the given region with the given handle. This is a no-op.
@@ -167,7 +171,7 @@ public:
167 171
168private: 172private:
169 /// Process handle for this mapper, used when location == CPU 173 /// Process handle for this mapper, used when location == CPU
170 u32 process_handle; 174 Kernel::KProcess* process_handle{};
171 /// List of memory pools assigned to this mapper 175 /// List of memory pools assigned to this mapper
172 MemoryPoolInfo* pool_infos{}; 176 MemoryPoolInfo* pool_infos{};
173 /// The number of pools 177 /// The number of pools
diff --git a/src/audio_core/renderer/system.cpp b/src/audio_core/renderer/system.cpp
index ca656edae..c30d68426 100644
--- a/src/audio_core/renderer/system.cpp
+++ b/src/audio_core/renderer/system.cpp
@@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
102 102
103Result System::Initialize(const AudioRendererParameterInternal& params, 103Result System::Initialize(const AudioRendererParameterInternal& params,
104 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 104 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
105 u32 process_handle_, Kernel::KProcess& process_, 105 Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
106 u64 applet_resource_user_id_, s32 session_id_) { 106 s32 session_id_) {
107 if (!CheckValidRevision(params.revision)) { 107 if (!CheckValidRevision(params.revision)) {
108 return Service::Audio::ResultInvalidRevision; 108 return Service::Audio::ResultInvalidRevision;
109 } 109 }
@@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
119 behavior.SetUserLibRevision(params.revision); 119 behavior.SetUserLibRevision(params.revision);
120 120
121 process_handle = process_handle_; 121 process_handle = process_handle_;
122 process = &process_;
123 applet_resource_user_id = applet_resource_user_id_; 122 applet_resource_user_id = applet_resource_user_id_;
124 session_id = session_id_; 123 session_id = session_id_;
125 124
@@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
132 render_device = params.rendering_device; 131 render_device = params.rendering_device;
133 execution_mode = params.execution_mode; 132 execution_mode = params.execution_mode;
134 133
135 process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size); 134 process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
135 transfer_memory_size);
136 136
137 // Note: We're not actually using the transfer memory because it's a pain to code for. 137 // Note: We're not actually using the transfer memory because it's a pain to code for.
138 // Allocate the memory normally instead and hope the game doesn't try to read anything back 138 // Allocate the memory normally instead and hope the game doesn't try to read anything back
@@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
616 static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 * 616 static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
617 (static_cast<f32>(render_time_limit_percent) / 100.0f))}; 617 (static_cast<f32>(render_time_limit_percent) / 100.0f))};
618 audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit, 618 audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
619 applet_resource_user_id, process, 619 applet_resource_user_id, process_handle,
620 reset_command_buffers); 620 reset_command_buffers);
621 reset_command_buffers = false; 621 reset_command_buffers = false;
622 command_buffer_size = command_size; 622 command_buffer_size = command_size;
diff --git a/src/audio_core/renderer/system.h b/src/audio_core/renderer/system.h
index 753a0b796..3533a74ef 100644
--- a/src/audio_core/renderer/system.h
+++ b/src/audio_core/renderer/system.h
@@ -74,14 +74,14 @@ public:
74 * @param params - Input parameters to initialize the system with. 74 * @param params - Input parameters to initialize the system with.
75 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused. 75 * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
76 * @param transfer_memory_size - Size of the transfer memory. Unused. 76 * @param transfer_memory_size - Size of the transfer memory. Unused.
77 * @param process_handle - Process handle, also used for memory. Unused. 77 * @param process_handle - Process handle, also used for memory.
78 * @param applet_resource_user_id - Applet id for this renderer. Unused. 78 * @param applet_resource_user_id - Applet id for this renderer. Unused.
79 * @param session_id - Session id of this renderer. 79 * @param session_id - Session id of this renderer.
80 * @return Result code. 80 * @return Result code.
81 */ 81 */
82 Result Initialize(const AudioRendererParameterInternal& params, 82 Result Initialize(const AudioRendererParameterInternal& params,
83 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, 83 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
84 u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, 84 Kernel::KProcess* process_handle, u64 applet_resource_user_id,
85 s32 session_id); 85 s32 session_id);
86 86
87 /** 87 /**
@@ -278,9 +278,7 @@ private:
278 /// Does what locks do 278 /// Does what locks do
279 std::mutex lock{}; 279 std::mutex lock{};
280 /// Process this audio render is operating within, used for memory reads/writes. 280 /// Process this audio render is operating within, used for memory reads/writes.
281 Kernel::KProcess* process{}; 281 Kernel::KProcess* process_handle{};
282 /// Handle for the process for this system, unused
283 u32 process_handle{};
284 /// Applet resource id for this system, unused 282 /// Applet resource id for this system, unused
285 u64 applet_resource_user_id{}; 283 u64 applet_resource_user_id{};
286 /// Controls performance input and output 284 /// Controls performance input and output
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp
index d97ca2a40..49efae8e3 100644
--- a/src/audio_core/sink/cubeb_sink.cpp
+++ b/src/audio_core/sink/cubeb_sink.cpp
@@ -357,7 +357,9 @@ bool IsCubebSuitable() {
357 return false; 357 return false;
358 } 358 }
359 359
360 SCOPE_EXIT({ cubeb_destroy(ctx); }); 360 SCOPE_EXIT {
361 cubeb_destroy(ctx);
362 };
361 363
362#ifdef _WIN32 364#ifdef _WIN32
363 if (SUCCEEDED(com_init_result)) { 365 if (SUCCEEDED(com_init_result)) {
diff --git a/src/audio_core/sink/oboe_sink.cpp b/src/audio_core/sink/oboe_sink.cpp
index e61841172..466a9cc8e 100644
--- a/src/audio_core/sink/oboe_sink.cpp
+++ b/src/audio_core/sink/oboe_sink.cpp
@@ -67,9 +67,13 @@ public:
67 oboe::AudioStreamBuilder builder; 67 oboe::AudioStreamBuilder builder;
68 68
69 const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream); 69 const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
70 ASSERT(result == oboe::Result::OK); 70 if (result == oboe::Result::OK) {
71 return temp_stream->getChannelCount() >= 6 ? 6 : 2;
72 }
71 73
72 return temp_stream->getChannelCount() >= 6 ? 6 : 2; 74 LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
75 direction == oboe::Direction::Output ? "output" : "input");
76 return 2;
73 } 77 }
74 78
75protected: 79protected:
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index c047b0668..0a98eb31e 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -20,10 +20,10 @@
20namespace AudioCore::Sink { 20namespace AudioCore::Sink {
21 21
22void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { 22void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
23 SCOPE_EXIT({ 23 SCOPE_EXIT {
24 queue.enqueue(buffer); 24 queue.enqueue(buffer);
25 ++queued_buffers; 25 ++queued_buffers;
26 }); 26 };
27 27
28 if (type == StreamType::In) { 28 if (type == StreamType::In) {
29 return; 29 return;
diff --git a/src/common/demangle.cpp b/src/common/demangle.cpp
index 6e117cb41..b2c9d126a 100644
--- a/src/common/demangle.cpp
+++ b/src/common/demangle.cpp
@@ -20,7 +20,9 @@ std::string DemangleSymbol(const std::string& mangled) {
20 } 20 }
21 21
22 char* demangled = nullptr; 22 char* demangled = nullptr;
23 SCOPE_EXIT({ std::free(demangled); }); 23 SCOPE_EXIT {
24 std::free(demangled);
25 };
24 26
25 if (is_itanium(mangled)) { 27 if (is_itanium(mangled)) {
26 demangled = llvm::itaniumDemangle(mangled.c_str()); 28 demangled = llvm::itaniumDemangle(mangled.c_str());
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 860c39e6a..e0b5a6a67 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -430,11 +430,11 @@ public:
430 explicit Impl(size_t backing_size_, size_t virtual_size_) 430 explicit Impl(size_t backing_size_, size_t virtual_size_)
431 : backing_size{backing_size_}, virtual_size{virtual_size_} { 431 : backing_size{backing_size_}, virtual_size{virtual_size_} {
432 bool good = false; 432 bool good = false;
433 SCOPE_EXIT({ 433 SCOPE_EXIT {
434 if (!good) { 434 if (!good) {
435 Release(); 435 Release();
436 } 436 }
437 }); 437 };
438 438
439 long page_size = sysconf(_SC_PAGESIZE); 439 long page_size = sysconf(_SC_PAGESIZE);
440 if (page_size != 0x1000) { 440 if (page_size != 0x1000) {
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
index 85dc18c11..3205eb7da 100644
--- a/src/common/page_table.cpp
+++ b/src/common/page_table.cpp
@@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
24 out_entry->block_size = page_size; 24 out_entry->block_size = page_size;
25 25
26 // Regardless of whether the page was mapped, advance on exit. 26 // Regardless of whether the page was mapped, advance on exit.
27 SCOPE_EXIT({ 27 SCOPE_EXIT {
28 context->next_page += 1; 28 context->next_page += 1;
29 context->next_offset += page_size; 29 context->next_offset += page_size;
30 }); 30 };
31 31
32 // Validate that we can read the actual entry. 32 // Validate that we can read the actual entry.
33 const auto page = context->next_page; 33 const auto page = context->next_page;
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index e7e9fdb38..b92db6185 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -8,6 +8,7 @@
8#include <atomic> 8#include <atomic>
9#include <cstddef> 9#include <cstddef>
10#include <cstring> 10#include <cstring>
11#include <limits>
11#include <new> 12#include <new>
12#include <span> 13#include <span>
13#include <type_traits> 14#include <type_traits>
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
index e9c789c88..f3e88cde9 100644
--- a/src/common/scope_exit.h
+++ b/src/common/scope_exit.h
@@ -7,29 +7,61 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8 8
9namespace detail { 9namespace detail {
10template <typename Func> 10template <class F>
11struct ScopeExitHelper { 11class ScopeGuard {
12 explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {} 12 YUZU_NON_COPYABLE(ScopeGuard);
13 ~ScopeExitHelper() { 13
14private:
15 F f;
16 bool active;
17
18public:
19 constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
20 constexpr ~ScopeGuard() {
14 if (active) { 21 if (active) {
15 func(); 22 f();
16 } 23 }
17 } 24 }
18 25 constexpr void Cancel() {
19 void Cancel() {
20 active = false; 26 active = false;
21 } 27 }
22 28
23 Func func; 29 constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
24 bool active{true}; 30 rhs.Cancel();
31 }
32
33 ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
25}; 34};
26 35
27template <typename Func> 36template <class F>
28ScopeExitHelper<Func> ScopeExit(Func&& func) { 37constexpr ScopeGuard<F> MakeScopeGuard(F f) {
29 return ScopeExitHelper<Func>(std::forward<Func>(func)); 38 return ScopeGuard<F>(std::move(f));
30} 39}
40
41enum class ScopeGuardOnExit {};
42
43template <typename F>
44constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
45 return ScopeGuard<F>(std::forward<F>(f));
46}
47
31} // namespace detail 48} // namespace detail
32 49
50#define CONCATENATE_IMPL(s1, s2) s1##s2
51#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
52
53#ifdef __COUNTER__
54#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
55#else
56#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
57#endif
58
59/**
60 * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
61 * used when the caller might want to cancel the ScopeExit.
62 */
63#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
64
33/** 65/**
34 * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy 66 * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
35 * for doing ad-hoc clean-up tasks in a function with multiple returns. 67 * for doing ad-hoc clean-up tasks in a function with multiple returns.
@@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
38 * \code 70 * \code
39 * const int saved_val = g_foo; 71 * const int saved_val = g_foo;
40 * g_foo = 55; 72 * g_foo = 55;
41 * SCOPE_EXIT({ g_foo = saved_val; }); 73 * SCOPE_EXIT{ g_foo = saved_val; };
42 * 74 *
43 * if (Bar()) { 75 * if (Bar()) {
44 * return 0; 76 * return 0;
@@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
47 * } 79 * }
48 * \endcode 80 * \endcode
49 */ 81 */
50#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) 82#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
51
52/**
53 * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
54 * used when the caller might want to cancel the ScopeExit.
55 */
56#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)
diff --git a/src/common/settings.h b/src/common/settings.h
index aa054dc24..b2b071e7e 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -384,6 +384,12 @@ struct Values {
384 AstcRecompression::Bc3, 384 AstcRecompression::Bc3,
385 "astc_recompression", 385 "astc_recompression",
386 Category::RendererAdvanced}; 386 Category::RendererAdvanced};
387 SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
388 VramUsageMode::Conservative,
389 VramUsageMode::Conservative,
390 VramUsageMode::Aggressive,
391 "vram_usage_mode",
392 Category::RendererAdvanced};
387 SwitchableSetting<bool> async_presentation{linkage, 393 SwitchableSetting<bool> async_presentation{linkage,
388#ifdef ANDROID 394#ifdef ANDROID
389 true, 395 true,
diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h
index f42367e67..6e247e930 100644
--- a/src/common/settings_enums.h
+++ b/src/common/settings_enums.h
@@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
122 122
123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); 123ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
124 124
125ENUM(VramUsageMode, Conservative, Aggressive);
126
125ENUM(RendererBackend, OpenGL, Vulkan, Null); 127ENUM(RendererBackend, OpenGL, Vulkan, Null);
126 128
127ENUM(ShaderBackend, Glsl, Glasm, SpirV); 129ENUM(ShaderBackend, Glsl, Glasm, SpirV);
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 72c481798..1909aced5 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) {
38 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); 38 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
39} 39}
40 40
41std::string StringFromBuffer(std::span<const char> data) {
42 return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
43}
44
41// Turns " hej " into "hej". Also handles tabs. 45// Turns " hej " into "hej". Also handles tabs.
42std::string StripSpaces(const std::string& str) { 46std::string StripSpaces(const std::string& str) {
43 const std::size_t s = str.find_first_not_of(" \t\r\n"); 47 const std::size_t s = str.find_first_not_of(" \t\r\n");
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 9da1ca4e9..53d0549ca 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -19,6 +19,7 @@ namespace Common {
19[[nodiscard]] std::string ToUpper(std::string str); 19[[nodiscard]] std::string ToUpper(std::string str);
20 20
21[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data); 21[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
22[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
22 23
23[[nodiscard]] std::string StripSpaces(const std::string& s); 24[[nodiscard]] std::string StripSpaces(const std::string& s);
24[[nodiscard]] std::string StripQuotes(const std::string& s); 25[[nodiscard]] std::string StripQuotes(const std::string& s);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a54325f68..1eb43d816 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -2,8 +2,8 @@
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4add_library(core STATIC 4add_library(core STATIC
5 arm/arm_interface.h
6 arm/arm_interface.cpp 5 arm/arm_interface.cpp
6 arm/arm_interface.h
7 arm/debug.cpp 7 arm/debug.cpp
8 arm/debug.h 8 arm/debug.h
9 arm/exclusive_monitor.cpp 9 arm/exclusive_monitor.cpp
@@ -37,10 +37,10 @@ add_library(core STATIC
37 debugger/gdbstub.h 37 debugger/gdbstub.h
38 debugger/gdbstub_arch.cpp 38 debugger/gdbstub_arch.cpp
39 debugger/gdbstub_arch.h 39 debugger/gdbstub_arch.h
40 device_memory_manager.h
41 device_memory_manager.inc
42 device_memory.cpp 40 device_memory.cpp
43 device_memory.h 41 device_memory.h
42 device_memory_manager.h
43 device_memory_manager.inc
44 file_sys/bis_factory.cpp 44 file_sys/bis_factory.cpp
45 file_sys/bis_factory.h 45 file_sys/bis_factory.h
46 file_sys/card_image.cpp 46 file_sys/card_image.cpp
@@ -58,9 +58,14 @@ add_library(core STATIC
58 file_sys/fs_operate_range.h 58 file_sys/fs_operate_range.h
59 file_sys/fs_path.h 59 file_sys/fs_path.h
60 file_sys/fs_path_utility.h 60 file_sys/fs_path_utility.h
61 file_sys/fs_save_data_types.h
61 file_sys/fs_string_util.h 62 file_sys/fs_string_util.h
63 file_sys/fsa/fs_i_directory.h
64 file_sys/fsa/fs_i_file.h
65 file_sys/fsa/fs_i_filesystem.h
62 file_sys/fsmitm_romfsbuild.cpp 66 file_sys/fsmitm_romfsbuild.cpp
63 file_sys/fsmitm_romfsbuild.h 67 file_sys/fsmitm_romfsbuild.h
68 file_sys/fssrv/fssrv_sf_path.h
64 file_sys/fssystem/fs_i_storage.h 69 file_sys/fssystem/fs_i_storage.h
65 file_sys/fssystem/fs_types.h 70 file_sys/fssystem/fs_types.h
66 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp 71 file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@@ -390,6 +395,20 @@ add_library(core STATIC
390 hle/service/acc/errors.h 395 hle/service/acc/errors.h
391 hle/service/acc/profile_manager.cpp 396 hle/service/acc/profile_manager.cpp
392 hle/service/acc/profile_manager.h 397 hle/service/acc/profile_manager.h
398 hle/service/am/am.cpp
399 hle/service/am/am.h
400 hle/service/am/am_results.h
401 hle/service/am/am_types.h
402 hle/service/am/applet.cpp
403 hle/service/am/applet.h
404 hle/service/am/applet_data_broker.cpp
405 hle/service/am/applet_data_broker.h
406 hle/service/am/applet_manager.cpp
407 hle/service/am/applet_manager.h
408 hle/service/am/applet_message_queue.cpp
409 hle/service/am/applet_message_queue.h
410 hle/service/am/display_layer_manager.cpp
411 hle/service/am/display_layer_manager.h
393 hle/service/am/frontend/applet_cabinet.cpp 412 hle/service/am/frontend/applet_cabinet.cpp
394 hle/service/am/frontend/applet_cabinet.h 413 hle/service/am/frontend/applet_cabinet.h
395 hle/service/am/frontend/applet_controller.cpp 414 hle/service/am/frontend/applet_controller.cpp
@@ -411,20 +430,6 @@ add_library(core STATIC
411 hle/service/am/frontend/applet_web_browser_types.h 430 hle/service/am/frontend/applet_web_browser_types.h
412 hle/service/am/frontend/applets.cpp 431 hle/service/am/frontend/applets.cpp
413 hle/service/am/frontend/applets.h 432 hle/service/am/frontend/applets.h
414 hle/service/am/am.cpp
415 hle/service/am/am.h
416 hle/service/am/am_results.h
417 hle/service/am/am_types.h
418 hle/service/am/applet.cpp
419 hle/service/am/applet.h
420 hle/service/am/applet_manager.cpp
421 hle/service/am/applet_data_broker.cpp
422 hle/service/am/applet_data_broker.h
423 hle/service/am/applet_manager.h
424 hle/service/am/applet_message_queue.cpp
425 hle/service/am/applet_message_queue.h
426 hle/service/am/display_layer_manager.cpp
427 hle/service/am/display_layer_manager.h
428 hle/service/am/hid_registration.cpp 433 hle/service/am/hid_registration.cpp
429 hle/service/am/hid_registration.h 434 hle/service/am/hid_registration.h
430 hle/service/am/library_applet_storage.cpp 435 hle/service/am/library_applet_storage.cpp
@@ -441,10 +446,10 @@ add_library(core STATIC
441 hle/service/am/service/application_creator.h 446 hle/service/am/service/application_creator.h
442 hle/service/am/service/application_functions.cpp 447 hle/service/am/service/application_functions.cpp
443 hle/service/am/service/application_functions.h 448 hle/service/am/service/application_functions.h
444 hle/service/am/service/application_proxy_service.cpp
445 hle/service/am/service/application_proxy_service.h
446 hle/service/am/service/application_proxy.cpp 449 hle/service/am/service/application_proxy.cpp
447 hle/service/am/service/application_proxy.h 450 hle/service/am/service/application_proxy.h
451 hle/service/am/service/application_proxy_service.cpp
452 hle/service/am/service/application_proxy_service.h
448 hle/service/am/service/audio_controller.cpp 453 hle/service/am/service/audio_controller.cpp
449 hle/service/am/service/audio_controller.h 454 hle/service/am/service/audio_controller.h
450 hle/service/am/service/common_state_getter.cpp 455 hle/service/am/service/common_state_getter.cpp
@@ -473,10 +478,10 @@ add_library(core STATIC
473 hle/service/am/service/process_winding_controller.h 478 hle/service/am/service/process_winding_controller.h
474 hle/service/am/service/self_controller.cpp 479 hle/service/am/service/self_controller.cpp
475 hle/service/am/service/self_controller.h 480 hle/service/am/service/self_controller.h
476 hle/service/am/service/storage_accessor.cpp
477 hle/service/am/service/storage_accessor.h
478 hle/service/am/service/storage.cpp 481 hle/service/am/service/storage.cpp
479 hle/service/am/service/storage.h 482 hle/service/am/service/storage.h
483 hle/service/am/service/storage_accessor.cpp
484 hle/service/am/service/storage_accessor.h
480 hle/service/am/service/system_applet_proxy.cpp 485 hle/service/am/service/system_applet_proxy.cpp
481 hle/service/am/service/system_applet_proxy.h 486 hle/service/am/service/system_applet_proxy.h
482 hle/service/am/service/window_controller.cpp 487 hle/service/am/service/window_controller.cpp
@@ -491,37 +496,35 @@ add_library(core STATIC
491 hle/service/apm/apm_controller.h 496 hle/service/apm/apm_controller.h
492 hle/service/apm/apm_interface.cpp 497 hle/service/apm/apm_interface.cpp
493 hle/service/apm/apm_interface.h 498 hle/service/apm/apm_interface.h
494 hle/service/audio/audin_u.cpp
495 hle/service/audio/audin_u.h
496 hle/service/audio/audio.cpp
497 hle/service/audio/audio.h
498 hle/service/audio/audio_controller.cpp 499 hle/service/audio/audio_controller.cpp
499 hle/service/audio/audio_controller.h 500 hle/service/audio/audio_controller.h
500 hle/service/audio/audout_u.cpp 501 hle/service/audio/audio_device.cpp
501 hle/service/audio/audout_u.h 502 hle/service/audio/audio_device.h
502 hle/service/audio/audrec_a.cpp 503 hle/service/audio/audio_in_manager.cpp
503 hle/service/audio/audrec_a.h 504 hle/service/audio/audio_in_manager.h
504 hle/service/audio/audrec_u.cpp 505 hle/service/audio/audio_in.cpp
505 hle/service/audio/audrec_u.h 506 hle/service/audio/audio_in.h
506 hle/service/audio/audren_u.cpp 507 hle/service/audio/audio_out_manager.cpp
507 hle/service/audio/audren_u.h 508 hle/service/audio/audio_out_manager.h
509 hle/service/audio/audio_out.cpp
510 hle/service/audio/audio_out.h
511 hle/service/audio/audio_renderer_manager.cpp
512 hle/service/audio/audio_renderer_manager.h
513 hle/service/audio/audio_renderer.cpp
514 hle/service/audio/audio_renderer.h
515 hle/service/audio/audio.cpp
516 hle/service/audio/audio.h
508 hle/service/audio/errors.h 517 hle/service/audio/errors.h
509 hle/service/audio/hwopus.cpp 518 hle/service/audio/final_output_recorder_manager_for_applet.cpp
510 hle/service/audio/hwopus.h 519 hle/service/audio/final_output_recorder_manager_for_applet.h
520 hle/service/audio/final_output_recorder_manager.cpp
521 hle/service/audio/final_output_recorder_manager.h
522 hle/service/audio/hardware_opus_decoder_manager.cpp
523 hle/service/audio/hardware_opus_decoder_manager.h
524 hle/service/audio/hardware_opus_decoder.cpp
525 hle/service/audio/hardware_opus_decoder.h
511 hle/service/bcat/backend/backend.cpp 526 hle/service/bcat/backend/backend.cpp
512 hle/service/bcat/backend/backend.h 527 hle/service/bcat/backend/backend.h
513 hle/service/bcat/news/newly_arrived_event_holder.cpp
514 hle/service/bcat/news/newly_arrived_event_holder.h
515 hle/service/bcat/news/news_data_service.cpp
516 hle/service/bcat/news/news_data_service.h
517 hle/service/bcat/news/news_database_service.cpp
518 hle/service/bcat/news/news_database_service.h
519 hle/service/bcat/news/news_service.cpp
520 hle/service/bcat/news/news_service.h
521 hle/service/bcat/news/overwrite_event_holder.cpp
522 hle/service/bcat/news/overwrite_event_holder.h
523 hle/service/bcat/news/service_creator.cpp
524 hle/service/bcat/news/service_creator.h
525 hle/service/bcat/bcat.cpp 528 hle/service/bcat/bcat.cpp
526 hle/service/bcat/bcat.h 529 hle/service/bcat/bcat.h
527 hle/service/bcat/bcat_result.h 530 hle/service/bcat/bcat_result.h
@@ -537,6 +540,18 @@ add_library(core STATIC
537 hle/service/bcat/delivery_cache_progress_service.h 540 hle/service/bcat/delivery_cache_progress_service.h
538 hle/service/bcat/delivery_cache_storage_service.cpp 541 hle/service/bcat/delivery_cache_storage_service.cpp
539 hle/service/bcat/delivery_cache_storage_service.h 542 hle/service/bcat/delivery_cache_storage_service.h
543 hle/service/bcat/news/newly_arrived_event_holder.cpp
544 hle/service/bcat/news/newly_arrived_event_holder.h
545 hle/service/bcat/news/news_data_service.cpp
546 hle/service/bcat/news/news_data_service.h
547 hle/service/bcat/news/news_database_service.cpp
548 hle/service/bcat/news/news_database_service.h
549 hle/service/bcat/news/news_service.cpp
550 hle/service/bcat/news/news_service.h
551 hle/service/bcat/news/overwrite_event_holder.cpp
552 hle/service/bcat/news/overwrite_event_holder.h
553 hle/service/bcat/news/service_creator.cpp
554 hle/service/bcat/news/service_creator.h
540 hle/service/bcat/service_creator.cpp 555 hle/service/bcat/service_creator.cpp
541 hle/service/bcat/service_creator.h 556 hle/service/bcat/service_creator.h
542 hle/service/bpc/bpc.cpp 557 hle/service/bpc/bpc.cpp
@@ -545,6 +560,16 @@ add_library(core STATIC
545 hle/service/btdrv/btdrv.h 560 hle/service/btdrv/btdrv.h
546 hle/service/btm/btm.cpp 561 hle/service/btm/btm.cpp
547 hle/service/btm/btm.h 562 hle/service/btm/btm.h
563 hle/service/btm/btm_debug.cpp
564 hle/service/btm/btm_debug.h
565 hle/service/btm/btm_system.cpp
566 hle/service/btm/btm_system.h
567 hle/service/btm/btm_system_core.cpp
568 hle/service/btm/btm_system_core.h
569 hle/service/btm/btm_user.cpp
570 hle/service/btm/btm_user.h
571 hle/service/btm/btm_user_core.cpp
572 hle/service/btm/btm_user_core.h
548 hle/service/caps/caps.cpp 573 hle/service/caps/caps.cpp
549 hle/service/caps/caps.h 574 hle/service/caps/caps.h
550 hle/service/caps/caps_a.cpp 575 hle/service/caps/caps_a.cpp
@@ -587,6 +612,10 @@ add_library(core STATIC
587 hle/service/filesystem/fsp/fs_i_file.h 612 hle/service/filesystem/fsp/fs_i_file.h
588 hle/service/filesystem/fsp/fs_i_filesystem.cpp 613 hle/service/filesystem/fsp/fs_i_filesystem.cpp
589 hle/service/filesystem/fsp/fs_i_filesystem.h 614 hle/service/filesystem/fsp/fs_i_filesystem.h
615 hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
616 hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
617 hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
618 hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
590 hle/service/filesystem/fsp/fs_i_storage.cpp 619 hle/service/filesystem/fsp/fs_i_storage.cpp
591 hle/service/filesystem/fsp/fs_i_storage.h 620 hle/service/filesystem/fsp/fs_i_storage.h
592 hle/service/filesystem/fsp/fsp_ldr.cpp 621 hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -595,13 +624,13 @@ add_library(core STATIC
595 hle/service/filesystem/fsp/fsp_pr.h 624 hle/service/filesystem/fsp/fsp_pr.h
596 hle/service/filesystem/fsp/fsp_srv.cpp 625 hle/service/filesystem/fsp/fsp_srv.cpp
597 hle/service/filesystem/fsp/fsp_srv.h 626 hle/service/filesystem/fsp/fsp_srv.h
598 hle/service/filesystem/fsp/fsp_util.h 627 hle/service/filesystem/fsp/fsp_types.h
628 hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
629 hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
599 hle/service/filesystem/romfs_controller.cpp 630 hle/service/filesystem/romfs_controller.cpp
600 hle/service/filesystem/romfs_controller.h 631 hle/service/filesystem/romfs_controller.h
601 hle/service/filesystem/save_data_controller.cpp 632 hle/service/filesystem/save_data_controller.cpp
602 hle/service/filesystem/save_data_controller.h 633 hle/service/filesystem/save_data_controller.h
603 hle/service/fgm/fgm.cpp
604 hle/service/fgm/fgm.h
605 hle/service/friend/friend.cpp 634 hle/service/friend/friend.cpp
606 hle/service/friend/friend.h 635 hle/service/friend/friend.h
607 hle/service/friend/friend_interface.cpp 636 hle/service/friend/friend_interface.cpp
@@ -761,10 +790,10 @@ add_library(core STATIC
761 hle/service/ns/factory_reset_interface.h 790 hle/service/ns/factory_reset_interface.h
762 hle/service/ns/language.cpp 791 hle/service/ns/language.cpp
763 hle/service/ns/language.h 792 hle/service/ns/language.h
764 hle/service/ns/ns_results.h
765 hle/service/ns/ns_types.h
766 hle/service/ns/ns.cpp 793 hle/service/ns/ns.cpp
767 hle/service/ns/ns.h 794 hle/service/ns/ns.h
795 hle/service/ns/ns_results.h
796 hle/service/ns/ns_types.h
768 hle/service/ns/platform_service_manager.cpp 797 hle/service/ns/platform_service_manager.cpp
769 hle/service/ns/platform_service_manager.h 798 hle/service/ns/platform_service_manager.h
770 hle/service/ns/query_service.cpp 799 hle/service/ns/query_service.cpp
@@ -835,12 +864,12 @@ add_library(core STATIC
835 hle/service/nvnflinger/consumer_listener.h 864 hle/service/nvnflinger/consumer_listener.h
836 hle/service/nvnflinger/graphic_buffer_producer.cpp 865 hle/service/nvnflinger/graphic_buffer_producer.cpp
837 hle/service/nvnflinger/graphic_buffer_producer.h 866 hle/service/nvnflinger/graphic_buffer_producer.h
838 hle/service/nvnflinger/hos_binder_driver_server.cpp
839 hle/service/nvnflinger/hos_binder_driver_server.h
840 hle/service/nvnflinger/hos_binder_driver.cpp
841 hle/service/nvnflinger/hos_binder_driver.h
842 hle/service/nvnflinger/hardware_composer.cpp 867 hle/service/nvnflinger/hardware_composer.cpp
843 hle/service/nvnflinger/hardware_composer.h 868 hle/service/nvnflinger/hardware_composer.h
869 hle/service/nvnflinger/hos_binder_driver.cpp
870 hle/service/nvnflinger/hos_binder_driver.h
871 hle/service/nvnflinger/hos_binder_driver_server.cpp
872 hle/service/nvnflinger/hos_binder_driver_server.h
844 hle/service/nvnflinger/hwc_layer.h 873 hle/service/nvnflinger/hwc_layer.h
845 hle/service/nvnflinger/nvnflinger.cpp 874 hle/service/nvnflinger/nvnflinger.cpp
846 hle/service/nvnflinger/nvnflinger.h 875 hle/service/nvnflinger/nvnflinger.h
@@ -854,8 +883,20 @@ add_library(core STATIC
854 hle/service/nvnflinger/ui/graphic_buffer.cpp 883 hle/service/nvnflinger/ui/graphic_buffer.cpp
855 hle/service/nvnflinger/ui/graphic_buffer.h 884 hle/service/nvnflinger/ui/graphic_buffer.h
856 hle/service/nvnflinger/window.h 885 hle/service/nvnflinger/window.h
886 hle/service/olsc/daemon_controller.cpp
887 hle/service/olsc/daemon_controller.h
888 hle/service/olsc/native_handle_holder.cpp
889 hle/service/olsc/native_handle_holder.h
890 hle/service/olsc/olsc_service_for_application.cpp
891 hle/service/olsc/olsc_service_for_application.h
892 hle/service/olsc/olsc_service_for_system_service.cpp
893 hle/service/olsc/olsc_service_for_system_service.h
857 hle/service/olsc/olsc.cpp 894 hle/service/olsc/olsc.cpp
858 hle/service/olsc/olsc.h 895 hle/service/olsc/olsc.h
896 hle/service/olsc/remote_storage_controller.cpp
897 hle/service/olsc/remote_storage_controller.h
898 hle/service/olsc/transfer_task_list_controller.cpp
899 hle/service/olsc/transfer_task_list_controller.h
859 hle/service/omm/omm.cpp 900 hle/service/omm/omm.cpp
860 hle/service/omm/omm.h 901 hle/service/omm/omm.h
861 hle/service/omm/operation_mode_manager.cpp 902 hle/service/omm/operation_mode_manager.cpp
@@ -866,25 +907,44 @@ add_library(core STATIC
866 hle/service/omm/power_state_interface.h 907 hle/service/omm/power_state_interface.h
867 hle/service/os/event.cpp 908 hle/service/os/event.cpp
868 hle/service/os/event.h 909 hle/service/os/event.h
910 hle/service/os/multi_wait.cpp
911 hle/service/os/multi_wait.h
869 hle/service/os/multi_wait_holder.cpp 912 hle/service/os/multi_wait_holder.cpp
870 hle/service/os/multi_wait_holder.h 913 hle/service/os/multi_wait_holder.h
871 hle/service/os/multi_wait_utils.h 914 hle/service/os/multi_wait_utils.h
872 hle/service/os/multi_wait.cpp
873 hle/service/os/multi_wait.h
874 hle/service/os/mutex.cpp 915 hle/service/os/mutex.cpp
875 hle/service/os/mutex.h 916 hle/service/os/mutex.h
876 hle/service/pcie/pcie.cpp 917 hle/service/pcie/pcie.cpp
877 hle/service/pcie/pcie.h 918 hle/service/pcie/pcie.h
919 hle/service/pctl/parental_control_service_factory.cpp
920 hle/service/pctl/parental_control_service_factory.h
921 hle/service/pctl/parental_control_service.cpp
922 hle/service/pctl/parental_control_service.h
878 hle/service/pctl/pctl.cpp 923 hle/service/pctl/pctl.cpp
879 hle/service/pctl/pctl.h 924 hle/service/pctl/pctl.h
880 hle/service/pctl/pctl_module.cpp 925 hle/service/pctl/pctl_results.h
881 hle/service/pctl/pctl_module.h 926 hle/service/pctl/pctl_types.h
882 hle/service/pcv/pcv.cpp 927 hle/service/pcv/pcv.cpp
883 hle/service/pcv/pcv.h 928 hle/service/pcv/pcv.h
884 hle/service/pm/pm.cpp 929 hle/service/pm/pm.cpp
885 hle/service/pm/pm.h 930 hle/service/pm/pm.h
886 hle/service/prepo/prepo.cpp 931 hle/service/prepo/prepo.cpp
887 hle/service/prepo/prepo.h 932 hle/service/prepo/prepo.h
933 hle/service/psc/ovln/ovln_types.h
934 hle/service/psc/ovln/receiver_service.cpp
935 hle/service/psc/ovln/receiver_service.h
936 hle/service/psc/ovln/receiver.cpp
937 hle/service/psc/ovln/receiver.h
938 hle/service/psc/ovln/sender_service.cpp
939 hle/service/psc/ovln/sender_service.h
940 hle/service/psc/ovln/sender.cpp
941 hle/service/psc/ovln/sender.h
942 hle/service/psc/pm_control.cpp
943 hle/service/psc/pm_control.h
944 hle/service/psc/pm_module.cpp
945 hle/service/psc/pm_module.h
946 hle/service/psc/pm_service.cpp
947 hle/service/psc/pm_service.h
888 hle/service/psc/psc.cpp 948 hle/service/psc/psc.cpp
889 hle/service/psc/psc.h 949 hle/service/psc/psc.h
890 hle/service/psc/time/alarms.cpp 950 hle/service/psc/time/alarms.cpp
@@ -908,15 +968,17 @@ add_library(core STATIC
908 hle/service/psc/time/common.cpp 968 hle/service/psc/time/common.cpp
909 hle/service/psc/time/common.h 969 hle/service/psc/time/common.h
910 hle/service/psc/time/errors.h 970 hle/service/psc/time/errors.h
911 hle/service/psc/time/shared_memory.cpp
912 hle/service/psc/time/shared_memory.h
913 hle/service/psc/time/static.cpp
914 hle/service/psc/time/static.h
915 hle/service/psc/time/manager.h 971 hle/service/psc/time/manager.h
972 hle/service/psc/time/power_state_request_manager.cpp
973 hle/service/psc/time/power_state_request_manager.h
916 hle/service/psc/time/power_state_service.cpp 974 hle/service/psc/time/power_state_service.cpp
917 hle/service/psc/time/power_state_service.h 975 hle/service/psc/time/power_state_service.h
918 hle/service/psc/time/service_manager.cpp 976 hle/service/psc/time/service_manager.cpp
919 hle/service/psc/time/service_manager.h 977 hle/service/psc/time/service_manager.h
978 hle/service/psc/time/shared_memory.cpp
979 hle/service/psc/time/shared_memory.h
980 hle/service/psc/time/static.cpp
981 hle/service/psc/time/static.h
920 hle/service/psc/time/steady_clock.cpp 982 hle/service/psc/time/steady_clock.cpp
921 hle/service/psc/time/steady_clock.h 983 hle/service/psc/time/steady_clock.h
922 hle/service/psc/time/system_clock.cpp 984 hle/service/psc/time/system_clock.cpp
@@ -925,8 +987,6 @@ add_library(core STATIC
925 hle/service/psc/time/time_zone.h 987 hle/service/psc/time/time_zone.h
926 hle/service/psc/time/time_zone_service.cpp 988 hle/service/psc/time/time_zone_service.cpp
927 hle/service/psc/time/time_zone_service.h 989 hle/service/psc/time/time_zone_service.h
928 hle/service/psc/time/power_state_request_manager.cpp
929 hle/service/psc/time/power_state_request_manager.h
930 hle/service/ptm/psm.cpp 990 hle/service/ptm/psm.cpp
931 hle/service/ptm/psm.h 991 hle/service/ptm/psm.h
932 hle/service/ptm/ptm.cpp 992 hle/service/ptm/ptm.cpp
@@ -945,19 +1005,19 @@ add_library(core STATIC
945 hle/service/service.h 1005 hle/service/service.h
946 hle/service/services.cpp 1006 hle/service/services.cpp
947 hle/service/services.h 1007 hle/service/services.h
1008 hle/service/set/factory_settings_server.cpp
1009 hle/service/set/factory_settings_server.h
1010 hle/service/set/firmware_debug_settings_server.cpp
1011 hle/service/set/firmware_debug_settings_server.h
1012 hle/service/set/key_code_map.h
948 hle/service/set/setting_formats/appln_settings.cpp 1013 hle/service/set/setting_formats/appln_settings.cpp
949 hle/service/set/setting_formats/appln_settings.h 1014 hle/service/set/setting_formats/appln_settings.h
950 hle/service/set/setting_formats/device_settings.cpp 1015 hle/service/set/setting_formats/device_settings.cpp
951 hle/service/set/setting_formats/device_settings.h 1016 hle/service/set/setting_formats/device_settings.h
952 hle/service/set/setting_formats/system_settings.cpp
953 hle/service/set/setting_formats/system_settings.h
954 hle/service/set/setting_formats/private_settings.cpp 1017 hle/service/set/setting_formats/private_settings.cpp
955 hle/service/set/setting_formats/private_settings.h 1018 hle/service/set/setting_formats/private_settings.h
956 hle/service/set/factory_settings_server.cpp 1019 hle/service/set/setting_formats/system_settings.cpp
957 hle/service/set/factory_settings_server.h 1020 hle/service/set/setting_formats/system_settings.h
958 hle/service/set/firmware_debug_settings_server.cpp
959 hle/service/set/firmware_debug_settings_server.h
960 hle/service/set/key_code_map.h
961 hle/service/set/settings.cpp 1021 hle/service/set/settings.cpp
962 hle/service/set/settings.h 1022 hle/service/set/settings.h
963 hle/service/set/settings_server.cpp 1023 hle/service/set/settings_server.cpp
@@ -1000,10 +1060,10 @@ add_library(core STATIC
1000 hle/service/vi/conductor.h 1060 hle/service/vi/conductor.h
1001 hle/service/vi/container.cpp 1061 hle/service/vi/container.cpp
1002 hle/service/vi/container.h 1062 hle/service/vi/container.h
1003 hle/service/vi/display_list.h
1004 hle/service/vi/display.h 1063 hle/service/vi/display.h
1005 hle/service/vi/layer_list.h 1064 hle/service/vi/display_list.h
1006 hle/service/vi/layer.h 1065 hle/service/vi/layer.h
1066 hle/service/vi/layer_list.h
1007 hle/service/vi/manager_display_service.cpp 1067 hle/service/vi/manager_display_service.cpp
1008 hle/service/vi/manager_display_service.h 1068 hle/service/vi/manager_display_service.h
1009 hle/service/vi/manager_root_service.cpp 1069 hle/service/vi/manager_root_service.cpp
@@ -1016,10 +1076,10 @@ add_library(core STATIC
1016 hle/service/vi/system_display_service.h 1076 hle/service/vi/system_display_service.h
1017 hle/service/vi/system_root_service.cpp 1077 hle/service/vi/system_root_service.cpp
1018 hle/service/vi/system_root_service.h 1078 hle/service/vi/system_root_service.h
1019 hle/service/vi/vi_results.h
1020 hle/service/vi/vi_types.h
1021 hle/service/vi/vi.cpp 1079 hle/service/vi/vi.cpp
1022 hle/service/vi/vi.h 1080 hle/service/vi/vi.h
1081 hle/service/vi/vi_results.h
1082 hle/service/vi/vi_types.h
1023 hle/service/vi/vsync_manager.cpp 1083 hle/service/vi/vsync_manager.cpp
1024 hle/service/vi/vsync_manager.h 1084 hle/service/vi/vsync_manager.h
1025 internal_network/network.cpp 1085 internal_network/network.cpp
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 7a5c22f78..9b1c77387 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
199 data.host_context = Common::Fiber::ThreadToFiber(); 199 data.host_context = Common::Fiber::ThreadToFiber();
200 200
201 // Cleanup 201 // Cleanup
202 SCOPE_EXIT({ 202 SCOPE_EXIT {
203 data.host_context->Exit(); 203 data.host_context->Exit();
204 MicroProfileOnThreadExit(); 204 MicroProfileOnThreadExit();
205 }); 205 };
206 206
207 // Running 207 // Running
208 if (!gpu_barrier->Sync(token)) { 208 if (!gpu_barrier->Sync(token)) {
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index 6dfee806c..f104d495b 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
391 std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); 391 std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
392 const auto current_vaddr = 392 const auto current_vaddr =
393 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); 393 static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
394 SCOPE_EXIT({ 394 SCOPE_EXIT{
395 page_index += next_pages; 395 page_index += next_pages;
396 page_offset = 0; 396 page_offset = 0;
397 increment(copy_amount); 397 increment(copy_amount);
398 remaining_size -= copy_amount; 398 remaining_size -= copy_amount;
399 }); 399 };
400 400
401 auto phys_addr = compressed_physical_ptr[page_index]; 401 auto phys_addr = compressed_physical_ptr[page_index];
402 if (phys_addr == 0) { 402 if (phys_addr == 0) {
@@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
522 auto* memory_device_inter = registered_processes[asid.id]; 522 auto* memory_device_inter = registered_processes[asid.id];
523 const auto release_pending = [&] { 523 const auto release_pending = [&] {
524 if (uncache_bytes > 0) { 524 if (uncache_bytes > 0) {
525 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, 525 if (memory_device_inter != nullptr) {
526 uncache_bytes, false); 526 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
527 uncache_bytes, false);
528 }
527 uncache_bytes = 0; 529 uncache_bytes = 0;
528 } 530 }
529 if (cache_bytes > 0) { 531 if (cache_bytes > 0) {
530 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, 532 if (memory_device_inter != nullptr) {
531 cache_bytes, true); 533 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
534 cache_bytes, true);
535 }
532 cache_bytes = 0; 536 cache_bytes = 0;
533 } 537 }
534 }; 538 };
diff --git a/src/core/file_sys/fs_directory.h b/src/core/file_sys/fs_directory.h
index 25c9cb18a..3f90abb8f 100644
--- a/src/core/file_sys/fs_directory.h
+++ b/src/core/file_sys/fs_directory.h
@@ -3,6 +3,10 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <string_view>
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9
6namespace FileSys { 10namespace FileSys {
7 11
8constexpr inline size_t EntryNameLengthMax = 0x300; 12constexpr inline size_t EntryNameLengthMax = 0x300;
diff --git a/src/core/file_sys/fs_filesystem.h b/src/core/file_sys/fs_filesystem.h
index 7f237b7fa..329b5aca5 100644
--- a/src/core/file_sys/fs_filesystem.h
+++ b/src/core/file_sys/fs_filesystem.h
@@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
23 File = (1 << 1), 23 File = (1 << 1),
24 24
25 All = (Directory | File), 25 All = (Directory | File),
26
27 NotRequireFileSize = (1ULL << 31),
26}; 28};
27DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) 29DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
28 30
@@ -36,4 +38,29 @@ enum class CreateOption : u8 {
36 BigFile = (1 << 0), 38 BigFile = (1 << 0),
37}; 39};
38 40
41struct FileSystemAttribute {
42 u8 dir_entry_name_length_max_defined;
43 u8 file_entry_name_length_max_defined;
44 u8 dir_path_name_length_max_defined;
45 u8 file_path_name_length_max_defined;
46 INSERT_PADDING_BYTES_NOINIT(0x5);
47 u8 utf16_dir_entry_name_length_max_defined;
48 u8 utf16_file_entry_name_length_max_defined;
49 u8 utf16_dir_path_name_length_max_defined;
50 u8 utf16_file_path_name_length_max_defined;
51 INSERT_PADDING_BYTES_NOINIT(0x18);
52 s32 dir_entry_name_length_max;
53 s32 file_entry_name_length_max;
54 s32 dir_path_name_length_max;
55 s32 file_path_name_length_max;
56 INSERT_PADDING_WORDS_NOINIT(0x5);
57 s32 utf16_dir_entry_name_length_max;
58 s32 utf16_file_entry_name_length_max;
59 s32 utf16_dir_path_name_length_max;
60 s32 utf16_file_path_name_length_max;
61 INSERT_PADDING_WORDS_NOINIT(0x18);
62 INSERT_PADDING_WORDS_NOINIT(0x1);
63};
64static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
65
39} // namespace FileSys 66} // namespace FileSys
diff --git a/src/core/file_sys/fs_memory_management.h b/src/core/file_sys/fs_memory_management.h
index f03c6354b..080017c5d 100644
--- a/src/core/file_sys/fs_memory_management.h
+++ b/src/core/file_sys/fs_memory_management.h
@@ -10,7 +10,7 @@ namespace FileSys {
10 10
11constexpr size_t RequiredAlignment = alignof(u64); 11constexpr size_t RequiredAlignment = alignof(u64);
12 12
13void* AllocateUnsafe(size_t size) { 13inline void* AllocateUnsafe(size_t size) {
14 // Allocate 14 // Allocate
15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); 15 void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
16 16
@@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
21 return ptr; 21 return ptr;
22} 22}
23 23
24void DeallocateUnsafe(void* ptr, size_t size) { 24inline void DeallocateUnsafe(void* ptr, size_t size) {
25 // Deallocate the pointer 25 // Deallocate the pointer
26 ::operator delete(ptr, std::align_val_t{RequiredAlignment}); 26 ::operator delete(ptr, std::align_val_t{RequiredAlignment});
27} 27}
28 28
29void* Allocate(size_t size) { 29inline void* Allocate(size_t size) {
30 return AllocateUnsafe(size); 30 return AllocateUnsafe(size);
31} 31}
32 32
33void Deallocate(void* ptr, size_t size) { 33inline void Deallocate(void* ptr, size_t size) {
34 // If the pointer is non-null, deallocate it 34 // If the pointer is non-null, deallocate it
35 if (ptr != nullptr) { 35 if (ptr != nullptr) {
36 DeallocateUnsafe(ptr, size); 36 DeallocateUnsafe(ptr, size);
diff --git a/src/core/file_sys/fs_path.h b/src/core/file_sys/fs_path.h
index 56ba08a6a..1566e82b9 100644
--- a/src/core/file_sys/fs_path.h
+++ b/src/core/file_sys/fs_path.h
@@ -381,7 +381,7 @@ public:
381 381
382 // Check that it's possible for us to remove a child 382 // Check that it's possible for us to remove a child
383 auto* p = m_write_buffer.Get(); 383 auto* p = m_write_buffer.Get();
384 s32 len = std::strlen(p); 384 s32 len = static_cast<s32>(std::strlen(p));
385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); 385 R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
386 386
387 // Handle a trailing separator 387 // Handle a trailing separator
diff --git a/src/core/file_sys/fs_path_utility.h b/src/core/file_sys/fs_path_utility.h
index e9011d065..cdfd8c772 100644
--- a/src/core/file_sys/fs_path_utility.h
+++ b/src/core/file_sys/fs_path_utility.h
@@ -426,9 +426,10 @@ public:
426 R_SUCCEED(); 426 R_SUCCEED();
427 } 427 }
428 428
429 static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size, 429 static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
430 bool is_windows_path, bool is_drive_relative_path, 430 size_t max_out_size, bool is_windows_path,
431 bool allow_all_characters = false) { 431 bool is_drive_relative_path,
432 bool allow_all_characters = false) {
432 // Use StringTraits names for remainder of scope 433 // Use StringTraits names for remainder of scope
433 using namespace StringTraits; 434 using namespace StringTraits;
434 435
@@ -447,7 +448,7 @@ public:
447 char* replacement_path = nullptr; 448 char* replacement_path = nullptr;
448 size_t replacement_path_size = 0; 449 size_t replacement_path_size = 0;
449 450
450 SCOPE_EXIT({ 451 SCOPE_EXIT {
451 if (replacement_path != nullptr) { 452 if (replacement_path != nullptr) {
452 if (std::is_constant_evaluated()) { 453 if (std::is_constant_evaluated()) {
453 delete[] replacement_path; 454 delete[] replacement_path;
@@ -455,7 +456,7 @@ public:
455 Deallocate(replacement_path, replacement_path_size); 456 Deallocate(replacement_path, replacement_path_size);
456 } 457 }
457 } 458 }
458 }); 459 };
459 460
460 // Perform path replacement, if necessary 461 // Perform path replacement, if necessary
461 if (IsParentDirectoryPathReplacementNeeded(cur_path)) { 462 if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
@@ -1102,8 +1103,8 @@ public:
1102 R_SUCCEED(); 1103 R_SUCCEED();
1103 } 1104 }
1104 1105
1105 static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len, 1106 static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
1106 const PathFlags& flags) { 1107 const PathFlags& flags) {
1107 // Use StringTraits names for remainder of scope 1108 // Use StringTraits names for remainder of scope
1108 using namespace StringTraits; 1109 using namespace StringTraits;
1109 1110
@@ -1199,7 +1200,7 @@ public:
1199 const size_t replaced_src_len = path_len - (src - path); 1200 const size_t replaced_src_len = path_len - (src - path);
1200 1201
1201 char* replaced_src = nullptr; 1202 char* replaced_src = nullptr;
1202 SCOPE_EXIT({ 1203 SCOPE_EXIT {
1203 if (replaced_src != nullptr) { 1204 if (replaced_src != nullptr) {
1204 if (std::is_constant_evaluated()) { 1205 if (std::is_constant_evaluated()) {
1205 delete[] replaced_src; 1206 delete[] replaced_src;
@@ -1207,7 +1208,7 @@ public:
1207 Deallocate(replaced_src, replaced_src_len); 1208 Deallocate(replaced_src, replaced_src_len);
1208 } 1209 }
1209 } 1210 }
1210 }); 1211 };
1211 1212
1212 if (std::is_constant_evaluated()) { 1213 if (std::is_constant_evaluated()) {
1213 replaced_src = new char[replaced_src_len]; 1214 replaced_src = new char[replaced_src_len];
diff --git a/src/core/file_sys/fs_save_data_types.h b/src/core/file_sys/fs_save_data_types.h
new file mode 100644
index 000000000..493dba34f
--- /dev/null
+++ b/src/core/file_sys/fs_save_data_types.h
@@ -0,0 +1,188 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <fmt/format.h>
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace FileSys {
12
13using SaveDataId = u64;
14using SystemSaveDataId = u64;
15using SystemBcatSaveDataId = SystemSaveDataId;
16using ProgramId = u64;
17
18enum class SaveDataSpaceId : u8 {
19 System = 0,
20 User = 1,
21 SdSystem = 2,
22 Temporary = 3,
23 SdUser = 4,
24
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 System = 0,
31 Account = 1,
32 Bcat = 2,
33 Device = 3,
34 Temporary = 4,
35 Cache = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44struct SaveDataSize {
45 u64 normal;
46 u64 journal;
47};
48static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
49
50using UserId = u128;
51static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
52static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
53
54constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
55constexpr inline UserId InvalidUserId = {};
56
57enum class SaveDataFlags : u32 {
58 None = (0 << 0),
59 KeepAfterResettingSystemSaveData = (1 << 0),
60 KeepAfterRefurbishment = (1 << 1),
61 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
62 NeedsSecureDelete = (1 << 3),
63};
64
65enum class SaveDataMetaType : u8 {
66 None = 0,
67 Thumbnail = 1,
68 ExtensionContext = 2,
69};
70
71struct SaveDataMetaInfo {
72 u32 size;
73 SaveDataMetaType type;
74 INSERT_PADDING_BYTES(0xB);
75};
76static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
77 "Data type must be trivially copyable.");
78static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
79
80struct SaveDataCreationInfo {
81 s64 size;
82 s64 journal_size;
83 s64 block_size;
84 u64 owner_id;
85 u32 flags;
86 SaveDataSpaceId space_id;
87 bool pseudo;
88 INSERT_PADDING_BYTES(0x1A);
89};
90static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
91 "Data type must be trivially copyable.");
92static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
93
94struct SaveDataAttribute {
95 ProgramId program_id;
96 UserId user_id;
97 SystemSaveDataId system_save_data_id;
98 SaveDataType type;
99 SaveDataRank rank;
100 u16 index;
101 INSERT_PADDING_BYTES(0x1C);
102
103 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
104 SystemSaveDataId system_save_data_id, u16 index,
105 SaveDataRank rank) {
106 return {
107 .program_id = program_id,
108 .user_id = user_id,
109 .system_save_data_id = system_save_data_id,
110 .type = type,
111 .rank = rank,
112 .index = index,
113 };
114 }
115
116 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
117 SystemSaveDataId system_save_data_id, u16 index) {
118 return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
119 }
120
121 static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
122 SystemSaveDataId system_save_data_id) {
123 return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
124 }
125
126 std::string DebugInfo() const {
127 return fmt::format(
128 "[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
129 "rank={}, index={}]",
130 program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
131 static_cast<u8>(rank), index);
132 }
133};
134static_assert(sizeof(SaveDataAttribute) == 0x40);
135static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
136
137constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
138 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
139 std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
140}
141
142constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
143 return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
144 lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
145 rhs.type, rhs.rank, rhs.index);
146}
147
148constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
149 return !(lhs == rhs);
150}
151
152struct SaveDataExtraData {
153 SaveDataAttribute attr;
154 u64 owner_id;
155 s64 timestamp;
156 u32 flags;
157 INSERT_PADDING_BYTES(4);
158 s64 available_size;
159 s64 journal_size;
160 s64 commit_id;
161 INSERT_PADDING_BYTES(0x190);
162};
163static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
164static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
165 "Data type must be trivially copyable.");
166
167struct SaveDataFilter {
168 bool use_program_id;
169 bool use_save_data_type;
170 bool use_user_id;
171 bool use_save_data_id;
172 bool use_index;
173 SaveDataRank rank;
174 SaveDataAttribute attribute;
175};
176static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size.");
177static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
178 "Data type must be trivially copyable.");
179
180struct HashSalt {
181 static constexpr size_t Size = 32;
182
183 std::array<u8, Size> value;
184};
185static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
186static_assert(sizeof(HashSalt) == HashSalt::Size);
187
188} // namespace FileSys
diff --git a/src/core/file_sys/fs_string_util.h b/src/core/file_sys/fs_string_util.h
index 874e09054..c751a8f1a 100644
--- a/src/core/file_sys/fs_string_util.h
+++ b/src/core/file_sys/fs_string_util.h
@@ -20,6 +20,11 @@ constexpr int Strlen(const T* str) {
20} 20}
21 21
22template <typename T> 22template <typename T>
23constexpr int Strnlen(const T* str, std::size_t count) {
24 return Strnlen(str, static_cast<int>(count));
25}
26
27template <typename T>
23constexpr int Strnlen(const T* str, int count) { 28constexpr int Strnlen(const T* str, int count) {
24 ASSERT(str != nullptr); 29 ASSERT(str != nullptr);
25 ASSERT(count >= 0); 30 ASSERT(count >= 0);
@@ -33,6 +38,11 @@ constexpr int Strnlen(const T* str, int count) {
33} 38}
34 39
35template <typename T> 40template <typename T>
41constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
42 return Strncmp(lhs, rhs, static_cast<int>(count));
43}
44
45template <typename T>
36constexpr int Strncmp(const T* lhs, const T* rhs, int count) { 46constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
37 ASSERT(lhs != nullptr); 47 ASSERT(lhs != nullptr);
38 ASSERT(rhs != nullptr); 48 ASSERT(rhs != nullptr);
@@ -52,6 +62,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
52} 62}
53 63
54template <typename T> 64template <typename T>
65static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
66 return Strlcpy<T>(dst, src, static_cast<int>(count));
67}
68
69template <typename T>
55static constexpr int Strlcpy(T* dst, const T* src, int count) { 70static constexpr int Strlcpy(T* dst, const T* src, int count) {
56 ASSERT(dst != nullptr); 71 ASSERT(dst != nullptr);
57 ASSERT(src != nullptr); 72 ASSERT(src != nullptr);
diff --git a/src/core/file_sys/fsa/fs_i_directory.h b/src/core/file_sys/fsa/fs_i_directory.h
new file mode 100644
index 000000000..c8e895eab
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_directory.h
@@ -0,0 +1,91 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_directory.h"
9#include "core/file_sys/fs_file.h"
10#include "core/file_sys/fs_filesystem.h"
11#include "core/file_sys/savedata_factory.h"
12#include "core/file_sys/vfs/vfs.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IDirectory {
18public:
19 explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
20 : backend(std::move(backend_)) {
21 // TODO(DarkLordZach): Verify that this is the correct behavior.
22 // Build entry index now to save time later.
23 if (True(mode & OpenDirectoryMode::Directory)) {
24 BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
25 }
26 if (True(mode & OpenDirectoryMode::File)) {
27 BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
28 }
29 }
30 virtual ~IDirectory() {}
31
32 Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
33 R_UNLESS(out_count != nullptr, ResultNullptrArgument);
34 if (max_entries == 0) {
35 *out_count = 0;
36 R_SUCCEED();
37 }
38 R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
39 R_UNLESS(max_entries > 0, ResultInvalidArgument);
40 R_RETURN(this->DoRead(out_count, out_entries, max_entries));
41 }
42
43 Result GetEntryCount(s64* out) {
44 R_UNLESS(out != nullptr, ResultNullptrArgument);
45 R_RETURN(this->DoGetEntryCount(out));
46 }
47
48private:
49 Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
50 const u64 actual_entries =
51 std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
52 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
53 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
54 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
55
56 next_entry_index += actual_entries;
57 *out_count = actual_entries;
58
59 std::memcpy(out_entries, begin, range_size);
60
61 R_SUCCEED();
62 }
63
64 Result DoGetEntryCount(s64* out) {
65 *out = entries.size() - next_entry_index;
66 R_SUCCEED();
67 }
68
69 // TODO: Remove this when VFS is gone
70 template <typename T>
71 void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
72 entries.reserve(entries.size() + new_data.size());
73
74 for (const auto& new_entry : new_data) {
75 auto name = new_entry->GetName();
76
77 if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
78 continue;
79 }
80
81 entries.emplace_back(name, static_cast<s8>(type),
82 type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
83 }
84 }
85
86 VirtualDir backend;
87 std::vector<DirectoryEntry> entries;
88 u64 next_entry_index = 0;
89};
90
91} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_file.h b/src/core/file_sys/fsa/fs_i_file.h
new file mode 100644
index 000000000..1188ae8ca
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_file.h
@@ -0,0 +1,167 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/overflow.h"
7#include "core/file_sys/errors.h"
8#include "core/file_sys/fs_file.h"
9#include "core/file_sys/fs_filesystem.h"
10#include "core/file_sys/fs_operate_range.h"
11#include "core/file_sys/vfs/vfs.h"
12#include "core/file_sys/vfs/vfs_types.h"
13#include "core/hle/result.h"
14
15namespace FileSys::Fsa {
16
17class IFile {
18public:
19 explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
20 virtual ~IFile() {}
21
22 Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
23 // Check that we have an output pointer
24 R_UNLESS(out != nullptr, ResultNullptrArgument);
25
26 // If we have nothing to read, just succeed
27 if (size == 0) {
28 *out = 0;
29 R_SUCCEED();
30 }
31
32 // Check that the read is valid
33 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
34 R_UNLESS(offset >= 0, ResultOutOfRange);
35 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
36
37 // Do the read
38 R_RETURN(this->DoRead(out, offset, buffer, size, option));
39 }
40
41 Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
42 R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
43 }
44
45 Result GetSize(s64* out) {
46 R_UNLESS(out != nullptr, ResultNullptrArgument);
47 R_RETURN(this->DoGetSize(out));
48 }
49
50 Result Flush() {
51 R_RETURN(this->DoFlush());
52 }
53
54 Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
55 // Handle the zero-size case
56 if (size == 0) {
57 if (option.HasFlushFlag()) {
58 R_TRY(this->Flush());
59 }
60 R_SUCCEED();
61 }
62
63 // Check the write is valid
64 R_UNLESS(buffer != nullptr, ResultNullptrArgument);
65 R_UNLESS(offset >= 0, ResultOutOfRange);
66 R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
67
68 R_RETURN(this->DoWrite(offset, buffer, size, option));
69 }
70
71 Result SetSize(s64 size) {
72 R_UNLESS(size >= 0, ResultOutOfRange);
73 R_RETURN(this->DoSetSize(size));
74 }
75
76 Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
77 const void* src, size_t src_size) {
78 R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
79 }
80
81 Result OperateRange(OperationId op_id, s64 offset, s64 size) {
82 R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
83 }
84
85protected:
86 Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
87 OpenMode open_mode) {
88 // Check that we can read
89 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
90
91 // Get the file size, and validate our offset
92 s64 file_size = 0;
93 R_TRY(this->DoGetSize(std::addressof(file_size)));
94 R_UNLESS(offset <= file_size, ResultOutOfRange);
95
96 *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
97 R_SUCCEED();
98 }
99
100 Result DrySetSize(s64 size, OpenMode open_mode) {
101 // Check that we can write
102 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
103 R_SUCCEED();
104 }
105
106 Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
107 OpenMode open_mode) {
108 // Check that we can write
109 R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
110
111 // Get the file size
112 s64 file_size = 0;
113 R_TRY(this->DoGetSize(&file_size));
114
115 // Determine if we need to append
116 *out_append = false;
117 if (file_size < offset + static_cast<s64>(size)) {
118 R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
119 ResultFileExtensionWithoutOpenModeAllowAppend);
120 *out_append = true;
121 }
122
123 R_SUCCEED();
124 }
125
126private:
127 Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
128 const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
129 *out = read_size;
130
131 R_SUCCEED();
132 }
133
134 Result DoGetSize(s64* out) {
135 *out = backend->GetSize();
136 R_SUCCEED();
137 }
138
139 Result DoFlush() {
140 // Exists for SDK compatibiltity -- No need to flush file.
141 R_SUCCEED();
142 }
143
144 Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
145 const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
146
147 ASSERT_MSG(written == size,
148 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
149 written);
150
151 R_SUCCEED();
152 }
153
154 Result DoSetSize(s64 size) {
155 backend->Resize(size);
156 R_SUCCEED();
157 }
158
159 Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
160 const void* src, size_t src_size) {
161 R_THROW(ResultNotImplemented);
162 }
163
164 VirtualFile backend;
165};
166
167} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fsa/fs_i_filesystem.h b/src/core/file_sys/fsa/fs_i_filesystem.h
new file mode 100644
index 000000000..8172190f4
--- /dev/null
+++ b/src/core/file_sys/fsa/fs_i_filesystem.h
@@ -0,0 +1,206 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/errors.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fs_path.h"
9#include "core/file_sys/vfs/vfs_types.h"
10#include "core/hle/result.h"
11#include "core/hle/service/filesystem/filesystem.h"
12
13namespace FileSys::Fsa {
14
15class IFile;
16class IDirectory;
17
18enum class QueryId : u32 {
19 SetConcatenationFileAttribute = 0,
20 UpdateMac = 1,
21 IsSignedSystemPartitionOnSdCardValid = 2,
22 QueryUnpreparedFileInformation = 3,
23};
24
25class IFileSystem {
26public:
27 explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
28 virtual ~IFileSystem() {}
29
30 Result CreateFile(const Path& path, s64 size, CreateOption option) {
31 R_UNLESS(size >= 0, ResultOutOfRange);
32 R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
33 }
34
35 Result CreateFile(const Path& path, s64 size) {
36 R_RETURN(this->CreateFile(path, size, CreateOption::None));
37 }
38
39 Result DeleteFile(const Path& path) {
40 R_RETURN(this->DoDeleteFile(path));
41 }
42
43 Result CreateDirectory(const Path& path) {
44 R_RETURN(this->DoCreateDirectory(path));
45 }
46
47 Result DeleteDirectory(const Path& path) {
48 R_RETURN(this->DoDeleteDirectory(path));
49 }
50
51 Result DeleteDirectoryRecursively(const Path& path) {
52 R_RETURN(this->DoDeleteDirectoryRecursively(path));
53 }
54
55 Result RenameFile(const Path& old_path, const Path& new_path) {
56 R_RETURN(this->DoRenameFile(old_path, new_path));
57 }
58
59 Result RenameDirectory(const Path& old_path, const Path& new_path) {
60 R_RETURN(this->DoRenameDirectory(old_path, new_path));
61 }
62
63 Result GetEntryType(DirectoryEntryType* out, const Path& path) {
64 R_RETURN(this->DoGetEntryType(out, path));
65 }
66
67 Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
68 R_UNLESS(out_file != nullptr, ResultNullptrArgument);
69 R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
70 R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
71 R_RETURN(this->DoOpenFile(out_file, path, mode));
72 }
73
74 Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
75 R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
76 R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
77 R_UNLESS(static_cast<u64>(
78 mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
79 ResultInvalidOpenMode);
80 R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
81 }
82
83 Result Commit() {
84 R_RETURN(this->DoCommit());
85 }
86
87 Result GetFreeSpaceSize(s64* out, const Path& path) {
88 R_UNLESS(out != nullptr, ResultNullptrArgument);
89 R_RETURN(this->DoGetFreeSpaceSize(out, path));
90 }
91
92 Result GetTotalSpaceSize(s64* out, const Path& path) {
93 R_UNLESS(out != nullptr, ResultNullptrArgument);
94 R_RETURN(this->DoGetTotalSpaceSize(out, path));
95 }
96
97 Result CleanDirectoryRecursively(const Path& path) {
98 R_RETURN(this->DoCleanDirectoryRecursively(path));
99 }
100
101 Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
102 R_UNLESS(out != nullptr, ResultNullptrArgument);
103 R_RETURN(this->DoGetFileTimeStampRaw(out, path));
104 }
105
106 Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
107 const Path& path) {
108 R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
109 }
110
111 // These aren't accessible as commands
112 Result CommitProvisionally(s64 counter) {
113 R_RETURN(this->DoCommitProvisionally(counter));
114 }
115
116 Result Rollback() {
117 R_RETURN(this->DoRollback());
118 }
119
120 Result Flush() {
121 R_RETURN(this->DoFlush());
122 }
123
124private:
125 Result DoCreateFile(const Path& path, s64 size, int flags) {
126 R_RETURN(backend.CreateFile(path.GetString(), size));
127 }
128
129 Result DoDeleteFile(const Path& path) {
130 R_RETURN(backend.DeleteFile(path.GetString()));
131 }
132
133 Result DoCreateDirectory(const Path& path) {
134 R_RETURN(backend.CreateDirectory(path.GetString()));
135 }
136
137 Result DoDeleteDirectory(const Path& path) {
138 R_RETURN(backend.DeleteDirectory(path.GetString()));
139 }
140
141 Result DoDeleteDirectoryRecursively(const Path& path) {
142 R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
143 }
144
145 Result DoRenameFile(const Path& old_path, const Path& new_path) {
146 R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
147 }
148
149 Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
150 R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
151 }
152
153 Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
154 R_RETURN(backend.GetEntryType(out, path.GetString()));
155 }
156
157 Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
158 R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
159 }
160
161 Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
162 R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
163 }
164
165 Result DoCommit() {
166 R_THROW(ResultNotImplemented);
167 }
168
169 Result DoGetFreeSpaceSize(s64* out, const Path& path) {
170 R_THROW(ResultNotImplemented);
171 }
172
173 Result DoGetTotalSpaceSize(s64* out, const Path& path) {
174 R_THROW(ResultNotImplemented);
175 }
176
177 Result DoCleanDirectoryRecursively(const Path& path) {
178 R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
179 }
180
181 Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
182 R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
183 }
184
185 Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
186 const Path& path) {
187 R_THROW(ResultNotImplemented);
188 }
189
190 // These aren't accessible as commands
191 Result DoCommitProvisionally(s64 counter) {
192 R_THROW(ResultNotImplemented);
193 }
194
195 Result DoRollback() {
196 R_THROW(ResultNotImplemented);
197 }
198
199 Result DoFlush() {
200 R_THROW(ResultNotImplemented);
201 }
202
203 Service::FileSystem::VfsDirectoryServiceWrapper backend;
204};
205
206} // namespace FileSys::Fsa
diff --git a/src/core/file_sys/fssrv/fssrv_sf_path.h b/src/core/file_sys/fssrv/fssrv_sf_path.h
new file mode 100644
index 000000000..a0c0b2dac
--- /dev/null
+++ b/src/core/file_sys/fssrv/fssrv_sf_path.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/fs_directory.h"
7
8namespace FileSys::Sf {
9
10struct Path {
11 char str[EntryNameLengthMax + 1];
12
13 static constexpr Path Encode(const char* p) {
14 Path path = {};
15 for (size_t i = 0; i < sizeof(path) - 1; i++) {
16 path.str[i] = p[i];
17 if (p[i] == '\x00') {
18 break;
19 }
20 }
21 return path;
22 }
23
24 static constexpr size_t GetPathLength(const Path& path) {
25 size_t len = 0;
26 for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
27 len++;
28 }
29 return len;
30 }
31};
32static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
33
34using FspPath = Path;
35
36} // namespace FileSys::Sf
diff --git a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
index f342efb57..0e83ca1b9 100644
--- a/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
+++ b/src/core/file_sys/fssystem/fssystem_aes_xts_storage.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <mutex>
6#include <optional> 7#include <optional>
7 8
8#include "core/crypto/aes_util.h" 9#include "core/crypto/aes_util.h"
diff --git a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
index caea0b8f8..a68fd973c 100644
--- a/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
+++ b/src/core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
@@ -36,7 +36,9 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay
36 // Get the base storage size. 36 // Get the base storage size.
37 m_base_storage_size = base_storages[2]->GetSize(); 37 m_base_storage_size = base_storages[2]->GetSize();
38 { 38 {
39 auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; }); 39 auto size_guard = SCOPE_GUARD {
40 m_base_storage_size = 0;
41 };
40 R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize) 42 R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
41 << m_log_size_ratio << m_log_size_ratio, 43 << m_log_size_ratio << m_log_size_ratio,
42 ResultHierarchicalSha256BaseStorageTooLarge); 44 ResultHierarchicalSha256BaseStorageTooLarge);
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index ae4e441c9..289969cc4 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -98,7 +98,9 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
98 98
99Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) { 99Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
100 const u64 original_program_id = aci_header.title_id; 100 const u64 original_program_id = aci_header.title_id;
101 SCOPE_EXIT({ aci_header.title_id = original_program_id; }); 101 SCOPE_EXIT {
102 aci_header.title_id = original_program_id;
103 };
102 104
103 return this->Load(file); 105 return this->Load(file);
104} 106}
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index cbf411a20..106922e04 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -14,48 +14,11 @@ namespace FileSys {
14 14
15namespace { 15namespace {
16 16
17void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
18 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
19 if (meta.zero_1 != 0) {
20 LOG_WARNING(Service_FS,
21 "Possibly incorrect SaveDataAttribute, type is "
22 "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
23 meta.zero_1);
24 }
25 if (meta.zero_2 != 0) {
26 LOG_WARNING(Service_FS,
27 "Possibly incorrect SaveDataAttribute, type is "
28 "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
29 meta.zero_2);
30 }
31 if (meta.zero_3 != 0) {
32 LOG_WARNING(Service_FS,
33 "Possibly incorrect SaveDataAttribute, type is "
34 "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
35 meta.zero_3);
36 }
37 }
38
39 if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
40 LOG_WARNING(Service_FS,
41 "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
42 "non-zero ({:016X}).",
43 meta.title_id);
44 }
45
46 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
47 LOG_WARNING(Service_FS,
48 "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
49 "non-zero ({:016X}{:016X})",
50 meta.user_id[1], meta.user_id[0]);
51 }
52}
53
54bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) { 17bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
55 return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage || 18 return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
56 (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User 19 (space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
57 (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) && 20 (attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
58 attr.title_id == 0 && attr.save_id == 0); 21 attr.program_id == 0 && attr.system_save_data_id == 0);
59} 22}
60 23
61std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id, 24std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
63 // Only detect nand user saves. 26 // Only detect nand user saves.
64 const auto space_id_path = [space_id]() -> std::string_view { 27 const auto space_id_path = [space_id]() -> std::string_view {
65 switch (space_id) { 28 switch (space_id) {
66 case SaveDataSpaceId::NandUser: 29 case SaveDataSpaceId::User:
67 return "/user/save"; 30 return "/user/save";
68 default: 31 default:
69 return ""; 32 return "";
@@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
79 42
80 // Only detect account/device saves from the future location. 43 // Only detect account/device saves from the future location.
81 switch (type) { 44 switch (type) {
82 case SaveDataType::SaveData: 45 case SaveDataType::Account:
83 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id); 46 return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
84 case SaveDataType::DeviceSaveData: 47 case SaveDataType::Device:
85 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id); 48 return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
86 default: 49 default:
87 return ""; 50 return "";
@@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
90 53
91} // Anonymous namespace 54} // Anonymous namespace
92 55
93std::string SaveDataAttribute::DebugInfo() const {
94 return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
95 "rank={}, index={}]",
96 title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
97 static_cast<u8>(rank), index);
98}
99
100SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_, 56SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
101 VirtualDir save_directory_) 57 VirtualDir save_directory_)
102 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} { 58 : system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
108SaveDataFactory::~SaveDataFactory() = default; 64SaveDataFactory::~SaveDataFactory() = default;
109 65
110VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 66VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
111 PrintSaveDataAttributeWarnings(meta); 67 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
112 68 meta.user_id, meta.system_save_data_id);
113 const auto save_directory =
114 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
115 69
116 return dir->CreateDirectoryRelative(save_directory); 70 return dir->CreateDirectoryRelative(save_directory);
117} 71}
118 72
119VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const { 73VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
120 74
121 const auto save_directory = 75 const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
122 GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id); 76 meta.user_id, meta.system_save_data_id);
123 77
124 auto out = dir->GetDirectoryRelative(save_directory); 78 auto out = dir->GetDirectoryRelative(save_directory);
125 79
@@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
136 90
137std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) { 91std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
138 switch (space) { 92 switch (space) {
139 case SaveDataSpaceId::NandSystem: 93 case SaveDataSpaceId::System:
140 return "/system/"; 94 return "/system/";
141 case SaveDataSpaceId::NandUser: 95 case SaveDataSpaceId::User:
142 return "/user/"; 96 return "/user/";
143 case SaveDataSpaceId::TemporaryStorage: 97 case SaveDataSpaceId::Temporary:
144 return "/temp/"; 98 return "/temp/";
145 default: 99 default:
146 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 100 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
153 u128 user_id, u64 save_id) { 107 u128 user_id, u64 save_id) {
154 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 108 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
155 // be interpreted as the title id of the current process. 109 // be interpreted as the title id of the current process.
156 if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { 110 if (type == SaveDataType::Account || type == SaveDataType::Device) {
157 if (title_id == 0) { 111 if (title_id == 0) {
158 title_id = program_id; 112 title_id = program_id;
159 } 113 }
@@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
173 std::string out = GetSaveDataSpaceIdPath(space); 127 std::string out = GetSaveDataSpaceIdPath(space);
174 128
175 switch (type) { 129 switch (type) {
176 case SaveDataType::SystemSaveData: 130 case SaveDataType::System:
177 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); 131 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
178 case SaveDataType::SaveData: 132 case SaveDataType::Account:
179 case SaveDataType::DeviceSaveData: 133 case SaveDataType::Device:
180 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 134 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
181 title_id); 135 title_id);
182 case SaveDataType::TemporaryStorage: 136 case SaveDataType::Temporary:
183 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 137 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
184 title_id); 138 title_id);
185 case SaveDataType::CacheStorage: 139 case SaveDataType::Cache:
186 return fmt::format("{}save/cache/{:016X}", out, title_id); 140 return fmt::format("{}save/cache/{:016X}", out, title_id);
187 default: 141 default:
188 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); 142 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
202SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, 156SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
203 u128 user_id) const { 157 u128 user_id) const {
204 const auto path = 158 const auto path =
205 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 159 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
206 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 160 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
207 161
208 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); 162 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
221void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 175void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
222 SaveDataSize new_value) const { 176 SaveDataSize new_value) const {
223 const auto path = 177 const auto path =
224 GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 178 GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
225 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 179 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
226 180
227 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); 181 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 5ab7e4d32..15dd4ec7d 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/fs_save_data_types.h"
10#include "core/file_sys/vfs/vfs.h" 11#include "core/file_sys/vfs/vfs.h"
11#include "core/hle/result.h" 12#include "core/hle/result.h"
12 13
@@ -16,73 +17,6 @@ class System;
16 17
17namespace FileSys { 18namespace FileSys {
18 19
19enum class SaveDataSpaceId : u8 {
20 NandSystem = 0,
21 NandUser = 1,
22 SdCardSystem = 2,
23 TemporaryStorage = 3,
24 SdCardUser = 4,
25 ProperSystem = 100,
26 SafeMode = 101,
27};
28
29enum class SaveDataType : u8 {
30 SystemSaveData = 0,
31 SaveData = 1,
32 BcatDeliveryCacheStorage = 2,
33 DeviceSaveData = 3,
34 TemporaryStorage = 4,
35 CacheStorage = 5,
36 SystemBcat = 6,
37};
38
39enum class SaveDataRank : u8 {
40 Primary = 0,
41 Secondary = 1,
42};
43
44enum class SaveDataFlags : u32 {
45 None = (0 << 0),
46 KeepAfterResettingSystemSaveData = (1 << 0),
47 KeepAfterRefurbishment = (1 << 1),
48 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
49 NeedsSecureDelete = (1 << 3),
50};
51
52struct SaveDataAttribute {
53 u64 title_id;
54 u128 user_id;
55 u64 save_id;
56 SaveDataType type;
57 SaveDataRank rank;
58 u16 index;
59 INSERT_PADDING_BYTES_NOINIT(4);
60 u64 zero_1;
61 u64 zero_2;
62 u64 zero_3;
63
64 std::string DebugInfo() const;
65};
66static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
67
68struct SaveDataExtraData {
69 SaveDataAttribute attr;
70 u64 owner_id;
71 s64 timestamp;
72 SaveDataFlags flags;
73 INSERT_PADDING_BYTES_NOINIT(4);
74 s64 available_size;
75 s64 journal_size;
76 s64 commit_id;
77 std::array<u8, 0x190> unused;
78};
79static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
80
81struct SaveDataSize {
82 u64 normal;
83 u64 journal;
84};
85
86constexpr const char* GetSaveDataSizeFileName() { 20constexpr const char* GetSaveDataSizeFileName() {
87 return ".yuzu_save_size"; 21 return ".yuzu_save_size";
88} 22}
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index 472e8571c..3e01e3b67 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -24,7 +24,9 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
24 // Create a session request. 24 // Create a session request.
25 KSessionRequest* request = KSessionRequest::Create(m_kernel); 25 KSessionRequest* request = KSessionRequest::Create(m_kernel);
26 R_UNLESS(request != nullptr, ResultOutOfResource); 26 R_UNLESS(request != nullptr, ResultOutOfResource);
27 SCOPE_EXIT({ request->Close(); }); 27 SCOPE_EXIT {
28 request->Close();
29 };
28 30
29 // Initialize the request. 31 // Initialize the request.
30 request->Initialize(nullptr, address, size); 32 request->Initialize(nullptr, address, size);
@@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
37 // Create a session request. 39 // Create a session request.
38 KSessionRequest* request = KSessionRequest::Create(m_kernel); 40 KSessionRequest* request = KSessionRequest::Create(m_kernel);
39 R_UNLESS(request != nullptr, ResultOutOfResource); 41 R_UNLESS(request != nullptr, ResultOutOfResource);
40 SCOPE_EXIT({ request->Close(); }); 42 SCOPE_EXIT {
43 request->Close();
44 };
41 45
42 // Initialize the request. 46 // Initialize the request.
43 request->Initialize(event, address, size); 47 request->Initialize(event, address, size);
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 1dd86fb3c..19cdf4f3a 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
1305 1305
1306 // Ensure that we maintain the instruction cache. 1306 // Ensure that we maintain the instruction cache.
1307 bool reprotected_pages = false; 1307 bool reprotected_pages = false;
1308 SCOPE_EXIT({ 1308 SCOPE_EXIT {
1309 if (reprotected_pages && any_code_pages) { 1309 if (reprotected_pages && any_code_pages) {
1310 InvalidateInstructionCache(m_kernel, this, dst_address, size); 1310 InvalidateInstructionCache(m_kernel, this, dst_address, size);
1311 } 1311 }
1312 }); 1312 };
1313 1313
1314 // Unmap. 1314 // Unmap.
1315 { 1315 {
@@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
1397 // Close the opened pages when we're done with them. 1397 // Close the opened pages when we're done with them.
1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
1399 // automatically. 1399 // automatically.
1400 SCOPE_EXIT({ pg.Close(); }); 1400 SCOPE_EXIT {
1401 pg.Close();
1402 };
1401 1403
1402 // Clear all the newly allocated pages. 1404 // Clear all the newly allocated pages.
1403 for (const auto& it : pg) { 1405 for (const auto& it : pg) {
@@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
1603 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); 1605 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
1604 1606
1605 // Ensure that the page group is closed when we're done working with it. 1607 // Ensure that the page group is closed when we're done working with it.
1606 SCOPE_EXIT({ pg.Close(); }); 1608 SCOPE_EXIT {
1609 pg.Close();
1610 };
1607 1611
1608 // Clear all pages. 1612 // Clear all pages.
1609 for (const auto& it : pg) { 1613 for (const auto& it : pg) {
@@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
2191 // Close the opened pages when we're done with them. 2195 // Close the opened pages when we're done with them.
2192 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 2196 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
2193 // automatically. 2197 // automatically.
2194 SCOPE_EXIT({ pg.Close(); }); 2198 SCOPE_EXIT {
2199 pg.Close();
2200 };
2195 2201
2196 // Clear all the newly allocated pages. 2202 // Clear all the newly allocated pages.
2197 for (const auto& it : pg) { 2203 for (const auto& it : pg) {
@@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
2592 // Temporarily unlock ourselves, so that other operations can occur while we flush the 2598 // Temporarily unlock ourselves, so that other operations can occur while we flush the
2593 // region. 2599 // region.
2594 m_general_lock.Unlock(); 2600 m_general_lock.Unlock();
2595 SCOPE_EXIT({ m_general_lock.Lock(); }); 2601 SCOPE_EXIT {
2602 m_general_lock.Lock();
2603 };
2596 2604
2597 // Flush the region. 2605 // Flush the region.
2598 R_ASSERT(FlushDataCache(dst_address, size)); 2606 R_ASSERT(FlushDataCache(dst_address, size));
@@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
3311 // Ensure we unmap the io memory when we're done with it. 3319 // Ensure we unmap the io memory when we're done with it.
3312 const KPageProperties unmap_properties = 3320 const KPageProperties unmap_properties =
3313 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3321 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3314 SCOPE_EXIT({ 3322 SCOPE_EXIT {
3315 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3323 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3316 unmap_properties, OperationType::Unmap, true)); 3324 unmap_properties, OperationType::Unmap, true));
3317 }); 3325 };
3318 3326
3319 // Read the memory. 3327 // Read the memory.
3320 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3328 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
3347 // Ensure we unmap the io memory when we're done with it. 3355 // Ensure we unmap the io memory when we're done with it.
3348 const KPageProperties unmap_properties = 3356 const KPageProperties unmap_properties =
3349 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3357 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3350 SCOPE_EXIT({ 3358 SCOPE_EXIT {
3351 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3359 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3352 unmap_properties, OperationType::Unmap, true)); 3360 unmap_properties, OperationType::Unmap, true));
3353 }); 3361 };
3354 3362
3355 // Write the memory. 3363 // Write the memory.
3356 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3364 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
4491 4499
4492 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll 4500 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
4493 // free on scope exit. 4501 // free on scope exit.
4494 SCOPE_EXIT({ 4502 SCOPE_EXIT {
4495 if (start_partial_page != 0) { 4503 if (start_partial_page != 0) {
4496 m_kernel.MemoryManager().Close(start_partial_page, 1); 4504 m_kernel.MemoryManager().Close(start_partial_page, 1);
4497 } 4505 }
4498 if (end_partial_page != 0) { 4506 if (end_partial_page != 0) {
4499 m_kernel.MemoryManager().Close(end_partial_page, 1); 4507 m_kernel.MemoryManager().Close(end_partial_page, 1);
4500 } 4508 }
4501 }); 4509 };
4502 4510
4503 ON_RESULT_FAILURE { 4511 ON_RESULT_FAILURE {
4504 if (cur_mapped_addr != dst_addr) { 4512 if (cur_mapped_addr != dst_addr) {
@@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
5166 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); 5174 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
5167 5175
5168 // If we fail in the next bit (or retry), we need to cleanup the pages. 5176 // If we fail in the next bit (or retry), we need to cleanup the pages.
5169 auto pg_guard = SCOPE_GUARD({ 5177 auto pg_guard = SCOPE_GUARD {
5170 pg.OpenFirst(); 5178 pg.OpenFirst();
5171 pg.Close(); 5179 pg.Close();
5172 }); 5180 };
5173 5181
5174 // Map the memory. 5182 // Map the memory.
5175 { 5183 {
@@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
5694 5702
5695 // Ensure that any pages we track are closed on exit. 5703 // Ensure that any pages we track are closed on exit.
5696 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); 5704 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
5697 SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); 5705 SCOPE_EXIT {
5706 pages_to_close.CloseAndReset();
5707 };
5698 5708
5699 // Make a page group representing the region to unmap. 5709 // Make a page group representing the region to unmap.
5700 this->MakePageGroup(pages_to_close, virt_addr, num_pages); 5710 this->MakePageGroup(pages_to_close, virt_addr, num_pages);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 1bcc42890..cb9a11a63 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -77,7 +77,9 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process,
77 } 77 }
78 78
79 // Terminate and close the thread. 79 // Terminate and close the thread.
80 SCOPE_EXIT({ cur_child->Close(); }); 80 SCOPE_EXIT {
81 cur_child->Close();
82 };
81 83
82 if (const Result terminate_result = cur_child->Terminate(); 84 if (const Result terminate_result = cur_child->Terminate();
83 ResultTerminationRequested == terminate_result) { 85 ResultTerminationRequested == terminate_result) {
@@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() {
466 468
467Result KProcess::StartTermination() { 469Result KProcess::StartTermination() {
468 // Finalize the handle table when we're done, if the process isn't immortal. 470 // Finalize the handle table when we're done, if the process isn't immortal.
469 SCOPE_EXIT({ 471 SCOPE_EXIT {
470 if (!m_is_immortal) { 472 if (!m_is_immortal) {
471 this->FinalizeHandleTable(); 473 this->FinalizeHandleTable();
472 } 474 }
473 }); 475 };
474 476
475 // Terminate child threads other than the current one. 477 // Terminate child threads other than the current one.
476 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel))); 478 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
@@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
964 // Create a new thread for the process. 966 // Create a new thread for the process.
965 KThread* main_thread = KThread::Create(m_kernel); 967 KThread* main_thread = KThread::Create(m_kernel);
966 R_UNLESS(main_thread != nullptr, ResultOutOfResource); 968 R_UNLESS(main_thread != nullptr, ResultOutOfResource);
967 SCOPE_EXIT({ main_thread->Close(); }); 969 SCOPE_EXIT {
970 main_thread->Close();
971 };
968 972
969 // Initialize the thread. 973 // Initialize the thread.
970 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0, 974 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
@@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
1155 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); 1159 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
1156 1160
1157 // Ensure we maintain a clean state on exit. 1161 // Ensure we maintain a clean state on exit.
1158 SCOPE_EXIT({ res_limit->Close(); }); 1162 SCOPE_EXIT {
1163 res_limit->Close();
1164 };
1159 1165
1160 // Declare flags and code address. 1166 // Declare flags and code address.
1161 Svc::CreateProcessFlag flag{}; 1167 Svc::CreateProcessFlag flag{};
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index adaabdd6d..40c3323ef 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
651 // Process any special data. 651 // Process any special data.
652 if (src_header.GetHasSpecialHeader()) { 652 if (src_header.GetHasSpecialHeader()) {
653 // After we process, make sure we track whether the receive list is broken. 653 // After we process, make sure we track whether the receive list is broken.
654 SCOPE_EXIT({ 654 SCOPE_EXIT {
655 if (offset > dst_recv_list_idx) { 655 if (offset > dst_recv_list_idx) {
656 recv_list_broken = true; 656 recv_list_broken = true;
657 } 657 }
658 }); 658 };
659 659
660 // Process special data. 660 // Process special data.
661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, 661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread,
@@ -665,11 +665,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
665 // Process any pointer buffers. 665 // Process any pointer buffers.
666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) { 666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
667 // After we process, make sure we track whether the receive list is broken. 667 // After we process, make sure we track whether the receive list is broken.
668 SCOPE_EXIT({ 668 SCOPE_EXIT {
669 if (offset > dst_recv_list_idx) { 669 if (offset > dst_recv_list_idx) {
670 recv_list_broken = true; 670 recv_list_broken = true;
671 } 671 }
672 }); 672 };
673 673
674 R_TRY(ProcessReceiveMessagePointerDescriptors( 674 R_TRY(ProcessReceiveMessagePointerDescriptors(
675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, 675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list,
@@ -680,11 +680,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
680 // Process any map alias buffers. 680 // Process any map alias buffers.
681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { 681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
682 // After we process, make sure we track whether the receive list is broken. 682 // After we process, make sure we track whether the receive list is broken.
683 SCOPE_EXIT({ 683 SCOPE_EXIT {
684 if (offset > dst_recv_list_idx) { 684 if (offset > dst_recv_list_idx) {
685 recv_list_broken = true; 685 recv_list_broken = true;
686 } 686 }
687 }); 687 };
688 688
689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. 689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
690 const KMemoryPermission perm = (i >= src_header.GetSendCount()) 690 const KMemoryPermission perm = (i >= src_header.GetSendCount())
@@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
702 // Process any raw data. 702 // Process any raw data.
703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { 703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
704 // After we process, make sure we track whether the receive list is broken. 704 // After we process, make sure we track whether the receive list is broken.
705 SCOPE_EXIT({ 705 SCOPE_EXIT {
706 if (offset + raw_count > dst_recv_list_idx) { 706 if (offset + raw_count > dst_recv_list_idx) {
707 recv_list_broken = true; 707 recv_list_broken = true;
708 } 708 }
709 }); 709 };
710 710
711 // Get the offset and size. 711 // Get the offset and size.
712 const size_t offset_words = offset * sizeof(u32); 712 const size_t offset_words = offset * sizeof(u32);
@@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1124 client_thread->Open(); 1124 client_thread->Open();
1125 } 1125 }
1126 1126
1127 SCOPE_EXIT({ client_thread->Close(); }); 1127 SCOPE_EXIT {
1128 client_thread->Close();
1129 };
1128 1130
1129 // Set the request as our current. 1131 // Set the request as our current.
1130 m_current_request = request; 1132 m_current_request = request;
@@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1174 // Reply to the client. 1176 // Reply to the client.
1175 { 1177 {
1176 // After we reply, close our reference to the request. 1178 // After we reply, close our reference to the request.
1177 SCOPE_EXIT({ request->Close(); }); 1179 SCOPE_EXIT {
1180 request->Close();
1181 };
1178 1182
1179 // Get the event to check whether the request is async. 1183 // Get the event to check whether the request is async.
1180 if (KEvent* event = request->GetEvent(); event != nullptr) { 1184 if (KEvent* event = request->GetEvent(); event != nullptr) {
@@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
1236 } 1240 }
1237 1241
1238 // Close reference to the request once we're done processing it. 1242 // Close reference to the request once we're done processing it.
1239 SCOPE_EXIT({ request->Close(); }); 1243 SCOPE_EXIT {
1244 request->Close();
1245 };
1240 1246
1241 // Extract relevant information from the request. 1247 // Extract relevant information from the request.
1242 const uint64_t client_message = request->GetAddress(); 1248 const uint64_t client_message = request->GetAddress();
@@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() {
1394 } 1400 }
1395 1401
1396 // Close a reference to the request once it's cleaned up. 1402 // Close a reference to the request once it's cleaned up.
1397 SCOPE_EXIT({ request->Close(); }); 1403 SCOPE_EXIT {
1404 request->Close();
1405 };
1398 1406
1399 // Extract relevant information from the request. 1407 // Extract relevant information from the request.
1400 const uint64_t client_message = request->GetAddress(); 1408 const uint64_t client_message = request->GetAddress();
@@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() {
1491 ASSERT(thread != nullptr); 1499 ASSERT(thread != nullptr);
1492 1500
1493 // Ensure that we close the request when done. 1501 // Ensure that we close the request when done.
1494 SCOPE_EXIT({ request->Close(); }); 1502 SCOPE_EXIT {
1503 request->Close();
1504 };
1495 1505
1496 // If we're terminating, close a reference to the thread and event. 1506 // If we're terminating, close a reference to the thread and event.
1497 if (terminate) { 1507 if (terminate) {
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
index a632d1634..1952c0083 100644
--- a/src/core/hle/kernel/k_thread_local_page.cpp
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -21,7 +21,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
21 // Allocate a new page. 21 // Allocate a new page.
22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel); 22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory); 23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
24 auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); }); 24 auto page_buf_guard = SCOPE_GUARD {
25 KPageBuffer::Free(kernel, page_buf);
26 };
25 27
26 // Map the address in. 28 // Map the address in.
27 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); 29 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index cbb1b02bb..09295e8ad 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -24,7 +24,9 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
24 24
25 // Construct the page group, guarding to make sure our state is valid on exit. 25 // Construct the page group, guarding to make sure our state is valid on exit.
26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); 26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
27 auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); }); 27 auto pg_guard = SCOPE_GUARD {
28 m_page_group.reset();
29 };
28 30
29 // Lock the memory. 31 // Lock the memory.
30 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size, 32 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f4b02fac..9e5eaeec4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -109,7 +109,9 @@ struct KernelCore::Impl {
109 109
110 void Shutdown() { 110 void Shutdown() {
111 is_shutting_down.store(true, std::memory_order_relaxed); 111 is_shutting_down.store(true, std::memory_order_relaxed);
112 SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); 112 SCOPE_EXIT {
113 is_shutting_down.store(false, std::memory_order_relaxed);
114 };
113 115
114 CloseServices(); 116 CloseServices();
115 117
@@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
1080 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1082 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1081 1083
1082 // Ensure that we don't hold onto any extra references. 1084 // Ensure that we don't hold onto any extra references.
1083 SCOPE_EXIT({ process->Close(); }); 1085 SCOPE_EXIT {
1086 process->Close();
1087 };
1084 1088
1085 // Register the new process. 1089 // Register the new process.
1086 KProcess::Register(*this, process); 1090 KProcess::Register(*this, process);
@@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1108 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1112 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1109 1113
1110 // Ensure that we don't hold onto any extra references. 1114 // Ensure that we don't hold onto any extra references.
1111 SCOPE_EXIT({ process->Close(); }); 1115 SCOPE_EXIT {
1116 process->Close();
1117 };
1112 1118
1113 // Register the new process. 1119 // Register the new process.
1114 KProcess::Register(*this, process); 1120 KProcess::Register(*this, process);
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp
index bae4cb0cd..7be2802f0 100644
--- a/src/core/hle/kernel/svc/svc_code_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_code_memory.cpp
@@ -45,7 +45,9 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
45 45
46 KCodeMemory* code_mem = KCodeMemory::Create(kernel); 46 KCodeMemory* code_mem = KCodeMemory::Create(kernel);
47 R_UNLESS(code_mem != nullptr, ResultOutOfResource); 47 R_UNLESS(code_mem != nullptr, ResultOutOfResource);
48 SCOPE_EXIT({ code_mem->Close(); }); 48 SCOPE_EXIT {
49 code_mem->Close();
50 };
49 51
50 // Verify that the region is in range. 52 // Verify that the region is in range.
51 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), 53 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp
index 42add9473..ac828320f 100644
--- a/src/core/hle/kernel/svc/svc_device_address_space.cpp
+++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp
@@ -28,7 +28,9 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_
28 // Create the device address space. 28 // Create the device address space.
29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); 29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
30 R_UNLESS(das != nullptr, ResultOutOfResource); 30 R_UNLESS(das != nullptr, ResultOutOfResource);
31 SCOPE_EXIT({ das->Close(); }); 31 SCOPE_EXIT {
32 das->Close();
33 };
32 34
33 // Initialize the device address space. 35 // Initialize the device address space.
34 R_TRY(das->Initialize(das_address, das_size)); 36 R_TRY(das->Initialize(das_address, das_size));
diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp
index 901202e6a..8e4beb396 100644
--- a/src/core/hle/kernel/svc/svc_event.cpp
+++ b/src/core/hle/kernel/svc/svc_event.cpp
@@ -72,10 +72,10 @@ Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
72 event_reservation.Commit(); 72 event_reservation.Commit();
73 73
74 // Ensure that we clean up the event (and its only references are handle table) on function end. 74 // Ensure that we clean up the event (and its only references are handle table) on function end.
75 SCOPE_EXIT({ 75 SCOPE_EXIT {
76 event->GetReadableEvent().Close(); 76 event->GetReadableEvent().Close();
77 event->Close(); 77 event->Close();
78 }); 78 };
79 79
80 // Register the event. 80 // Register the event.
81 KEvent::Register(kernel, event); 81 KEvent::Register(kernel, event);
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index 85cc4f561..b619bd70a 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -129,11 +129,11 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
129 } 129 }
130 130
131 // Ensure handles are closed when we're done. 131 // Ensure handles are closed when we're done.
132 SCOPE_EXIT({ 132 SCOPE_EXIT {
133 for (auto i = 0; i < num_handles; ++i) { 133 for (auto i = 0; i < num_handles; ++i) {
134 objs[i]->Close(); 134 objs[i]->Close();
135 } 135 }
136 }); 136 };
137 137
138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, 138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
139 num_handles, reply_target, timeout_ns)); 139 num_handles, reply_target, timeout_ns));
@@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
208 event_reservation.Commit(); 208 event_reservation.Commit();
209 209
210 // At end of scope, kill the standing references to the sub events. 210 // At end of scope, kill the standing references to the sub events.
211 SCOPE_EXIT({ 211 SCOPE_EXIT {
212 event->GetReadableEvent().Close(); 212 event->GetReadableEvent().Close();
213 event->Close(); 213 event->Close();
214 }); 214 };
215 215
216 // Register the event. 216 // Register the event.
217 KEvent::Register(system.Kernel(), event); 217 KEvent::Register(system.Kernel(), event);
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 737749f7d..9a22dadaf 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -68,10 +68,10 @@ Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
68 port->Initialize(max_sessions, is_light, name); 68 port->Initialize(max_sessions, is_light, name);
69 69
70 // Ensure that we clean up the port (and its only references are handle table) on function end. 70 // Ensure that we clean up the port (and its only references are handle table) on function end.
71 SCOPE_EXIT({ 71 SCOPE_EXIT {
72 port->GetServerPort().Close(); 72 port->GetServerPort().Close();
73 port->GetClientPort().Close(); 73 port->GetClientPort().Close();
74 }); 74 };
75 75
76 // Register the port. 76 // Register the port.
77 KPort::Register(kernel, port); 77 KPort::Register(kernel, port);
@@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t
150 KPort::Register(system.Kernel(), port); 150 KPort::Register(system.Kernel(), port);
151 151
152 // Ensure that our only reference to the port is in the handle table when we're done. 152 // Ensure that our only reference to the port is in the handle table when we're done.
153 SCOPE_EXIT({ 153 SCOPE_EXIT {
154 port->GetClientPort().Close(); 154 port->GetClientPort().Close();
155 port->GetServerPort().Close(); 155 port->GetServerPort().Close();
156 }); 156 };
157 157
158 // Register the handle in the table. 158 // Register the handle in the table.
159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); 159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp
index c8e820b6a..6f3972482 100644
--- a/src/core/hle/kernel/svc/svc_resource_limit.cpp
+++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp
@@ -18,7 +18,9 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource); 18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
19 19
20 // Ensure we don't leak a reference to the limit. 20 // Ensure we don't leak a reference to the limit.
21 SCOPE_EXIT({ resource_limit->Close(); }); 21 SCOPE_EXIT {
22 resource_limit->Close();
23 };
22 24
23 // Initialize the resource limit. 25 // Initialize the resource limit.
24 resource_limit->Initialize(); 26 resource_limit->Initialize();
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp
index 2f5905f32..b034d21d1 100644
--- a/src/core/hle/kernel/svc/svc_session.cpp
+++ b/src/core/hle/kernel/svc/svc_session.cpp
@@ -69,10 +69,10 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
69 69
70 // Ensure that we clean up the session (and its only references are handle table) on function 70 // Ensure that we clean up the session (and its only references are handle table) on function
71 // end. 71 // end.
72 SCOPE_EXIT({ 72 SCOPE_EXIT {
73 session->GetClientSession().Close(); 73 session->GetClientSession().Close();
74 session->GetServerSession().Close(); 74 session->GetServerSession().Close();
75 }); 75 };
76 76
77 // Register the session. 77 // Register the session.
78 T::Register(system.Kernel(), session); 78 T::Register(system.Kernel(), session);
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
index 6c79cfd8d..fb03908d7 100644
--- a/src/core/hle/kernel/svc/svc_synchronization.cpp
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -78,11 +78,11 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
78 } 78 }
79 79
80 // Ensure handles are closed when we're done. 80 // Ensure handles are closed when we're done.
81 SCOPE_EXIT({ 81 SCOPE_EXIT {
82 for (auto i = 0; i < num_handles; ++i) { 82 for (auto i = 0; i < num_handles; ++i) {
83 objs[i]->Close(); 83 objs[i]->Close();
84 } 84 }
85 }); 85 };
86 86
87 // Convert the timeout from nanoseconds to ticks. 87 // Convert the timeout from nanoseconds to ticks.
88 s64 timeout; 88 s64 timeout;
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index 7681afa33..7517bb9d3 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -51,7 +51,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
51 // Create the thread. 51 // Create the thread.
52 KThread* thread = KThread::Create(kernel); 52 KThread* thread = KThread::Create(kernel);
53 R_UNLESS(thread != nullptr, ResultOutOfResource) 53 R_UNLESS(thread != nullptr, ResultOutOfResource)
54 SCOPE_EXIT({ thread->Close(); }); 54 SCOPE_EXIT {
55 thread->Close();
56 };
55 57
56 // Initialize the thread. 58 // Initialize the thread.
57 { 59 {
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 671bca23f..2ea0d4421 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -52,7 +52,9 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
52 R_UNLESS(trmem != nullptr, ResultOutOfResource); 52 R_UNLESS(trmem != nullptr, ResultOutOfResource);
53 53
54 // Ensure the only reference is in the handle table when we're done. 54 // Ensure the only reference is in the handle table when we're done.
55 SCOPE_EXIT({ trmem->Close(); }); 55 SCOPE_EXIT {
56 trmem->Close();
57 };
56 58
57 // Ensure that the region is in range. 59 // Ensure that the region is in range.
58 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); 60 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp
index 4d58c4db5..9057244a9 100644
--- a/src/core/hle/service/am/applet_data_broker.cpp
+++ b/src/core/hle/service/am/applet_data_broker.cpp
@@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { 24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
25 std::scoped_lock lk{m_lock}; 25 std::scoped_lock lk{m_lock};
26 26
27 SCOPE_EXIT({ 27 SCOPE_EXIT {
28 if (m_data.empty()) { 28 if (m_data.empty()) {
29 m_event.Clear(); 29 m_event.Clear();
30 } 30 }
31 }); 31 };
32 32
33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); 33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
34 34
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
index 992c50713..388d2045c 100644
--- a/src/core/hle/service/am/process.cpp
+++ b/src/core/hle/service/am/process.cpp
@@ -68,7 +68,9 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
68 Kernel::KProcess::Register(m_system.Kernel(), process); 68 Kernel::KProcess::Register(m_system.Kernel(), process);
69 69
70 // On exit, ensure we free the additional reference to the process. 70 // On exit, ensure we free the additional reference to the process.
71 SCOPE_EXIT({ process->Close(); }); 71 SCOPE_EXIT {
72 process->Close();
73 };
72 74
73 // Insert process modules into memory. 75 // Insert process modules into memory.
74 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); 76 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index cb53b07e0..bfccb6b09 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString()); 123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
124 124
125 FileSys::SaveDataAttribute attribute{}; 125 FileSys::SaveDataAttribute attribute{};
126 attribute.title_id = m_applet->program_id; 126 attribute.program_id = m_applet->program_id;
127 attribute.user_id = user_id.AsU128(); 127 attribute.user_id = user_id.AsU128();
128 attribute.type = FileSys::SaveDataType::SaveData; 128 attribute.type = FileSys::SaveDataType::Account;
129 129
130 FileSys::VirtualDir save_data{}; 130 FileSys::VirtualDir save_data{};
131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( 131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
132 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute)); 132 &save_data, FileSys::SaveDataSpaceId::User, attribute));
133 133
134 *out_size = 0; 134 *out_size = 0;
135 R_SUCCEED(); 135 R_SUCCEED();
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
deleted file mode 100644
index de2aa6906..000000000
--- a/src/core/hle/service/audio/audin_u.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/in/audio_in_system.h"
5#include "audio_core/renderer/audio_device.h"
6#include "common/common_funcs.h"
7#include "common/logging/log.h"
8#include "common/scratch_buffer.h"
9#include "common/string_util.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/service/audio/audin_u.h"
13#include "core/hle/service/ipc_helpers.h"
14
15namespace Service::Audio {
16using namespace AudioCore::AudioIn;
17
18class IAudioIn final : public ServiceFramework<IAudioIn> {
19public:
20 explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
21 const std::string& device_name, const AudioInParameter& in_params,
22 Kernel::KProcess* handle, u64 applet_resource_user_id)
23 : ServiceFramework{system_, "IAudioIn"},
24 service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
25 process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
29 {1, &IAudioIn::Start, "Start"},
30 {2, &IAudioIn::Stop, "Stop"},
31 {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
32 {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
33 {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
34 {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
35 {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
36 {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
37 {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
38 {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
39 {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
40 {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
41 {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
42 {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47
48 process->Open();
49
50 if (impl->GetSystem()
51 .Initialize(device_name, in_params, handle, applet_resource_user_id)
52 .IsError()) {
53 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
54 }
55 }
56
57 ~IAudioIn() override {
58 impl->Free();
59 service_context.CloseEvent(event);
60 process->Close();
61 }
62
63 [[nodiscard]] std::shared_ptr<In> GetImpl() {
64 return impl;
65 }
66
67private:
68 void GetAudioInState(HLERequestContext& ctx) {
69 const auto state = static_cast<u32>(impl->GetState());
70
71 LOG_DEBUG(Service_Audio, "called. State={}", state);
72
73 IPC::ResponseBuilder rb{ctx, 3};
74 rb.Push(ResultSuccess);
75 rb.Push(state);
76 }
77
78 void Start(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_Audio, "called");
80
81 auto result = impl->StartSystem();
82
83 IPC::ResponseBuilder rb{ctx, 2};
84 rb.Push(result);
85 }
86
87 void Stop(HLERequestContext& ctx) {
88 LOG_DEBUG(Service_Audio, "called");
89
90 auto result = impl->StopSystem();
91
92 IPC::ResponseBuilder rb{ctx, 2};
93 rb.Push(result);
94 }
95
96 void AppendAudioInBuffer(HLERequestContext& ctx) {
97 IPC::RequestParser rp{ctx};
98 u64 tag = rp.PopRaw<u64>();
99
100 const auto in_buffer_size{ctx.GetReadBufferSize()};
101 if (in_buffer_size < sizeof(AudioInBuffer)) {
102 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
103 }
104
105 const auto& in_buffer = ctx.ReadBuffer();
106 AudioInBuffer buffer{};
107 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
108
109 [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
111
112 auto result = impl->AppendBuffer(buffer, tag);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(result);
116 }
117
118 void RegisterBufferEvent(HLERequestContext& ctx) {
119 LOG_DEBUG(Service_Audio, "called");
120
121 auto& buffer_event = impl->GetBufferEvent();
122
123 IPC::ResponseBuilder rb{ctx, 2, 1};
124 rb.Push(ResultSuccess);
125 rb.PushCopyObjects(buffer_event);
126 }
127
128 void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
129 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
130 released_buffer.resize_destructive(write_buffer_size);
131 released_buffer[0] = 0;
132
133 const auto count = impl->GetReleasedBuffers(released_buffer);
134
135 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
136 impl->GetSystem().GetSessionId(), count);
137
138 ctx.WriteBuffer(released_buffer);
139
140 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(ResultSuccess);
142 rb.Push(count);
143 }
144
145 void ContainsAudioInBuffer(HLERequestContext& ctx) {
146 IPC::RequestParser rp{ctx};
147
148 const u64 tag{rp.Pop<u64>()};
149 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
150
151 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
152
153 IPC::ResponseBuilder rb{ctx, 3};
154 rb.Push(ResultSuccess);
155 rb.Push(buffer_queued);
156 }
157
158 void GetAudioInBufferCount(HLERequestContext& ctx) {
159 const auto buffer_count = impl->GetBufferCount();
160
161 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
162
163 IPC::ResponseBuilder rb{ctx, 3};
164 rb.Push(ResultSuccess);
165 rb.Push(buffer_count);
166 }
167
168 void SetDeviceGain(HLERequestContext& ctx) {
169 IPC::RequestParser rp{ctx};
170
171 const auto volume{rp.Pop<f32>()};
172 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
173
174 impl->SetVolume(volume);
175
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(ResultSuccess);
178 }
179
180 void GetDeviceGain(HLERequestContext& ctx) {
181 auto volume{impl->GetVolume()};
182
183 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
184
185 IPC::ResponseBuilder rb{ctx, 3};
186 rb.Push(ResultSuccess);
187 rb.Push(volume);
188 }
189
190 void FlushAudioInBuffers(HLERequestContext& ctx) {
191 bool flushed{impl->FlushAudioInBuffers()};
192
193 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
194
195 IPC::ResponseBuilder rb{ctx, 3};
196 rb.Push(ResultSuccess);
197 rb.Push(flushed);
198 }
199
200 KernelHelpers::ServiceContext service_context;
201 Kernel::KEvent* event;
202 Kernel::KProcess* process;
203 std::shared_ptr<AudioCore::AudioIn::In> impl;
204 Common::ScratchBuffer<u64> released_buffer;
205};
206
207AudInU::AudInU(Core::System& system_)
208 : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
209 impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
210 // clang-format off
211 static const FunctionInfo functions[] = {
212 {0, &AudInU::ListAudioIns, "ListAudioIns"},
213 {1, &AudInU::OpenAudioIn, "OpenAudioIn"},
214 {2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
215 {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
216 {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
217 {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
218 };
219 // clang-format on
220
221 RegisterHandlers(functions);
222}
223
224AudInU::~AudInU() = default;
225
226void AudInU::ListAudioIns(HLERequestContext& ctx) {
227 using namespace AudioCore::Renderer;
228
229 LOG_DEBUG(Service_Audio, "called");
230
231 const auto write_count =
232 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
233 std::vector<AudioDevice::AudioDeviceName> device_names{};
234
235 u32 out_count{0};
236 if (write_count > 0) {
237 out_count = impl->GetDeviceNames(device_names, write_count, false);
238 ctx.WriteBuffer(device_names);
239 }
240
241 IPC::ResponseBuilder rb{ctx, 3};
242 rb.Push(ResultSuccess);
243 rb.Push(out_count);
244}
245
246void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
247 using namespace AudioCore::Renderer;
248
249 LOG_DEBUG(Service_Audio, "called");
250
251 const auto write_count =
252 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
253 std::vector<AudioDevice::AudioDeviceName> device_names{};
254
255 u32 out_count{0};
256 if (write_count > 0) {
257 out_count = impl->GetDeviceNames(device_names, write_count, true);
258 ctx.WriteBuffer(device_names);
259 }
260
261 IPC::ResponseBuilder rb{ctx, 3};
262 rb.Push(ResultSuccess);
263 rb.Push(out_count);
264}
265
266void AudInU::OpenAudioIn(HLERequestContext& ctx) {
267 IPC::RequestParser rp{ctx};
268 auto in_params{rp.PopRaw<AudioInParameter>()};
269 auto applet_resource_user_id{rp.PopRaw<u64>()};
270 const auto device_name_data{ctx.ReadBuffer()};
271 auto device_name = Common::StringFromBuffer(device_name_data);
272 auto handle{ctx.GetCopyHandle(0)};
273
274 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
275 if (process.IsNull()) {
276 LOG_ERROR(Service_Audio, "Failed to get process handle");
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(ResultUnknown);
279 return;
280 }
281
282 std::scoped_lock l{impl->mutex};
283 auto link{impl->LinkToManager()};
284 if (link.IsError()) {
285 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
286 IPC::ResponseBuilder rb{ctx, 2};
287 rb.Push(link);
288 return;
289 }
290
291 size_t new_session_id{};
292 auto result{impl->AcquireSessionId(new_session_id)};
293 if (result.IsError()) {
294 IPC::ResponseBuilder rb{ctx, 2};
295 rb.Push(result);
296 return;
297 }
298
299 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
300 impl->num_free_sessions);
301
302 auto audio_in =
303 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
304 process.GetPointerUnsafe(), applet_resource_user_id);
305 impl->sessions[new_session_id] = audio_in->GetImpl();
306 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
307
308 auto& out_system = impl->sessions[new_session_id]->GetSystem();
309 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
310 .channel_count = out_system.GetChannelCount(),
311 .sample_format =
312 static_cast<u32>(out_system.GetSampleFormat()),
313 .state = static_cast<u32>(out_system.GetState())};
314
315 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
316
317 std::string out_name{out_system.GetName()};
318 ctx.WriteBuffer(out_name);
319
320 rb.Push(ResultSuccess);
321 rb.PushRaw<AudioInParameterInternal>(out_params);
322 rb.PushIpcInterface<IAudioIn>(audio_in);
323}
324
325void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
326 IPC::RequestParser rp{ctx};
327 auto protocol_specified{rp.PopRaw<u64>()};
328 auto in_params{rp.PopRaw<AudioInParameter>()};
329 auto applet_resource_user_id{rp.PopRaw<u64>()};
330 const auto device_name_data{ctx.ReadBuffer()};
331 auto device_name = Common::StringFromBuffer(device_name_data);
332 auto handle{ctx.GetCopyHandle(0)};
333
334 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
335 if (process.IsNull()) {
336 LOG_ERROR(Service_Audio, "Failed to get process handle");
337 IPC::ResponseBuilder rb{ctx, 2};
338 rb.Push(ResultUnknown);
339 return;
340 }
341
342 std::scoped_lock l{impl->mutex};
343 auto link{impl->LinkToManager()};
344 if (link.IsError()) {
345 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
346 IPC::ResponseBuilder rb{ctx, 2};
347 rb.Push(link);
348 return;
349 }
350
351 size_t new_session_id{};
352 auto result{impl->AcquireSessionId(new_session_id)};
353 if (result.IsError()) {
354 IPC::ResponseBuilder rb{ctx, 2};
355 rb.Push(result);
356 return;
357 }
358
359 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
360 impl->num_free_sessions);
361
362 auto audio_in =
363 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
364 process.GetPointerUnsafe(), applet_resource_user_id);
365 impl->sessions[new_session_id] = audio_in->GetImpl();
366 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
367
368 auto& out_system = impl->sessions[new_session_id]->GetSystem();
369 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
370 .channel_count = out_system.GetChannelCount(),
371 .sample_format =
372 static_cast<u32>(out_system.GetSampleFormat()),
373 .state = static_cast<u32>(out_system.GetState())};
374
375 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
376
377 std::string out_name{out_system.GetName()};
378 if (protocol_specified == 0) {
379 if (out_system.IsUac()) {
380 out_name = "UacIn";
381 } else {
382 out_name = "DeviceIn";
383 }
384 }
385
386 ctx.WriteBuffer(out_name);
387
388 rb.Push(ResultSuccess);
389 rb.PushRaw<AudioInParameterInternal>(out_params);
390 rb.PushIpcInterface<IAudioIn>(audio_in);
391}
392
393} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
deleted file mode 100644
index 51e770ff9..000000000
--- a/src/core/hle/service/audio/audin_u.h
+++ /dev/null
@@ -1,38 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class In;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class AudInU final : public ServiceFramework<AudInU> {
23public:
24 explicit AudInU(Core::System& system_);
25 ~AudInU() override;
26
27private:
28 void ListAudioIns(HLERequestContext& ctx);
29 void ListAudioInsAutoFiltered(HLERequestContext& ctx);
30 void OpenInOutImpl(HLERequestContext& ctx);
31 void OpenAudioIn(HLERequestContext& ctx);
32 void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
33
34 KernelHelpers::ServiceContext service_context;
35 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
36};
37
38} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 44af030eb..331176bf7 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,14 +2,14 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/audio/audin_u.h"
6#include "core/hle/service/audio/audio.h" 5#include "core/hle/service/audio/audio.h"
7#include "core/hle/service/audio/audio_controller.h" 6#include "core/hle/service/audio/audio_controller.h"
8#include "core/hle/service/audio/audout_u.h" 7#include "core/hle/service/audio/audio_in_manager.h"
9#include "core/hle/service/audio/audrec_a.h" 8#include "core/hle/service/audio/audio_out_manager.h"
10#include "core/hle/service/audio/audrec_u.h" 9#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/audio/audren_u.h" 10#include "core/hle/service/audio/final_output_recorder_manager.h"
12#include "core/hle/service/audio/hwopus.h" 11#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
12#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
13#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
15 15
@@ -19,12 +19,16 @@ void LoopProcess(Core::System& system) {
19 auto server_manager = std::make_unique<ServerManager>(system); 19 auto server_manager = std::make_unique<ServerManager>(system);
20 20
21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system)); 21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
22 server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); 22 server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
23 server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); 23 server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
24 server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); 24 server_manager->RegisterNamedService(
25 server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system)); 25 "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
26 server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system)); 26 server_manager->RegisterNamedService("audrec:u",
27 server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system)); 27 std::make_shared<IFinalOutputRecorderManager>(system));
28 server_manager->RegisterNamedService("audren:u",
29 std::make_shared<IAudioRendererManager>(system));
30 server_manager->RegisterNamedService("hwopus",
31 std::make_shared<IHardwareOpusDecoderManager>(system));
28 ServerManager::RunServer(std::move(server_manager)); 32 ServerManager::RunServer(std::move(server_manager));
29} 33}
30 34
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp
index a6da66d0f..7a51d1023 100644
--- a/src/core/hle/service/audio/audio_controller.cpp
+++ b/src/core/hle/service/audio/audio_controller.cpp
@@ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_)
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetTargetVolume"}, 17 {0, nullptr, "GetTargetVolume"},
18 {1, nullptr, "SetTargetVolume"}, 18 {1, nullptr, "SetTargetVolume"},
19 {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, 19 {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
20 {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, 20 {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
21 {4, nullptr, "IsTargetMute"}, 21 {4, nullptr, "IsTargetMute"},
22 {5, nullptr, "SetTargetMute"}, 22 {5, nullptr, "SetTargetMute"},
23 {6, nullptr, "IsTargetConnected"}, 23 {6, nullptr, "IsTargetConnected"},
24 {7, nullptr, "SetDefaultTarget"}, 24 {7, nullptr, "SetDefaultTarget"},
25 {8, nullptr, "GetDefaultTarget"}, 25 {8, nullptr, "GetDefaultTarget"},
26 {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, 26 {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
27 {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, 27 {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
28 {11, nullptr, "SetForceMutePolicy"}, 28 {11, nullptr, "SetForceMutePolicy"},
29 {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, 29 {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
30 {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, 30 {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
31 {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, 31 {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
32 {15, nullptr, "SetOutputTarget"}, 32 {15, nullptr, "SetOutputTarget"},
33 {16, nullptr, "SetInputTargetForceEnabled"}, 33 {16, nullptr, "SetInputTargetForceEnabled"},
34 {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, 34 {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
35 {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, 35 {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, 36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, 37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
38 {21, nullptr, "GetAudioOutputTargetForPlayReport"}, 38 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
39 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, 39 {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
40 {23, nullptr, "SetSystemOutputMasterVolume"}, 40 {23, nullptr, "SetSystemOutputMasterVolume"},
41 {24, nullptr, "GetSystemOutputMasterVolume"}, 41 {24, nullptr, "GetSystemOutputMasterVolume"},
42 {25, nullptr, "GetAudioVolumeDataForPlayReport"}, 42 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
@@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
44 {27, nullptr, "SetVolumeMappingTableForDev"}, 44 {27, nullptr, "SetVolumeMappingTableForDev"},
45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, 45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, 46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
47 {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, 47 {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
48 {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, 48 {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
49 {32, nullptr, "GetActiveOutputTarget"}, 49 {32, nullptr, "GetActiveOutputTarget"},
50 {33, nullptr, "GetTargetDeviceInfo"}, 50 {33, nullptr, "GetTargetDeviceInfo"},
51 {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, 51 {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, 54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@@ -138,7 +138,7 @@ Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target,
138} 138}
139 139
140Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) { 140Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) {
141 LOG_WARNING(Audio, "(STUBBED) called"); 141 LOG_WARNING(Audio, "(STUBBED) called, output_level_mode={}", output_level_mode);
142 R_SUCCEED(); 142 R_SUCCEED();
143} 143}
144 144
@@ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
150 R_SUCCEED(); 150 R_SUCCEED();
151} 151}
152 152
153Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
154 LOG_WARNING(Service_Audio, "(STUBBED) called");
155 R_SUCCEED();
156}
157
153Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) { 158Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
154 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); 159 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
155 160
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h
index 9e8514373..d37c4843e 100644
--- a/src/core/hle/service/audio/audio_controller.h
+++ b/src/core/hle/service/audio/audio_controller.h
@@ -45,6 +45,7 @@ private:
45 Set::AudioOutputMode output_mode); 45 Set::AudioOutputMode output_mode);
46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode); 46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode); 47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
48 Result NotifyHeadphoneVolumeWarningDisplayedEvent();
48 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled); 49 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
49 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled); 50 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
50 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event); 51 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
diff --git a/src/core/hle/service/audio/audio_device.cpp b/src/core/hle/service/audio/audio_device.cpp
new file mode 100644
index 000000000..438f3cccd
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.cpp
@@ -0,0 +1,163 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_core.h"
5#include "common/string_util.h"
6#include "core/hle/service/audio/audio_device.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::Renderer;
11
12IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
13 u32 device_num)
14 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
15 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
16 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
17 static const FunctionInfo functions[] = {
18 {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
19 {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
20 {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
21 {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
22 {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
23 {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
24 {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
25 {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
26 {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
27 {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
28 {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
29 {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
30 {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
31 {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
32 };
33 RegisterHandlers(functions);
34
35 event->Signal();
36}
37
38IAudioDevice::~IAudioDevice() {
39 service_context.CloseEvent(event);
40}
41
42Result IAudioDevice::ListAudioDeviceName(
43 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
44 R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
45}
46
47Result IAudioDevice::SetAudioDeviceOutputVolume(
48 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
49 R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
50}
51
52Result IAudioDevice::GetAudioDeviceOutputVolume(
53 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
54 R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
55}
56
57Result IAudioDevice::GetActiveAudioDeviceName(
58 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
59 R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
60}
61
62Result IAudioDevice::ListAudioDeviceNameAuto(
63 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
64 Out<s32> out_count) {
65 *out_count = impl->ListAudioDeviceName(out_names);
66
67 std::string out{};
68 for (s32 i = 0; i < *out_count; i++) {
69 std::string a{};
70 u32 j = 0;
71 while (out_names[i].name[j] != '\0') {
72 a += out_names[i].name[j];
73 j++;
74 }
75 out += "\n\t" + a;
76 }
77
78 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
79 R_SUCCEED();
80}
81
82Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
83 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
84 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
85
86 const std::string device_name = Common::StringFromBuffer(name[0].name);
87 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
88
89 if (device_name == "AudioTvOutput") {
90 impl->SetDeviceVolumes(volume);
91 }
92
93 R_SUCCEED();
94}
95
96Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
97 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
98 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
99
100 const std::string device_name = Common::StringFromBuffer(name[0].name);
101 LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
102
103 *out_volume = 1.0f;
104 if (device_name == "AudioTvOutput") {
105 *out_volume = impl->GetDeviceVolume(device_name);
106 }
107
108 R_SUCCEED();
109}
110
111Result IAudioDevice::GetActiveAudioDeviceNameAuto(
112 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
113 R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
114 out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
115 LOG_DEBUG(Service_Audio, "(STUBBED) called");
116 R_SUCCEED();
117}
118
119Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
120 LOG_DEBUG(Service_Audio, "(STUBBED) called");
121 event->Signal();
122 *out_event = &event->GetReadableEvent();
123 R_SUCCEED();
124}
125
126Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
127 LOG_DEBUG(Service_Audio, "(STUBBED) called");
128 *out_event = &event->GetReadableEvent();
129 R_SUCCEED();
130}
131
132Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
133 LOG_DEBUG(Service_Audio, "called");
134 *out_event = &event->GetReadableEvent();
135 R_SUCCEED();
136}
137
138Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
139 *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
140 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
141 R_SUCCEED();
142}
143
144Result IAudioDevice::ListAudioOutputDeviceName(
145 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
146 *out_count = impl->ListAudioOutputDeviceName(out_names);
147
148 std::string out{};
149 for (s32 i = 0; i < *out_count; i++) {
150 std::string a{};
151 u32 j = 0;
152 while (out_names[i].name[j] != '\0') {
153 a += out_names[i].name[j];
154 j++;
155 }
156 out += "\n\t" + a;
157 }
158
159 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
160 R_SUCCEED();
161}
162
163} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_device.h b/src/core/hle/service/audio/audio_device.h
new file mode 100644
index 000000000..752157272
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_device.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17using AudioCore::Renderer::AudioDevice;
18
19class IAudioDevice final : public ServiceFramework<IAudioDevice> {
20
21public:
22 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
23 u32 device_num);
24 ~IAudioDevice() override;
25
26private:
27 Result ListAudioDeviceName(
28 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
29 Out<s32> out_count);
30 Result SetAudioDeviceOutputVolume(
31 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume);
32 Result GetAudioDeviceOutputVolume(
33 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name);
34 Result GetActiveAudioDeviceName(
35 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name);
36 Result ListAudioDeviceNameAuto(
37 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
38 Out<s32> out_count);
39 Result SetAudioDeviceOutputVolumeAuto(
40 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume);
41 Result GetAudioDeviceOutputVolumeAuto(
42 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name);
43 Result GetActiveAudioDeviceNameAuto(
44 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name);
45 Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
46 Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
47 Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
48 Result GetActiveChannelCount(Out<u32> out_active_channel_count);
49 Result ListAudioOutputDeviceName(
50 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
51 Out<s32> out_count);
52
53 KernelHelpers::ServiceContext service_context;
54 std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
55 Kernel::KEvent* event;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.cpp b/src/core/hle/service/audio/audio_in.cpp
new file mode 100644
index 000000000..416803acc
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_in.h"
5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::Audio {
9using namespace AudioCore::AudioIn;
10
11IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
12 const std::string& device_name, const AudioInParameter& in_params,
13 Kernel::KProcess* handle, u64 applet_resource_user_id)
14 : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
15 event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
16 manager, event,
17 session_id)} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"},
21 {1, D<&IAudioIn::Start>, "Start"},
22 {2, D<&IAudioIn::Stop>, "Stop"},
23 {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"},
24 {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"},
25 {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"},
26 {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"},
27 {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"},
28 {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"},
29 {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"},
30 {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"},
31 {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"},
32 {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"},
33 {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"},
34 {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39
40 process->Open();
41
42 if (impl->GetSystem()
43 .Initialize(device_name, in_params, handle, applet_resource_user_id)
44 .IsError()) {
45 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
46 }
47}
48
49IAudioIn::~IAudioIn() {
50 impl->Free();
51 service_context.CloseEvent(event);
52 process->Close();
53}
54
55Result IAudioIn::GetAudioInState(Out<u32> out_state) {
56 *out_state = static_cast<u32>(impl->GetState());
57 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
58 R_SUCCEED();
59}
60
61Result IAudioIn::Start() {
62 LOG_DEBUG(Service_Audio, "called");
63 R_RETURN(impl->StartSystem());
64}
65
66Result IAudioIn::Stop() {
67 LOG_DEBUG(Service_Audio, "called");
68 R_RETURN(impl->StopSystem());
69}
70
71Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
72 u64 buffer_client_ptr) {
73 R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
74}
75
76Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
77 u64 buffer_client_ptr) {
78 if (buffer.empty()) {
79 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
80 R_THROW(Audio::ResultInsufficientBuffer);
81 }
82
83 [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()};
84 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id,
85 buffer_client_ptr);
86
87 R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr));
88}
89
90Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
91 LOG_DEBUG(Service_Audio, "called");
92 *out_event = &impl->GetBufferEvent();
93 R_SUCCEED();
94}
95
96Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
97 Out<u32> out_count) {
98 R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count));
99}
100
101Result IAudioIn::GetReleasedAudioInBuffersAuto(
102 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
103
104 if (!out_audio_buffer.empty()) {
105 out_audio_buffer[0] = 0;
106 }
107 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
108
109 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
110 impl->GetSystem().GetSessionId(), *out_count);
111 R_SUCCEED();
112}
113
114Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
115 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
116
117 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
118 *out_contains_buffer);
119 R_SUCCEED();
120}
121
122Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) {
123 *out_buffer_count = impl->GetBufferCount();
124 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
125 R_SUCCEED();
126}
127
128Result IAudioIn::SetDeviceGain(f32 device_gain) {
129 impl->SetVolume(device_gain);
130 LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain);
131 R_SUCCEED();
132}
133
134Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) {
135 *out_device_gain = impl->GetVolume();
136 LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain);
137 R_SUCCEED();
138}
139
140Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) {
141 *out_flushed = impl->FlushAudioInBuffers();
142 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.h b/src/core/hle/service/audio/audio_in.h
new file mode 100644
index 000000000..3fe1e1e87
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/in/audio_in.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13class IAudioIn final : public ServiceFramework<IAudioIn> {
14public:
15 explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager,
16 size_t session_id, const std::string& device_name,
17 const AudioCore::AudioIn::AudioInParameter& in_params,
18 Kernel::KProcess* handle, u64 applet_resource_user_id);
19 ~IAudioIn() override;
20
21 std::shared_ptr<AudioCore::AudioIn::In> GetImpl() {
22 return impl;
23 }
24
25 Result GetAudioInState(Out<u32> out_state);
26 Result Start();
27 Result Stop();
28 Result AppendAudioInBuffer(
29 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
30 u64 buffer_client_ptr);
31 Result AppendAudioInBufferAuto(
32 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
33 u64 buffer_client_ptr);
34 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
35 Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
36 Out<u32> out_count);
37 Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
38 Out<u32> out_count);
39 Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
40 Result GetAudioInBufferCount(Out<u32> out_buffer_count);
41 Result SetDeviceGain(f32 device_gain);
42 Result GetDeviceGain(Out<f32> out_device_gain);
43 Result FlushAudioInBuffers(Out<bool> out_flushed);
44
45private:
46 Kernel::KProcess* process;
47 KernelHelpers::ServiceContext service_context;
48 Kernel::KEvent* event;
49 std::shared_ptr<AudioCore::AudioIn::In> impl;
50 Common::ScratchBuffer<u64> released_buffer;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.cpp b/src/core/hle/service/audio/audio_in_manager.cpp
new file mode 100644
index 000000000..2675a5773
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.cpp
@@ -0,0 +1,125 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_in.h"
6#include "core/hle/service/audio/audio_in_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::AudioIn;
11
12IAudioInManager::IAudioInManager(Core::System& system_)
13 : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
14 system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"},
18 {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"},
19 {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"},
20 {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"},
21 {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"},
22 {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IAudioInManager::~IAudioInManager() = default;
30
31Result IAudioInManager::ListAudioIns(
32 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) {
33 LOG_DEBUG(Service_Audio, "called");
34 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
35}
36
37Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
38 Out<SharedPointer<IAudioIn>> out_audio_in,
39 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
40 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
41 AudioInParameter parameter,
42 InCopyHandle<Kernel::KProcess> process_handle,
43 ClientAppletResourceUserId aruid) {
44 LOG_DEBUG(Service_Audio, "called");
45 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
46 name, {}, parameter, process_handle, aruid));
47}
48
49Result IAudioInManager::ListAudioInsAuto(
50 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
51 LOG_DEBUG(Service_Audio, "called");
52 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
53}
54
55Result IAudioInManager::OpenAudioInAuto(
56 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
57 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
58 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
59 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
60 LOG_DEBUG(Service_Audio, "called");
61 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
62 name, {}, parameter, process_handle, aruid));
63}
64
65Result IAudioInManager::ListAudioInsAutoFiltered(
66 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
67 LOG_DEBUG(Service_Audio, "called");
68 *out_count = impl->GetDeviceNames(out_audio_ins, true);
69 R_SUCCEED();
70}
71
72Result IAudioInManager::OpenAudioInProtocolSpecified(
73 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
74 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
75 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
76 AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
77 ClientAppletResourceUserId aruid) {
78 LOG_DEBUG(Service_Audio, "called");
79
80 if (!process_handle) {
81 LOG_ERROR(Service_Audio, "Failed to get process handle");
82 R_THROW(ResultUnknown);
83 }
84 if (name.empty() || out_name.empty()) {
85 LOG_ERROR(Service_Audio, "Invalid buffers");
86 R_THROW(ResultUnknown);
87 }
88
89 std::scoped_lock l{impl->mutex};
90
91 size_t new_session_id{};
92
93 R_TRY(impl->LinkToManager());
94 R_TRY(impl->AcquireSessionId(new_session_id));
95
96 LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
97 impl->num_free_sessions);
98
99 const auto device_name = Common::StringFromBuffer(name[0].name);
100 *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
101 parameter, process_handle.Get(), aruid.pid);
102 impl->sessions[new_session_id] = (*out_audio_in)->GetImpl();
103 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
104
105 auto& out_system = impl->sessions[new_session_id]->GetSystem();
106 *out_parameter_internal =
107 AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
108 .channel_count = out_system.GetChannelCount(),
109 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
110 .state = static_cast<u32>(out_system.GetState())};
111
112 out_name[0] = AudioDeviceName(out_system.GetName());
113
114 if (protocol == Protocol{}) {
115 if (out_system.IsUac()) {
116 out_name[0] = AudioDeviceName("UacIn");
117 } else {
118 out_name[0] = AudioDeviceName("DeviceIn");
119 }
120 }
121
122 R_SUCCEED();
123}
124
125} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.h b/src/core/hle/service/audio/audio_in_manager.h
new file mode 100644
index 000000000..2a983bc60
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14using Protocol = std::array<u32, 2>;
15
16class IAudioIn;
17
18class IAudioInManager final : public ServiceFramework<IAudioInManager> {
19public:
20 explicit IAudioInManager(Core::System& system_);
21 ~IAudioInManager() override;
22
23private:
24 Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins,
25 Out<u32> out_count);
26 Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
27 Out<SharedPointer<IAudioIn>> out_audio_in,
28 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
29 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
30 AudioCore::AudioIn::AudioInParameter parameter,
31 InCopyHandle<Kernel::KProcess> process_handle,
32 ClientAppletResourceUserId aruid);
33
34 Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins,
35 Out<u32> out_count);
36 Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
37 Out<SharedPointer<IAudioIn>> out_audio_in,
38 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
39 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
40 AudioCore::AudioIn::AudioInParameter parameter,
41 InCopyHandle<Kernel::KProcess> process_handle,
42 ClientAppletResourceUserId aruid);
43
44 Result ListAudioInsAutoFiltered(
45 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count);
46 Result OpenAudioInProtocolSpecified(
47 Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
48 Out<SharedPointer<IAudioIn>> out_audio_in,
49 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
50 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
51 AudioCore::AudioIn::AudioInParameter parameter,
52 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
53
54 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
55};
56
57} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.cpp b/src/core/hle/service/audio/audio_out.cpp
new file mode 100644
index 000000000..53009d5d7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/out/audio_out.h"
5#include "audio_core/out/audio_out_system.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/service/audio/audio_out.h"
8#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Service::Audio {
13using namespace AudioCore::AudioOut;
14
15IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
16 const std::string& device_name, const AudioOutParameter& in_params,
17 Kernel::KProcess* handle, u64 applet_resource_user_id)
18 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
19 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
20 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
21
22 // clang-format off
23 static const FunctionInfo functions[] = {
24 {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"},
25 {1, D<&IAudioOut::Start>, "Start"},
26 {2, D<&IAudioOut::Stop>, "Stop"},
27 {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"},
28 {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"},
29 {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"},
30 {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"},
31 {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"},
32 {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"},
33 {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"},
34 {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"},
35 {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"},
36 {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"},
37 {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"},
38 };
39 // clang-format on
40 RegisterHandlers(functions);
41
42 process->Open();
43}
44
45IAudioOut::~IAudioOut() {
46 impl->Free();
47 service_context.CloseEvent(event);
48 process->Close();
49}
50
51Result IAudioOut::GetAudioOutState(Out<u32> out_state) {
52 *out_state = static_cast<u32>(impl->GetState());
53 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
54 R_SUCCEED();
55}
56
57Result IAudioOut::Start() {
58 LOG_DEBUG(Service_Audio, "called");
59 R_RETURN(impl->StartSystem());
60}
61
62Result IAudioOut::Stop() {
63 LOG_DEBUG(Service_Audio, "called");
64 R_RETURN(impl->StopSystem());
65}
66
67Result IAudioOut::AppendAudioOutBuffer(
68 InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
69 R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
70}
71
72Result IAudioOut::AppendAudioOutBufferAuto(
73 InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
74 if (audio_out_buffer.empty()) {
75 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
76 R_THROW(Audio::ResultInsufficientBuffer);
77 }
78
79 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
80 impl->GetSystem().GetSessionId(), buffer_client_ptr);
81 R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr));
82}
83
84Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
85 LOG_DEBUG(Service_Audio, "called");
86 *out_event = &impl->GetBufferEvent();
87 R_SUCCEED();
88}
89
90Result IAudioOut::GetReleasedAudioOutBuffers(
91 OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) {
92 R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count));
93}
94
95Result IAudioOut::GetReleasedAudioOutBuffersAuto(
96 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
97
98 if (!out_audio_buffer.empty()) {
99 out_audio_buffer[0] = 0;
100 }
101 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
102
103 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
104 impl->GetSystem().GetSessionId(), *out_count);
105 R_SUCCEED();
106}
107
108Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
109 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
110
111 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
112 *out_contains_buffer);
113 R_SUCCEED();
114}
115
116Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) {
117 *out_buffer_count = impl->GetBufferCount();
118 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
119 R_SUCCEED();
120}
121
122Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) {
123 *out_played_sample_count = impl->GetPlayedSampleCount();
124 LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count);
125 R_SUCCEED();
126}
127
128Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) {
129 *out_flushed = impl->FlushAudioOutBuffers();
130 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
131 R_SUCCEED();
132}
133
134Result IAudioOut::SetAudioOutVolume(f32 volume) {
135 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
136 impl->SetVolume(volume);
137 R_SUCCEED();
138}
139
140Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) {
141 *out_volume = impl->GetVolume();
142 LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.h b/src/core/hle/service/audio/audio_out.h
new file mode 100644
index 000000000..779b213e7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Kernel {
13class KReadableEvent;
14}
15
16namespace Service::Audio {
17
18class IAudioOut : public ServiceFramework<IAudioOut> {
19public:
20 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
21 size_t session_id, const std::string& device_name,
22 const AudioCore::AudioOut::AudioOutParameter& in_params,
23 Kernel::KProcess* handle, u64 applet_resource_user_id);
24 ~IAudioOut() override;
25
26 std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
27 return impl;
28 }
29
30 Result GetAudioOutState(Out<u32> out_state);
31 Result Start();
32 Result Stop();
33 Result AppendAudioOutBuffer(
34 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer,
35 u64 buffer_client_ptr);
36 Result AppendAudioOutBufferAuto(
37 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer,
38 u64 buffer_client_ptr);
39 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
41 Out<u32> out_count);
42 Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
43 Out<u32> out_count);
44 Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
45 Result GetAudioOutBufferCount(Out<u32> out_buffer_count);
46 Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count);
47 Result FlushAudioOutBuffers(Out<bool> out_flushed);
48 Result SetAudioOutVolume(f32 volume);
49 Result GetAudioOutVolume(Out<f32> out_volume);
50
51private:
52 KernelHelpers::ServiceContext service_context;
53 Kernel::KEvent* event;
54 Kernel::KProcess* process;
55 std::shared_ptr<AudioCore::AudioOut::Out> impl;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.cpp b/src/core/hle/service/audio/audio_out_manager.cpp
new file mode 100644
index 000000000..153445097
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.cpp
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_out.h"
6#include "core/hle/service/audio/audio_out_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/memory.h"
9
10namespace Service::Audio {
11using namespace AudioCore::AudioOut;
12
13IAudioOutManager::IAudioOutManager(Core::System& system_)
14 : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
18 {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"},
19 {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"},
20 {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25}
26
27IAudioOutManager::~IAudioOutManager() = default;
28
29Result IAudioOutManager::ListAudioOuts(
30 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) {
31 R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
32}
33
34Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
38 AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle,
40 ClientAppletResourceUserId aruid) {
41 R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
42 parameter, process_handle, aruid));
43}
44
45Result IAudioOutManager::ListAudioOutsAuto(
46 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) {
47 if (!out_audio_outs.empty()) {
48 out_audio_outs[0] = AudioDeviceName("DeviceOut");
49 *out_count = 1;
50 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
51 } else {
52 *out_count = 0;
53 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
54 }
55
56 R_SUCCEED();
57}
58
59Result IAudioOutManager::OpenAudioOutAuto(
60 Out<AudioOutParameterInternal> out_parameter_internal,
61 Out<SharedPointer<IAudioOut>> out_audio_out,
62 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
63 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
64 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
65 if (!process_handle) {
66 LOG_ERROR(Service_Audio, "Failed to get process handle");
67 R_THROW(ResultUnknown);
68 }
69 if (name.empty() || out_name.empty()) {
70 LOG_ERROR(Service_Audio, "Invalid buffers");
71 R_THROW(ResultUnknown);
72 }
73
74 size_t new_session_id{};
75 R_TRY(impl->LinkToManager());
76 R_TRY(impl->AcquireSessionId(new_session_id));
77
78 const auto device_name = Common::StringFromBuffer(name[0].name);
79 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
80 impl->num_free_sessions);
81
82 auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
83 parameter, process_handle.Get(), aruid.pid);
84 R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(),
85 aruid.pid));
86
87 *out_audio_out = audio_out;
88 impl->sessions[new_session_id] = audio_out->GetImpl();
89 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
90
91 auto& out_system = impl->sessions[new_session_id]->GetSystem();
92 *out_parameter_internal =
93 AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
94 .channel_count = out_system.GetChannelCount(),
95 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
96 .state = static_cast<u32>(out_system.GetState())};
97
98 R_SUCCEED();
99}
100
101} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.h b/src/core/hle/service/audio/audio_out_manager.h
new file mode 100644
index 000000000..eaa27bc79
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14class IAudioOut;
15
16class IAudioOutManager final : public ServiceFramework<IAudioOutManager> {
17public:
18 explicit IAudioOutManager(Core::System& system_);
19 ~IAudioOutManager() override;
20
21private:
22 Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs,
23 Out<u32> out_count);
24 Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
25 Out<SharedPointer<IAudioOut>> out_audio_out,
26 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
27 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
28 AudioCore::AudioOut::AudioOutParameter parameter,
29 InCopyHandle<Kernel::KProcess> process_handle,
30 ClientAppletResourceUserId aruid);
31 Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs,
32 Out<u32> out_count);
33 Result OpenAudioOutAuto(
34 Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
38 AudioCore::AudioOut::AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
40
41 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
42};
43
44} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.cpp b/src/core/hle/service/audio/audio_renderer.cpp
new file mode 100644
index 000000000..fc4aad233
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.cpp
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_renderer.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8using namespace AudioCore::Renderer;
9
10IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
11 AudioCore::AudioRendererParameterInternal& params,
12 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
13 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
14 s32 session_id)
15 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
16 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
17 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
18 process_handle_} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
22 {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"},
23 {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"},
24 {3, D<&IAudioRenderer::GetState>, "GetState"},
25 {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"},
26 {5, D<&IAudioRenderer::Start>, "Start"},
27 {6, D<&IAudioRenderer::Stop>, "Stop"},
28 {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"},
29 {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"},
30 {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"},
31 {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"},
32 {11, nullptr, "ExecuteAudioRendererRendering"},
33 {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"},
34 {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"},
35 };
36 // clang-format on
37 RegisterHandlers(functions);
38
39 process_handle->Open();
40 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle,
41 applet_resource_user_id, session_id);
42}
43
44IAudioRenderer::~IAudioRenderer() {
45 impl->Finalize();
46 service_context.CloseEvent(rendered_event);
47 process_handle->Close();
48}
49
50Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) {
51 *out_sample_rate = impl->GetSystem().GetSampleRate();
52 LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate);
53 R_SUCCEED();
54}
55
56Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) {
57 *out_sample_count = impl->GetSystem().GetSampleCount();
58 LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count);
59 R_SUCCEED();
60}
61
62Result IAudioRenderer::GetState(Out<u32> out_state) {
63 *out_state = !impl->GetSystem().IsActive();
64 LOG_DEBUG(Service_Audio, "called, state {}", *out_state);
65 R_SUCCEED();
66}
67
68Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) {
69 LOG_DEBUG(Service_Audio, "called");
70 *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount();
71 R_SUCCEED();
72}
73
74Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
75 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
76 InBuffer<BufferAttr_HipcMapAlias> input) {
77 R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input));
78}
79
80Result IAudioRenderer::RequestUpdateAuto(
81 OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
82 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
83 InBuffer<BufferAttr_HipcAutoSelect> input) {
84 LOG_TRACE(Service_Audio, "called");
85
86 const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer);
87 if (result.IsFailure()) {
88 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
89 }
90
91 R_RETURN(result);
92}
93
94Result IAudioRenderer::Start() {
95 LOG_DEBUG(Service_Audio, "called");
96 impl->Start();
97 R_SUCCEED();
98}
99
100Result IAudioRenderer::Stop() {
101 LOG_DEBUG(Service_Audio, "called");
102 impl->Stop();
103 R_SUCCEED();
104}
105
106Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
107 LOG_DEBUG(Service_Audio, "called");
108 R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual,
109 Audio::ResultNotSupported);
110 *out_event = &rendered_event->GetReadableEvent();
111 R_SUCCEED();
112}
113
114Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) {
115 LOG_DEBUG(Service_Audio, "called");
116 impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit);
117 ;
118 R_SUCCEED();
119}
120
121Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) {
122 LOG_DEBUG(Service_Audio, "called");
123 *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit();
124 R_SUCCEED();
125}
126
127Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) {
128 LOG_DEBUG(Service_Audio, "called");
129 impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter);
130 R_SUCCEED();
131}
132
133Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) {
134 LOG_DEBUG(Service_Audio, "called");
135 *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter();
136 R_SUCCEED();
137}
138
139} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.h b/src/core/hle/service/audio/audio_renderer.h
new file mode 100644
index 000000000..f25c50ce8
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.h
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_renderer.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
18public:
19 explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
20 AudioCore::AudioRendererParameterInternal& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
22 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
23 s32 session_id);
24 ~IAudioRenderer() override;
25
26private:
27 Result GetSampleRate(Out<u32> out_sample_rate);
28 Result GetSampleCount(Out<u32> out_sample_count);
29 Result GetState(Out<u32> out_state);
30 Result GetMixBufferCount(Out<u32> out_mix_buffer_count);
31 Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
32 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
33 InBuffer<BufferAttr_HipcMapAlias> input);
34 Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
35 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
36 InBuffer<BufferAttr_HipcAutoSelect> input);
37 Result Start();
38 Result Stop();
39 Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result SetRenderingTimeLimit(u32 rendering_time_limit);
41 Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit);
42 Result SetVoiceDropParameter(f32 voice_drop_parameter);
43 Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter);
44
45 KernelHelpers::ServiceContext service_context;
46 Kernel::KEvent* rendered_event;
47 AudioCore::Renderer::Manager& manager;
48 std::unique_ptr<AudioCore::Renderer::Renderer> impl;
49 Kernel::KProcess* process_handle;
50 Common::ScratchBuffer<u8> output_buffer;
51 Common::ScratchBuffer<u8> performance_buffer;
52};
53
54} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
new file mode 100644
index 000000000..6a1345c07
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_render_manager.h"
5#include "audio_core/common/feature_support.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/service/audio/audio_device.h"
9#include "core/hle/service/audio/audio_renderer.h"
10#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/cmif_serialization.h"
12
13namespace Service::Audio {
14
15using namespace AudioCore::Renderer;
16
17IAudioRendererManager::IAudioRendererManager(Core::System& system_)
18 : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
22 {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"},
23 {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"},
24 {3, nullptr, "OpenAudioRendererForManualExecution"},
25 {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IAudioRendererManager::~IAudioRendererManager() = default;
33
34Result IAudioRendererManager::OpenAudioRenderer(
35 Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
36 AudioCore::AudioRendererParameterInternal parameter,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
38 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
39 LOG_DEBUG(Service_Audio, "called");
40
41 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
42 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
43 R_THROW(Audio::ResultOutOfSessions);
44 }
45
46 const auto session_id{impl->GetSessionId()};
47 if (session_id == -1) {
48 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
49 R_THROW(Audio::ResultOutOfSessions);
50 }
51
52 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
53 impl->GetSessionCount());
54
55 *out_audio_renderer =
56 std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size,
57 process_handle.Get(), aruid.pid, session_id);
58 R_SUCCEED();
59}
60
61Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size,
62 AudioCore::AudioRendererParameterInternal params) {
63 LOG_DEBUG(Service_Audio, "called");
64
65 R_TRY(impl->GetWorkBufferSize(params, *out_size))
66
67 std::string output_info{};
68 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
69 output_info +=
70 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
71 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
72 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
73 output_info += fmt::format(
74 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
75 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
76 "Context {:04X}",
77 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
78 params.splitter_destinations, params.voices, params.perf_frames,
79 params.external_context_size);
80
81 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
82 output_info, *out_size);
83 R_SUCCEED();
84}
85
86Result IAudioRendererManager::GetAudioDeviceService(
87 Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) {
88 LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid);
89 *out_audio_device = std::make_shared<IAudioDevice>(
90 system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
91 R_SUCCEED();
92}
93
94Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(
95 Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision,
96 ClientAppletResourceUserId aruid) {
97 LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision),
98 aruid.pid);
99 *out_audio_device =
100 std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++);
101 R_SUCCEED();
102}
103
104} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.h b/src/core/hle/service/audio/audio_renderer_manager.h
new file mode 100644
index 000000000..69eee664c
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_render_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IAudioDevice;
13class IAudioRenderer;
14
15class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
16public:
17 explicit IAudioRendererManager(Core::System& system_);
18 ~IAudioRendererManager() override;
19
20private:
21 Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
22 AudioCore::AudioRendererParameterInternal parameter,
23 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
24 InCopyHandle<Kernel::KProcess> process_handle,
25 ClientAppletResourceUserId aruid);
26 Result GetWorkBufferSize(Out<u64> out_size,
27 AudioCore::AudioRendererParameterInternal parameter);
28 Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device,
29 ClientAppletResourceUserId aruid);
30 Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
31 u32 revision, ClientAppletResourceUserId aruid);
32
33 std::unique_ptr<AudioCore::Renderer::Manager> impl;
34 u32 num_audio_devices{0};
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
deleted file mode 100644
index 8cc7b69f4..000000000
--- a/src/core/hle/service/audio/audout_u.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <cstring>
6#include <vector>
7
8#include "audio_core/out/audio_out_system.h"
9#include "audio_core/renderer/audio_device.h"
10#include "common/common_funcs.h"
11#include "common/logging/log.h"
12#include "common/scratch_buffer.h"
13#include "common/string_util.h"
14#include "common/swap.h"
15#include "core/core.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/audio/audout_u.h"
18#include "core/hle/service/audio/errors.h"
19#include "core/hle/service/ipc_helpers.h"
20#include "core/memory.h"
21
22namespace Service::Audio {
23using namespace AudioCore::AudioOut;
24
25class IAudioOut final : public ServiceFramework<IAudioOut> {
26public:
27 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
28 size_t session_id, const std::string& device_name,
29 const AudioOutParameter& in_params, Kernel::KProcess* handle,
30 u64 applet_resource_user_id)
31 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
32 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
33 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
34
35 // clang-format off
36 static const FunctionInfo functions[] = {
37 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
38 {1, &IAudioOut::Start, "Start"},
39 {2, &IAudioOut::Stop, "Stop"},
40 {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
41 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
42 {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"},
43 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
44 {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"},
45 {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"},
46 {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
47 {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
48 {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
49 {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
50 {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
51 };
52 // clang-format on
53 RegisterHandlers(functions);
54
55 process->Open();
56 }
57
58 ~IAudioOut() override {
59 impl->Free();
60 service_context.CloseEvent(event);
61 process->Close();
62 }
63
64 [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
65 return impl;
66 }
67
68private:
69 void GetAudioOutState(HLERequestContext& ctx) {
70 const auto state = static_cast<u32>(impl->GetState());
71
72 LOG_DEBUG(Service_Audio, "called. State={}", state);
73
74 IPC::ResponseBuilder rb{ctx, 3};
75 rb.Push(ResultSuccess);
76 rb.Push(state);
77 }
78
79 void Start(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Audio, "called");
81
82 auto result = impl->StartSystem();
83
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(result);
86 }
87
88 void Stop(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_Audio, "called");
90
91 auto result = impl->StopSystem();
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(result);
95 }
96
97 void AppendAudioOutBuffer(HLERequestContext& ctx) {
98 IPC::RequestParser rp{ctx};
99 u64 tag = rp.PopRaw<u64>();
100
101 const auto in_buffer_size{ctx.GetReadBufferSize()};
102 if (in_buffer_size < sizeof(AudioOutBuffer)) {
103 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
104 }
105
106 const auto& in_buffer = ctx.ReadBuffer();
107 AudioOutBuffer buffer{};
108 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
109
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
111 impl->GetSystem().GetSessionId(), tag);
112
113 auto result = impl->AppendBuffer(buffer, tag);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void RegisterBufferEvent(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_Audio, "called");
121
122 auto& buffer_event = impl->GetBufferEvent();
123
124 IPC::ResponseBuilder rb{ctx, 2, 1};
125 rb.Push(ResultSuccess);
126 rb.PushCopyObjects(buffer_event);
127 }
128
129 void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
130 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
131 released_buffer.resize_destructive(write_buffer_size);
132 released_buffer[0] = 0;
133
134 const auto count = impl->GetReleasedBuffers(released_buffer);
135
136 ctx.WriteBuffer(released_buffer);
137
138 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
139 impl->GetSystem().GetSessionId(), count);
140
141 IPC::ResponseBuilder rb{ctx, 3};
142 rb.Push(ResultSuccess);
143 rb.Push(count);
144 }
145
146 void ContainsAudioOutBuffer(HLERequestContext& ctx) {
147 IPC::RequestParser rp{ctx};
148
149 const u64 tag{rp.Pop<u64>()};
150 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
151
152 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
153
154 IPC::ResponseBuilder rb{ctx, 3};
155 rb.Push(ResultSuccess);
156 rb.Push(buffer_queued);
157 }
158
159 void GetAudioOutBufferCount(HLERequestContext& ctx) {
160 const auto buffer_count = impl->GetBufferCount();
161
162 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
163
164 IPC::ResponseBuilder rb{ctx, 3};
165 rb.Push(ResultSuccess);
166 rb.Push(buffer_count);
167 }
168
169 void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
170 const auto samples_played = impl->GetPlayedSampleCount();
171
172 LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
173
174 IPC::ResponseBuilder rb{ctx, 4};
175 rb.Push(ResultSuccess);
176 rb.Push(samples_played);
177 }
178
179 void FlushAudioOutBuffers(HLERequestContext& ctx) {
180 bool flushed{impl->FlushAudioOutBuffers()};
181
182 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
183
184 IPC::ResponseBuilder rb{ctx, 3};
185 rb.Push(ResultSuccess);
186 rb.Push(flushed);
187 }
188
189 void SetAudioOutVolume(HLERequestContext& ctx) {
190 IPC::RequestParser rp{ctx};
191 const auto volume = rp.Pop<f32>();
192
193 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
194
195 impl->SetVolume(volume);
196
197 IPC::ResponseBuilder rb{ctx, 2};
198 rb.Push(ResultSuccess);
199 }
200
201 void GetAudioOutVolume(HLERequestContext& ctx) {
202 const auto volume = impl->GetVolume();
203
204 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
205
206 IPC::ResponseBuilder rb{ctx, 3};
207 rb.Push(ResultSuccess);
208 rb.Push(volume);
209 }
210
211 KernelHelpers::ServiceContext service_context;
212 Kernel::KEvent* event;
213 Kernel::KProcess* process;
214 std::shared_ptr<AudioCore::AudioOut::Out> impl;
215 Common::ScratchBuffer<u64> released_buffer;
216};
217
218AudOutU::AudOutU(Core::System& system_)
219 : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
220 impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
221 // clang-format off
222 static const FunctionInfo functions[] = {
223 {0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
224 {1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
225 {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"},
226 {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"},
227 };
228 // clang-format on
229
230 RegisterHandlers(functions);
231}
232
233AudOutU::~AudOutU() = default;
234
235void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
236 using namespace AudioCore::Renderer;
237
238 std::scoped_lock l{impl->mutex};
239
240 const auto write_count =
241 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
242 std::vector<AudioDevice::AudioDeviceName> device_names{};
243 if (write_count > 0) {
244 device_names.emplace_back("DeviceOut");
245 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
246 } else {
247 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
248 }
249
250 ctx.WriteBuffer(device_names);
251
252 IPC::ResponseBuilder rb{ctx, 3};
253 rb.Push(ResultSuccess);
254 rb.Push<u32>(static_cast<u32>(device_names.size()));
255}
256
257void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
258 IPC::RequestParser rp{ctx};
259 auto in_params{rp.PopRaw<AudioOutParameter>()};
260 auto applet_resource_user_id{rp.PopRaw<u64>()};
261 const auto device_name_data{ctx.ReadBuffer()};
262 auto device_name = Common::StringFromBuffer(device_name_data);
263 auto handle{ctx.GetCopyHandle(0)};
264
265 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
266 if (process.IsNull()) {
267 LOG_ERROR(Service_Audio, "Failed to get process handle");
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(ResultUnknown);
270 return;
271 }
272
273 auto link{impl->LinkToManager()};
274 if (link.IsError()) {
275 LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
276 IPC::ResponseBuilder rb{ctx, 2};
277 rb.Push(link);
278 return;
279 }
280
281 size_t new_session_id{};
282 auto result{impl->AcquireSessionId(new_session_id)};
283 if (result.IsError()) {
284 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(result);
286 return;
287 }
288
289 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
290 impl->num_free_sessions);
291
292 auto audio_out =
293 std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params,
294 process.GetPointerUnsafe(), applet_resource_user_id);
295 result = audio_out->GetImpl()->GetSystem().Initialize(
296 device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
297 if (result.IsError()) {
298 LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
299 IPC::ResponseBuilder rb{ctx, 2};
300 rb.Push(result);
301 return;
302 }
303
304 impl->sessions[new_session_id] = audio_out->GetImpl();
305 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
306
307 auto& out_system = impl->sessions[new_session_id]->GetSystem();
308 AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
309 .channel_count = out_system.GetChannelCount(),
310 .sample_format =
311 static_cast<u32>(out_system.GetSampleFormat()),
312 .state = static_cast<u32>(out_system.GetState())};
313
314 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
315
316 ctx.WriteBuffer(out_system.GetName());
317
318 rb.Push(ResultSuccess);
319 rb.PushRaw<AudioOutParameterInternal>(out_params);
320 rb.PushIpcInterface<IAudioOut>(audio_out);
321}
322
323} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
deleted file mode 100644
index 8f288c6e0..000000000
--- a/src/core/hle/service/audio/audout_u.h
+++ /dev/null
@@ -1,37 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class Out;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class IAudioOut;
23
24class AudOutU final : public ServiceFramework<AudOutU> {
25public:
26 explicit AudOutU(Core::System& system_);
27 ~AudOutU() override;
28
29private:
30 void ListAudioOuts(HLERequestContext& ctx);
31 void OpenAudioOut(HLERequestContext& ctx);
32
33 KernelHelpers::ServiceContext service_context;
34 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
deleted file mode 100644
index 10108abc0..000000000
--- a/src/core/hle/service/audio/audren_u.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <memory>
6
7#include "audio_core/audio_core.h"
8#include "audio_core/common/audio_renderer_parameter.h"
9#include "audio_core/common/feature_support.h"
10#include "audio_core/renderer/audio_device.h"
11#include "audio_core/renderer/audio_renderer.h"
12#include "audio_core/renderer/voice/voice_info.h"
13#include "common/alignment.h"
14#include "common/bit_util.h"
15#include "common/common_funcs.h"
16#include "common/logging/log.h"
17#include "common/polyfill_ranges.h"
18#include "common/scratch_buffer.h"
19#include "common/string_util.h"
20#include "core/core.h"
21#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_process.h"
23#include "core/hle/kernel/k_transfer_memory.h"
24#include "core/hle/service/audio/audren_u.h"
25#include "core/hle/service/audio/errors.h"
26#include "core/hle/service/ipc_helpers.h"
27#include "core/memory.h"
28
29using namespace AudioCore::Renderer;
30
31namespace Service::Audio {
32
33class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
34public:
35 explicit IAudioRenderer(Core::System& system_, Manager& manager_,
36 AudioCore::AudioRendererParameterInternal& params,
37 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
38 u32 process_handle, Kernel::KProcess& process_,
39 u64 applet_resource_user_id, s32 session_id)
40 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
41 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
42 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
43 // clang-format off
44 static const FunctionInfo functions[] = {
45 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
46 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
47 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
48 {3, &IAudioRenderer::GetState, "GetState"},
49 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
50 {5, &IAudioRenderer::Start, "Start"},
51 {6, &IAudioRenderer::Stop, "Stop"},
52 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
53 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
54 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
55 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
56 {11, nullptr, "ExecuteAudioRendererRendering"},
57 {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
58 {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
59 };
60 // clang-format on
61 RegisterHandlers(functions);
62
63 process.Open();
64 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
65 applet_resource_user_id, session_id);
66 }
67
68 ~IAudioRenderer() override {
69 impl->Finalize();
70 service_context.CloseEvent(rendered_event);
71 process.Close();
72 }
73
74private:
75 void GetSampleRate(HLERequestContext& ctx) {
76 const auto sample_rate{impl->GetSystem().GetSampleRate()};
77
78 LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(ResultSuccess);
82 rb.Push(sample_rate);
83 }
84
85 void GetSampleCount(HLERequestContext& ctx) {
86 const auto sample_count{impl->GetSystem().GetSampleCount()};
87
88 LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
89
90 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(ResultSuccess);
92 rb.Push(sample_count);
93 }
94
95 void GetState(HLERequestContext& ctx) {
96 const u32 state{!impl->GetSystem().IsActive()};
97
98 LOG_DEBUG(Service_Audio, "called, state {}", state);
99
100 IPC::ResponseBuilder rb{ctx, 3};
101 rb.Push(ResultSuccess);
102 rb.Push(state);
103 }
104
105 void GetMixBufferCount(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Audio, "called");
107
108 const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
109
110 IPC::ResponseBuilder rb{ctx, 3};
111 rb.Push(ResultSuccess);
112 rb.Push(buffer_count);
113 }
114
115 void RequestUpdate(HLERequestContext& ctx) {
116 LOG_TRACE(Service_Audio, "called");
117
118 const auto input{ctx.ReadBuffer(0)};
119
120 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
121 // checking size 0. Performance size is 0 for most games.
122
123 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
124 if (is_buffer_b) {
125 const auto buffersB{ctx.BufferDescriptorB()};
126 output_buffer.resize_destructive(buffersB[0].Size());
127 performance_buffer.resize_destructive(buffersB[1].Size());
128 } else {
129 const auto buffersC{ctx.BufferDescriptorC()};
130 output_buffer.resize_destructive(buffersC[0].Size());
131 performance_buffer.resize_destructive(buffersC[1].Size());
132 }
133
134 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
135
136 if (result.IsSuccess()) {
137 if (is_buffer_b) {
138 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
139 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
140 } else {
141 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
142 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
143 }
144 } else {
145 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
146 result.GetDescription());
147 }
148
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(result);
151 }
152
153 void Start(HLERequestContext& ctx) {
154 LOG_DEBUG(Service_Audio, "called");
155
156 impl->Start();
157
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(ResultSuccess);
160 }
161
162 void Stop(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called");
164
165 impl->Stop();
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ResultSuccess);
169 }
170
171 void QuerySystemEvent(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called");
173
174 if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
175 IPC::ResponseBuilder rb{ctx, 2};
176 rb.Push(Audio::ResultNotSupported);
177 return;
178 }
179
180 IPC::ResponseBuilder rb{ctx, 2, 1};
181 rb.Push(ResultSuccess);
182 rb.PushCopyObjects(rendered_event->GetReadableEvent());
183 }
184
185 void SetRenderingTimeLimit(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Audio, "called");
187
188 IPC::RequestParser rp{ctx};
189 auto limit = rp.PopRaw<u32>();
190
191 auto& system_ = impl->GetSystem();
192 system_.SetRenderingTimeLimit(limit);
193
194 IPC::ResponseBuilder rb{ctx, 2};
195 rb.Push(ResultSuccess);
196 }
197
198 void GetRenderingTimeLimit(HLERequestContext& ctx) {
199 LOG_DEBUG(Service_Audio, "called");
200
201 auto& system_ = impl->GetSystem();
202 auto time = system_.GetRenderingTimeLimit();
203
204 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess);
206 rb.Push(time);
207 }
208
209 void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Audio, "called");
211 }
212
213 void SetVoiceDropParameter(HLERequestContext& ctx) {
214 LOG_DEBUG(Service_Audio, "called");
215
216 IPC::RequestParser rp{ctx};
217 auto voice_drop_param{rp.Pop<f32>()};
218
219 auto& system_ = impl->GetSystem();
220 system_.SetVoiceDropParameter(voice_drop_param);
221
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(ResultSuccess);
224 }
225
226 void GetVoiceDropParameter(HLERequestContext& ctx) {
227 LOG_DEBUG(Service_Audio, "called");
228
229 auto& system_ = impl->GetSystem();
230 auto voice_drop_param{system_.GetVoiceDropParameter()};
231
232 IPC::ResponseBuilder rb{ctx, 3};
233 rb.Push(ResultSuccess);
234 rb.Push(voice_drop_param);
235 }
236
237 KernelHelpers::ServiceContext service_context;
238 Kernel::KEvent* rendered_event;
239 Manager& manager;
240 std::unique_ptr<Renderer> impl;
241 Kernel::KProcess& process;
242 Common::ScratchBuffer<u8> output_buffer;
243 Common::ScratchBuffer<u8> performance_buffer;
244};
245
246class IAudioDevice final : public ServiceFramework<IAudioDevice> {
247
248public:
249 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
250 u32 device_num)
251 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
252 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
253 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
254 static const FunctionInfo functions[] = {
255 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
256 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
257 {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
258 {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
259 {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
260 {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
261 {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
262 {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
263 {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
264 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
265 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
266 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
267 {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
268 {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
269 };
270 RegisterHandlers(functions);
271
272 event->Signal();
273 }
274
275 ~IAudioDevice() override {
276 service_context.CloseEvent(event);
277 }
278
279private:
280 void ListAudioDeviceName(HLERequestContext& ctx) {
281 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
282
283 std::vector<AudioDevice::AudioDeviceName> out_names{};
284
285 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
286
287 std::string out{};
288 for (u32 i = 0; i < out_count; i++) {
289 std::string a{};
290 u32 j = 0;
291 while (out_names[i].name[j] != '\0') {
292 a += out_names[i].name[j];
293 j++;
294 }
295 out += "\n\t" + a;
296 }
297
298 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
299
300 IPC::ResponseBuilder rb{ctx, 3};
301
302 ctx.WriteBuffer(out_names);
303
304 rb.Push(ResultSuccess);
305 rb.Push(out_count);
306 }
307
308 void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx};
310 const f32 volume = rp.Pop<f32>();
311
312 const auto device_name_buffer = ctx.ReadBuffer();
313 const std::string name = Common::StringFromBuffer(device_name_buffer);
314
315 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
316
317 if (name == "AudioTvOutput") {
318 impl->SetDeviceVolumes(volume);
319 }
320
321 IPC::ResponseBuilder rb{ctx, 2};
322 rb.Push(ResultSuccess);
323 }
324
325 void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
326 const auto device_name_buffer = ctx.ReadBuffer();
327 const std::string name = Common::StringFromBuffer(device_name_buffer);
328
329 LOG_DEBUG(Service_Audio, "called. Name={}", name);
330
331 f32 volume{1.0f};
332 if (name == "AudioTvOutput") {
333 volume = impl->GetDeviceVolume(name);
334 }
335
336 IPC::ResponseBuilder rb{ctx, 3};
337 rb.Push(ResultSuccess);
338 rb.Push(volume);
339 }
340
341 void GetActiveAudioDeviceName(HLERequestContext& ctx) {
342 const auto write_size = ctx.GetWriteBufferSize();
343 std::string out_name{"AudioTvOutput"};
344
345 LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
346
347 out_name.resize(write_size);
348
349 ctx.WriteBuffer(out_name);
350
351 IPC::ResponseBuilder rb{ctx, 2};
352 rb.Push(ResultSuccess);
353 }
354
355 void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
356 LOG_DEBUG(Service_Audio, "(STUBBED) called");
357
358 event->Signal();
359
360 IPC::ResponseBuilder rb{ctx, 2, 1};
361 rb.Push(ResultSuccess);
362 rb.PushCopyObjects(event->GetReadableEvent());
363 }
364
365 void GetActiveChannelCount(HLERequestContext& ctx) {
366 const auto& sink{system.AudioCore().GetOutputSink()};
367 u32 channel_count{sink.GetSystemChannels()};
368
369 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
370
371 IPC::ResponseBuilder rb{ctx, 3};
372
373 rb.Push(ResultSuccess);
374 rb.Push<u32>(channel_count);
375 }
376
377 void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
378 LOG_DEBUG(Service_Audio, "(STUBBED) called");
379
380 IPC::ResponseBuilder rb{ctx, 2, 1};
381 rb.Push(ResultSuccess);
382 rb.PushCopyObjects(event->GetReadableEvent());
383 }
384
385 void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
386 LOG_DEBUG(Service_Audio, "called");
387
388 IPC::ResponseBuilder rb{ctx, 2, 1};
389 rb.Push(ResultSuccess);
390 rb.PushCopyObjects(event->GetReadableEvent());
391 }
392
393 void ListAudioOutputDeviceName(HLERequestContext& ctx) {
394 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
395
396 std::vector<AudioDevice::AudioDeviceName> out_names{};
397
398 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
399
400 std::string out{};
401 for (u32 i = 0; i < out_count; i++) {
402 std::string a{};
403 u32 j = 0;
404 while (out_names[i].name[j] != '\0') {
405 a += out_names[i].name[j];
406 j++;
407 }
408 out += "\n\t" + a;
409 }
410
411 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
412
413 IPC::ResponseBuilder rb{ctx, 3};
414
415 ctx.WriteBuffer(out_names);
416
417 rb.Push(ResultSuccess);
418 rb.Push(out_count);
419 }
420
421 KernelHelpers::ServiceContext service_context;
422 std::unique_ptr<AudioDevice> impl;
423 Kernel::KEvent* event;
424};
425
426AudRenU::AudRenU(Core::System& system_)
427 : ServiceFramework{system_, "audren:u"},
428 service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
429 // clang-format off
430 static const FunctionInfo functions[] = {
431 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
432 {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
433 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
434 {3, nullptr, "OpenAudioRendererForManualExecution"},
435 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
436 };
437 // clang-format on
438
439 RegisterHandlers(functions);
440}
441
442AudRenU::~AudRenU() = default;
443
444void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx};
446
447 AudioCore::AudioRendererParameterInternal params;
448 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
449 rp.Skip(1, false);
450 auto transfer_memory_size = rp.Pop<u64>();
451 auto applet_resource_user_id = rp.Pop<u64>();
452 auto transfer_memory_handle = ctx.GetCopyHandle(0);
453 auto process_handle = ctx.GetCopyHandle(1);
454
455 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
456 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
457 IPC::ResponseBuilder rb{ctx, 2};
458 rb.Push(Audio::ResultOutOfSessions);
459 return;
460 }
461
462 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
463 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
464
465 const auto session_id{impl->GetSessionId()};
466 if (session_id == -1) {
467 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
468 IPC::ResponseBuilder rb{ctx, 2};
469 rb.Push(Audio::ResultOutOfSessions);
470 return;
471 }
472
473 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
474 impl->GetSessionCount());
475
476 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
477 rb.Push(ResultSuccess);
478 rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
479 transfer_memory_size, process_handle, *process,
480 applet_resource_user_id, session_id);
481}
482
483void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
484 AudioCore::AudioRendererParameterInternal params;
485
486 IPC::RequestParser rp{ctx};
487 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
488
489 u64 size{0};
490 auto result = impl->GetWorkBufferSize(params, size);
491
492 std::string output_info{};
493 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
494 output_info +=
495 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
496 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
497 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
498 output_info += fmt::format(
499 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
500 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
501 "Context {:04X}",
502 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
503 params.splitter_destinations, params.voices, params.perf_frames,
504 params.external_context_size);
505
506 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
507 output_info, size);
508
509 IPC::ResponseBuilder rb{ctx, 4};
510 rb.Push(result);
511 rb.Push<u64>(size);
512}
513
514void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
515 IPC::RequestParser rp{ctx};
516
517 const auto applet_resource_user_id = rp.Pop<u64>();
518
519 LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522
523 rb.Push(ResultSuccess);
524 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
525 ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
526}
527
528void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
529 LOG_ERROR(Service_Audio, "called. Implement me!");
530}
531
532void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
533 struct Parameters {
534 u32 revision;
535 u64 applet_resource_user_id;
536 };
537
538 IPC::RequestParser rp{ctx};
539
540 const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
541
542 LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
543 AudioCore::GetRevisionNum(revision), applet_resource_user_id);
544
545 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
546
547 rb.Push(ResultSuccess);
548 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
549 num_audio_devices++);
550}
551
552} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
deleted file mode 100644
index 3d7993a16..000000000
--- a/src/core/hle/service/audio/audren_u.h
+++ /dev/null
@@ -1,35 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_render_manager.h"
7#include "common/scratch_buffer.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Audio {
16class IAudioRenderer;
17
18class AudRenU final : public ServiceFramework<AudRenU> {
19public:
20 explicit AudRenU(Core::System& system_);
21 ~AudRenU() override;
22
23private:
24 void OpenAudioRenderer(HLERequestContext& ctx);
25 void GetWorkBufferSize(HLERequestContext& ctx);
26 void GetAudioDeviceService(HLERequestContext& ctx);
27 void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
28 void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
29
30 KernelHelpers::ServiceContext service_context;
31 std::unique_ptr<AudioCore::Renderer::Manager> impl;
32 u32 num_audio_devices{0};
33};
34
35} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/final_output_recorder_manager.cpp
index bc55cec17..f70a0e62d 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_u.h" 4#include "core/hle/service/audio/final_output_recorder_manager.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
@@ -30,13 +30,14 @@ public:
30 } 30 }
31}; 31};
32 32
33AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} { 33IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
34 : ServiceFramework{system_, "audrec:u"} {
34 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
35 {0, nullptr, "OpenFinalOutputRecorder"}, 36 {0, nullptr, "OpenFinalOutputRecorder"},
36 }; 37 };
37 RegisterHandlers(functions); 38 RegisterHandlers(functions);
38} 39}
39 40
40AudRecU::~AudRecU() = default; 41IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
41 42
42} // namespace Service::Audio 43} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/final_output_recorder_manager.h
index 9edf89f6c..0663b894e 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecA final : public ServiceFramework<AudRecA> { 14class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
15public: 15public:
16 explicit AudRecA(Core::System& system_); 16 explicit IFinalOutputRecorderManager(Core::System& system_);
17 ~AudRecA() override; 17 ~IFinalOutputRecorderManager() override;
18}; 18};
19 19
20} // namespace Service::Audio 20} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
index fa82e9ac7..7e2e42bbe 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
@@ -1,11 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_a.h" 4#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
8AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { 8IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
9 : ServiceFramework{system_, "audrec:a"} {
9 // clang-format off 10 // clang-format off
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, nullptr, "RequestSuspend"}, 12 {0, nullptr, "RequestSuspend"},
@@ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"}
16 RegisterHandlers(functions); 17 RegisterHandlers(functions);
17} 18}
18 19
19AudRecA::~AudRecA() = default; 20IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
20 21
21} // namespace Service::Audio 22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
index 8b4817884..27940f7e0 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
@@ -11,10 +11,11 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecU final : public ServiceFramework<AudRecU> { 14class IFinalOutputRecorderManagerForApplet final
15 : public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
15public: 16public:
16 explicit AudRecU(Core::System& system_); 17 explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
17 ~AudRecU() override; 18 ~IFinalOutputRecorderManagerForApplet() override;
18}; 19};
19 20
20} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.cpp b/src/core/hle/service/audio/hardware_opus_decoder.cpp
new file mode 100644
index 000000000..03d3374c1
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.cpp
@@ -0,0 +1,145 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8
9using namespace AudioCore::OpusDecoder;
10
11IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
12 : ServiceFramework{system_, "IHardwareOpusDecoder"},
13 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"},
17 {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"},
18 {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"},
19 {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"},
20 {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"},
21 {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"},
22 {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"},
23 {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
24 {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"},
25 {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IHardwareOpusDecoder::~IHardwareOpusDecoder() = default;
33
34Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params,
35 Kernel::KTransferMemory* transfer_memory,
36 u64 transfer_memory_size) {
37 return impl->Initialize(params, transfer_memory, transfer_memory_size);
38}
39
40Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
41 Kernel::KTransferMemory* transfer_memory,
42 u64 transfer_memory_size) {
43 return impl->Initialize(params, transfer_memory, transfer_memory_size);
44}
45
46Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
47 Out<u32> out_data_size, Out<u32> out_sample_count,
48 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
49 R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data,
50 false));
51 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
52 *out_sample_count);
53 R_SUCCEED();
54}
55
56Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
57 LOG_DEBUG(Service_Audio, "called");
58 R_RETURN(impl->SetContext(decoder_context));
59}
60
61Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld(
62 OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size,
63 Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) {
64 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data,
65 out_pcm_data, false));
66 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
67 *out_sample_count);
68 R_SUCCEED();
69}
70
71Result IHardwareOpusDecoder::SetContextForMultiStream(
72 InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
73 LOG_DEBUG(Service_Audio, "called");
74 R_RETURN(impl->SetContext(decoder_context));
75}
76
77Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld(
78 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
79 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
80 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
81 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
82 out_pcm_data, false));
83 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
84 *out_sample_count, *out_time_taken);
85 R_SUCCEED();
86}
87
88Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld(
89 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
90 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
91 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
92 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
93 opus_data, out_pcm_data, false));
94 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
95 *out_sample_count, *out_time_taken);
96 R_SUCCEED();
97}
98
99Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld(
100 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
101 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
102 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
103 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
104 out_pcm_data, reset));
105 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
106 *out_data_size, *out_sample_count, *out_time_taken);
107 R_SUCCEED();
108}
109
110Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld(
111 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
112 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
113 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
114 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
115 opus_data, out_pcm_data, reset));
116 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
117 *out_data_size, *out_sample_count, *out_time_taken);
118 R_SUCCEED();
119}
120
121Result IHardwareOpusDecoder::DecodeInterleaved(
122 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
123 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
124 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
125 bool reset) {
126 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
127 out_pcm_data, reset));
128 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
129 *out_data_size, *out_sample_count, *out_time_taken);
130 R_SUCCEED();
131}
132
133Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream(
134 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
135 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
136 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
137 bool reset) {
138 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
139 opus_data, out_pcm_data, reset));
140 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
141 *out_data_size, *out_sample_count, *out_time_taken);
142 R_SUCCEED();
143}
144
145} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.h b/src/core/hle/service/audio/hardware_opus_decoder.h
new file mode 100644
index 000000000..511bf46bd
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
13public:
14 explicit IHardwareOpusDecoder(Core::System& system_,
15 AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
16 ~IHardwareOpusDecoder() override;
17
18 Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
19 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
20 Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
22
23private:
24 Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
25 Out<u32> out_data_size, Out<u32> out_sample_count,
26 InBuffer<BufferAttr_HipcMapAlias> opus_data);
27 Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
28 Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
29 Out<u32> out_data_size, Out<u32> out_sample_count,
30 InBuffer<BufferAttr_HipcMapAlias> opus_data);
31 Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
32 Result DecodeInterleavedWithPerfOld(
33 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
34 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
35 InBuffer<BufferAttr_HipcMapAlias> opus_data);
36 Result DecodeInterleavedForMultiStreamWithPerfOld(
37 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
38 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
39 InBuffer<BufferAttr_HipcMapAlias> opus_data);
40 Result DecodeInterleavedWithPerfAndResetOld(
41 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
42 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
43 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
44 Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
45 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
46 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
47 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
48 Result DecodeInterleaved(
49 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
50 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
51 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
52 bool reset);
53 Result DecodeInterleavedForMultiStream(
54 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
55 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
56 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
57 bool reset);
58
59 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
60 Common::ScratchBuffer<u8> output_data;
61};
62
63} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
new file mode 100644
index 000000000..9de72e30f
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
@@ -0,0 +1,156 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
6#include "core/hle/service/cmif_serialization.h"
7
8namespace Service::Audio {
9
10using namespace AudioCore::OpusDecoder;
11
12IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
13 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
17 {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
18 {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
19 {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
20 {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
21 {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
22 {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
23 {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
24 {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
25 {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
26 };
27 // clang-format on
28 RegisterHandlers(functions);
29}
30
31IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;
32
33Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
34 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
35 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
36 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
37 params.sample_rate, params.channel_count, tmem_size);
38
39 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
40 OpusParametersEx ex{
41 .sample_rate = params.sample_rate,
42 .channel_count = params.channel_count,
43 .use_large_frame_size = false,
44 };
45 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
46
47 *out_decoder = decoder;
48 R_SUCCEED();
49}
50
51Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
52 R_TRY(impl.GetWorkBufferSize(params, *out_size));
53 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
54 params.sample_rate, params.channel_count, *out_size);
55 R_SUCCEED();
56}
57
58Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
59 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
60 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
61 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
62 LOG_DEBUG(Service_Audio,
63 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
64 "transfer_memory_size {:#x}",
65 params->sample_rate, params->channel_count, params->total_stream_count,
66 params->stereo_stream_count, tmem_size);
67
68 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
69
70 OpusMultiStreamParametersEx ex{
71 .sample_rate = params->sample_rate,
72 .channel_count = params->channel_count,
73 .total_stream_count = params->total_stream_count,
74 .stereo_stream_count = params->stereo_stream_count,
75 .use_large_frame_size = false,
76 .mappings{},
77 };
78 std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
79 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
80
81 *out_decoder = decoder;
82 R_SUCCEED();
83}
84
85Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
86 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
87 R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
88 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
89 R_SUCCEED();
90}
91
92Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
93 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
94 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
95 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
96 params.sample_rate, params.channel_count, tmem_size);
97
98 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
99 R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));
100
101 *out_decoder = decoder;
102 R_SUCCEED();
103}
104
105Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
106 OpusParametersEx params) {
107 R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
108 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
109 R_SUCCEED();
110}
111
112Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
113 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
114 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
115 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
116 LOG_DEBUG(Service_Audio,
117 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
118 "use_large_frame_size {}"
119 "transfer_memory_size {:#x}",
120 params->sample_rate, params->channel_count, params->total_stream_count,
121 params->stereo_stream_count, params->use_large_frame_size, tmem_size);
122
123 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
124
125 R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));
126
127 *out_decoder = decoder;
128 R_SUCCEED();
129}
130
131Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
132 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
133 R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
134 LOG_DEBUG(Service_Audio,
135 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
136 "use_large_frame_size {} -- returned size {:#x}",
137 params->sample_rate, params->channel_count, params->total_stream_count,
138 params->stereo_stream_count, params->use_large_frame_size, *out_size);
139 R_SUCCEED();
140}
141
142Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
143 OpusParametersEx params) {
144 R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
145 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
146 R_SUCCEED();
147}
148
149Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
150 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
151 R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
152 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
153 R_SUCCEED();
154}
155
156} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.h b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
new file mode 100644
index 000000000..4f869c517
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder;
13
14using AudioCore::OpusDecoder::OpusMultiStreamParameters;
15using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
16using AudioCore::OpusDecoder::OpusParameters;
17using AudioCore::OpusDecoder::OpusParametersEx;
18
19class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
20public:
21 explicit IHardwareOpusDecoderManager(Core::System& system_);
22 ~IHardwareOpusDecoderManager() override;
23
24private:
25 Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
26 OpusParameters params, u32 tmem_size,
27 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
28 Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
29 Result OpenHardwareOpusDecoderForMultiStream(
30 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
31 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
32 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
33 Result GetWorkBufferSizeForMultiStream(
34 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
35 Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
36 OpusParametersEx params, u32 tmem_size,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
38 Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
39 Result OpenHardwareOpusDecoderForMultiStreamEx(
40 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
41 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
42 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
43 Result GetWorkBufferSizeForMultiStreamEx(
44 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
45 Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
46 Result GetWorkBufferSizeForMultiStreamExEx(
47 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
48
49 Core::System& system;
50 AudioCore::OpusDecoder::OpusDecoderManager impl;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
deleted file mode 100644
index 91f33aabd..000000000
--- a/src/core/hle/service/audio/hwopus.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5#include <vector>
6
7#include "audio_core/opus/decoder.h"
8#include "audio_core/opus/parameters.h"
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/scratch_buffer.h"
12#include "core/core.h"
13#include "core/hle/service/audio/hwopus.h"
14#include "core/hle/service/ipc_helpers.h"
15
16namespace Service::Audio {
17using namespace AudioCore::OpusDecoder;
18
19class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
20public:
21 explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
22 : ServiceFramework{system_, "IHardwareOpusDecoder"},
23 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
24 // clang-format off
25 static const FunctionInfo functions[] = {
26 {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"},
27 {1, &IHardwareOpusDecoder::SetContext, "SetContext"},
28 {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"},
29 {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"},
30 {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
31 {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"},
32 {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"},
33 {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
34 {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"},
35 {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40 }
41
42 Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
43 u64 transfer_memory_size) {
44 return impl->Initialize(params, transfer_memory, transfer_memory_size);
45 }
46
47 Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
48 u64 transfer_memory_size) {
49 return impl->Initialize(params, transfer_memory, transfer_memory_size);
50 }
51
52private:
53 void DecodeInterleavedOld(HLERequestContext& ctx) {
54 IPC::RequestParser rp{ctx};
55
56 auto input_data{ctx.ReadBuffer(0)};
57 output_data.resize_destructive(ctx.GetWriteBufferSize());
58
59 u32 size{};
60 u32 sample_count{};
61 auto result =
62 impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false);
63
64 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
65
66 ctx.WriteBuffer(output_data);
67
68 IPC::ResponseBuilder rb{ctx, 4};
69 rb.Push(result);
70 rb.Push(size);
71 rb.Push(sample_count);
72 }
73
74 void SetContext(HLERequestContext& ctx) {
75 IPC::RequestParser rp{ctx};
76
77 LOG_DEBUG(Service_Audio, "called");
78
79 auto input_data{ctx.ReadBuffer(0)};
80 auto result = impl->SetContext(input_data);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(result);
84 }
85
86 void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) {
87 IPC::RequestParser rp{ctx};
88
89 auto input_data{ctx.ReadBuffer(0)};
90 output_data.resize_destructive(ctx.GetWriteBufferSize());
91
92 u32 size{};
93 u32 sample_count{};
94 auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count,
95 input_data, output_data, false);
96
97 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
98
99 ctx.WriteBuffer(output_data);
100
101 IPC::ResponseBuilder rb{ctx, 4};
102 rb.Push(result);
103 rb.Push(size);
104 rb.Push(sample_count);
105 }
106
107 void SetContextForMultiStream(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109
110 LOG_DEBUG(Service_Audio, "called");
111
112 auto input_data{ctx.ReadBuffer(0)};
113 auto result = impl->SetContext(input_data);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
120 IPC::RequestParser rp{ctx};
121
122 auto input_data{ctx.ReadBuffer(0)};
123 output_data.resize_destructive(ctx.GetWriteBufferSize());
124
125 u32 size{};
126 u32 sample_count{};
127 u64 time_taken{};
128 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
129 output_data, false);
130
131 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
132 sample_count, time_taken);
133
134 ctx.WriteBuffer(output_data);
135
136 IPC::ResponseBuilder rb{ctx, 6};
137 rb.Push(result);
138 rb.Push(size);
139 rb.Push(sample_count);
140 rb.Push(time_taken);
141 }
142
143 void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) {
144 IPC::RequestParser rp{ctx};
145
146 auto input_data{ctx.ReadBuffer(0)};
147 output_data.resize_destructive(ctx.GetWriteBufferSize());
148
149 u32 size{};
150 u32 sample_count{};
151 u64 time_taken{};
152 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
153 input_data, output_data, false);
154
155 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
156 sample_count, time_taken);
157
158 ctx.WriteBuffer(output_data);
159
160 IPC::ResponseBuilder rb{ctx, 6};
161 rb.Push(result);
162 rb.Push(size);
163 rb.Push(sample_count);
164 rb.Push(time_taken);
165 }
166
167 void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) {
168 IPC::RequestParser rp{ctx};
169
170 auto reset{rp.Pop<bool>()};
171
172 auto input_data{ctx.ReadBuffer(0)};
173 output_data.resize_destructive(ctx.GetWriteBufferSize());
174
175 u32 size{};
176 u32 sample_count{};
177 u64 time_taken{};
178 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
179 output_data, reset);
180
181 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
182 reset, size, sample_count, time_taken);
183
184 ctx.WriteBuffer(output_data);
185
186 IPC::ResponseBuilder rb{ctx, 6};
187 rb.Push(result);
188 rb.Push(size);
189 rb.Push(sample_count);
190 rb.Push(time_taken);
191 }
192
193 void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) {
194 IPC::RequestParser rp{ctx};
195
196 auto reset{rp.Pop<bool>()};
197
198 auto input_data{ctx.ReadBuffer(0)};
199 output_data.resize_destructive(ctx.GetWriteBufferSize());
200
201 u32 size{};
202 u32 sample_count{};
203 u64 time_taken{};
204 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
205 input_data, output_data, reset);
206
207 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
208 reset, size, sample_count, time_taken);
209
210 ctx.WriteBuffer(output_data);
211
212 IPC::ResponseBuilder rb{ctx, 6};
213 rb.Push(result);
214 rb.Push(size);
215 rb.Push(sample_count);
216 rb.Push(time_taken);
217 }
218
219 void DecodeInterleaved(HLERequestContext& ctx) {
220 IPC::RequestParser rp{ctx};
221
222 auto reset{rp.Pop<bool>()};
223
224 auto input_data{ctx.ReadBuffer(0)};
225 output_data.resize_destructive(ctx.GetWriteBufferSize());
226
227 u32 size{};
228 u32 sample_count{};
229 u64 time_taken{};
230 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
231 output_data, reset);
232
233 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
234 reset, size, sample_count, time_taken);
235
236 ctx.WriteBuffer(output_data);
237
238 IPC::ResponseBuilder rb{ctx, 6};
239 rb.Push(result);
240 rb.Push(size);
241 rb.Push(sample_count);
242 rb.Push(time_taken);
243 }
244
245 void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
246 IPC::RequestParser rp{ctx};
247
248 auto reset{rp.Pop<bool>()};
249
250 auto input_data{ctx.ReadBuffer(0)};
251 output_data.resize_destructive(ctx.GetWriteBufferSize());
252
253 u32 size{};
254 u32 sample_count{};
255 u64 time_taken{};
256 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
257 input_data, output_data, reset);
258
259 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
260 reset, size, sample_count, time_taken);
261
262 ctx.WriteBuffer(output_data);
263
264 IPC::ResponseBuilder rb{ctx, 6};
265 rb.Push(result);
266 rb.Push(size);
267 rb.Push(sample_count);
268 rb.Push(time_taken);
269 }
270
271 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
272 Common::ScratchBuffer<u8> output_data;
273};
274
275void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx};
277
278 auto params = rp.PopRaw<OpusParameters>();
279 auto transfer_memory_size{rp.Pop<u32>()};
280 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
281 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
282
283 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
284 params.sample_rate, params.channel_count, transfer_memory_size);
285
286 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
287
288 OpusParametersEx ex{
289 .sample_rate = params.sample_rate,
290 .channel_count = params.channel_count,
291 .use_large_frame_size = false,
292 };
293 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
294
295 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
296 rb.Push(result);
297 rb.PushIpcInterface(decoder);
298}
299
300void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
301 IPC::RequestParser rp{ctx};
302 auto params = rp.PopRaw<OpusParameters>();
303
304 u64 size{};
305 auto result = impl.GetWorkBufferSize(params, size);
306
307 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}",
308 params.sample_rate, params.channel_count, size);
309
310 IPC::ResponseBuilder rb{ctx, 4};
311 rb.Push(result);
312 rb.Push(size);
313}
314
315void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
316 IPC::RequestParser rp{ctx};
317
318 auto input{ctx.ReadBuffer()};
319 OpusMultiStreamParameters params;
320 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
321
322 auto transfer_memory_size{rp.Pop<u32>()};
323 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
324 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
325
326 LOG_DEBUG(Service_Audio,
327 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
328 "transfer_memory_size 0x{:X}",
329 params.sample_rate, params.channel_count, params.total_stream_count,
330 params.stereo_stream_count, transfer_memory_size);
331
332 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
333
334 OpusMultiStreamParametersEx ex{
335 .sample_rate = params.sample_rate,
336 .channel_count = params.channel_count,
337 .total_stream_count = params.total_stream_count,
338 .stereo_stream_count = params.stereo_stream_count,
339 .use_large_frame_size = false,
340 .mappings{},
341 };
342 std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings));
343 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
344
345 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
346 rb.Push(result);
347 rb.PushIpcInterface(decoder);
348}
349
350void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352
353 auto input{ctx.ReadBuffer()};
354 OpusMultiStreamParameters params;
355 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
356
357 u64 size{};
358 auto result = impl.GetWorkBufferSizeForMultiStream(params, size);
359
360 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
361
362 IPC::ResponseBuilder rb{ctx, 4};
363 rb.Push(result);
364 rb.Push(size);
365}
366
367void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
368 IPC::RequestParser rp{ctx};
369
370 auto params = rp.PopRaw<OpusParametersEx>();
371 auto transfer_memory_size{rp.Pop<u32>()};
372 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
373 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
374
375 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
376 params.sample_rate, params.channel_count, transfer_memory_size);
377
378 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
379
380 auto result =
381 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
382
383 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
384 rb.Push(result);
385 rb.PushIpcInterface(decoder);
386}
387
388void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx};
390 auto params = rp.PopRaw<OpusParametersEx>();
391
392 u64 size{};
393 auto result = impl.GetWorkBufferSizeEx(params, size);
394
395 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
396
397 IPC::ResponseBuilder rb{ctx, 4};
398 rb.Push(result);
399 rb.Push(size);
400}
401
402void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
403 IPC::RequestParser rp{ctx};
404
405 auto input{ctx.ReadBuffer()};
406 OpusMultiStreamParametersEx params;
407 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
408
409 auto transfer_memory_size{rp.Pop<u32>()};
410 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
411 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
412
413 LOG_DEBUG(Service_Audio,
414 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
415 "use_large_frame_size {}"
416 "transfer_memory_size 0x{:X}",
417 params.sample_rate, params.channel_count, params.total_stream_count,
418 params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size);
419
420 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
421
422 auto result =
423 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
424
425 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
426 rb.Push(result);
427 rb.PushIpcInterface(decoder);
428}
429
430void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
431 IPC::RequestParser rp{ctx};
432
433 auto input{ctx.ReadBuffer()};
434 OpusMultiStreamParametersEx params;
435 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
436
437 u64 size{};
438 auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size);
439
440 LOG_DEBUG(Service_Audio,
441 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
442 "use_large_frame_size {} -- returned size 0x{:X}",
443 params.sample_rate, params.channel_count, params.total_stream_count,
444 params.stereo_stream_count, params.use_large_frame_size, size);
445
446 IPC::ResponseBuilder rb{ctx, 4};
447 rb.Push(result);
448 rb.Push(size);
449}
450
451void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) {
452 IPC::RequestParser rp{ctx};
453 auto params = rp.PopRaw<OpusParametersEx>();
454
455 u64 size{};
456 auto result = impl.GetWorkBufferSizeExEx(params, size);
457
458 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
459
460 IPC::ResponseBuilder rb{ctx, 4};
461 rb.Push(result);
462 rb.Push(size);
463}
464
465void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) {
466 IPC::RequestParser rp{ctx};
467
468 auto input{ctx.ReadBuffer()};
469 OpusMultiStreamParametersEx params;
470 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
471
472 u64 size{};
473 auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size);
474
475 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
476
477 IPC::ResponseBuilder rb{ctx, 4};
478 rb.Push(result);
479 rb.Push(size);
480}
481
482HwOpus::HwOpus(Core::System& system_)
483 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
484 static const FunctionInfo functions[] = {
485 {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
486 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
487 {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"},
488 {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"},
489 {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
490 {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
491 {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
492 "OpenHardwareOpusDecoderForMultiStreamEx"},
493 {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
494 {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"},
495 {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"},
496 };
497 RegisterHandlers(functions);
498}
499
500HwOpus::~HwOpus() = default;
501
502} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
deleted file mode 100644
index d3960065e..000000000
--- a/src/core/hle/service/audio/hwopus.h
+++ /dev/null
@@ -1,36 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Audio {
14
15class HwOpus final : public ServiceFramework<HwOpus> {
16public:
17 explicit HwOpus(Core::System& system_);
18 ~HwOpus() override;
19
20private:
21 void OpenHardwareOpusDecoder(HLERequestContext& ctx);
22 void GetWorkBufferSize(HLERequestContext& ctx);
23 void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx);
24 void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx);
25 void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
26 void GetWorkBufferSizeEx(HLERequestContext& ctx);
27 void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
28 void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
29 void GetWorkBufferSizeExEx(HLERequestContext& ctx);
30 void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx);
31
32 Core::System& system;
33 AudioCore::OpusDecoder::OpusDecoderManager impl;
34};
35
36} // namespace Service::Audio
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 38cdd57ad..83618a956 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/btdrv/btdrv.h" 7#include "core/hle/service/btdrv/btdrv.h"
8#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/ipc_helpers.h" 9#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/server_manager.h" 11#include "core/hle/service/server_manager.h"
@@ -13,9 +14,9 @@
13 14
14namespace Service::BtDrv { 15namespace Service::BtDrv {
15 16
16class Bt final : public ServiceFramework<Bt> { 17class IBluetoothUser final : public ServiceFramework<IBluetoothUser> {
17public: 18public:
18 explicit Bt(Core::System& system_) 19 explicit IBluetoothUser(Core::System& system_)
19 : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} { 20 : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} {
20 // clang-format off 21 // clang-format off
21 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
@@ -28,7 +29,7 @@ public:
28 {6, nullptr, "SetLeResponse"}, 29 {6, nullptr, "SetLeResponse"},
29 {7, nullptr, "LeSendIndication"}, 30 {7, nullptr, "LeSendIndication"},
30 {8, nullptr, "GetLeEventInfo"}, 31 {8, nullptr, "GetLeEventInfo"},
31 {9, &Bt::RegisterBleEvent, "RegisterBleEvent"}, 32 {9, C<&IBluetoothUser::RegisterBleEvent>, "RegisterBleEvent"},
32 }; 33 };
33 // clang-format on 34 // clang-format on
34 RegisterHandlers(functions); 35 RegisterHandlers(functions);
@@ -36,17 +37,16 @@ public:
36 register_event = service_context.CreateEvent("BT:RegisterEvent"); 37 register_event = service_context.CreateEvent("BT:RegisterEvent");
37 } 38 }
38 39
39 ~Bt() override { 40 ~IBluetoothUser() override {
40 service_context.CloseEvent(register_event); 41 service_context.CloseEvent(register_event);
41 } 42 }
42 43
43private: 44private:
44 void RegisterBleEvent(HLERequestContext& ctx) { 45 Result RegisterBleEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
45 LOG_WARNING(Service_BTM, "(STUBBED) called"); 46 LOG_WARNING(Service_BTM, "(STUBBED) called");
46 47
47 IPC::ResponseBuilder rb{ctx, 2, 1}; 48 *out_event = &register_event->GetReadableEvent();
48 rb.Push(ResultSuccess); 49 R_SUCCEED();
49 rb.PushCopyObjects(register_event->GetReadableEvent());
50 } 50 }
51 51
52 KernelHelpers::ServiceContext service_context; 52 KernelHelpers::ServiceContext service_context;
@@ -54,9 +54,9 @@ private:
54 Kernel::KEvent* register_event; 54 Kernel::KEvent* register_event;
55}; 55};
56 56
57class BtDrv final : public ServiceFramework<BtDrv> { 57class IBluetoothDriver final : public ServiceFramework<IBluetoothDriver> {
58public: 58public:
59 explicit BtDrv(Core::System& system_) : ServiceFramework{system_, "btdrv"} { 59 explicit IBluetoothDriver(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
60 // clang-format off 60 // clang-format off
61 static const FunctionInfo functions[] = { 61 static const FunctionInfo functions[] = {
62 {0, nullptr, "InitializeBluetoothDriver"}, 62 {0, nullptr, "InitializeBluetoothDriver"},
@@ -93,7 +93,7 @@ public:
93 {31, nullptr, "EnableMcMode"}, 93 {31, nullptr, "EnableMcMode"},
94 {32, nullptr, "EnableLlrScan"}, 94 {32, nullptr, "EnableLlrScan"},
95 {33, nullptr, "DisableLlrScan"}, 95 {33, nullptr, "DisableLlrScan"},
96 {34, nullptr, "EnableRadio"}, 96 {34, C<&IBluetoothDriver::EnableRadio>, "EnableRadio"},
97 {35, nullptr, "SetVisibility"}, 97 {35, nullptr, "SetVisibility"},
98 {36, nullptr, "EnableTbfcScan"}, 98 {36, nullptr, "EnableTbfcScan"},
99 {37, nullptr, "RegisterHidReportEvent"}, 99 {37, nullptr, "RegisterHidReportEvent"},
@@ -195,13 +195,19 @@ public:
195 195
196 RegisterHandlers(functions); 196 RegisterHandlers(functions);
197 } 197 }
198
199private:
200 Result EnableRadio() {
201 LOG_WARNING(Service_BTDRV, "(STUBBED) called");
202 R_SUCCEED();
203 }
198}; 204};
199 205
200void LoopProcess(Core::System& system) { 206void LoopProcess(Core::System& system) {
201 auto server_manager = std::make_unique<ServerManager>(system); 207 auto server_manager = std::make_unique<ServerManager>(system);
202 208
203 server_manager->RegisterNamedService("btdrv", std::make_shared<BtDrv>(system)); 209 server_manager->RegisterNamedService("btdrv", std::make_shared<IBluetoothDriver>(system));
204 server_manager->RegisterNamedService("bt", std::make_shared<Bt>(system)); 210 server_manager->RegisterNamedService("bt", std::make_shared<IBluetoothUser>(system));
205 ServerManager::RunServer(std::move(server_manager)); 211 ServerManager::RunServer(std::move(server_manager));
206} 212}
207 213
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 2dc23e674..d120dade8 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -3,141 +3,18 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm.h" 6#include "core/hle/service/btm/btm.h"
10#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/btm/btm_debug.h"
11#include "core/hle/service/kernel_helpers.h" 8#include "core/hle/service/btm/btm_system.h"
9#include "core/hle/service/btm/btm_user.h"
12#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
13#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
14 12
15namespace Service::BTM { 13namespace Service::BTM {
16 14
17class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 15class IBtm final : public ServiceFramework<IBtm> {
18public: 16public:
19 explicit IBtmUserCore(Core::System& system_) 17 explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} {
20 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
24 {1, nullptr, "GetBleScanFilterParameter"},
25 {2, nullptr, "GetBleScanFilterParameter2"},
26 {3, nullptr, "StartBleScanForGeneral"},
27 {4, nullptr, "StopBleScanForGeneral"},
28 {5, nullptr, "GetBleScanResultsForGeneral"},
29 {6, nullptr, "StartBleScanForPaired"},
30 {7, nullptr, "StopBleScanForPaired"},
31 {8, nullptr, "StartBleScanForSmartDevice"},
32 {9, nullptr, "StopBleScanForSmartDevice"},
33 {10, nullptr, "GetBleScanResultsForSmartDevice"},
34 {17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"},
35 {18, nullptr, "BleConnect"},
36 {19, nullptr, "BleDisconnect"},
37 {20, nullptr, "BleGetConnectionState"},
38 {21, nullptr, "AcquireBlePairingEvent"},
39 {22, nullptr, "BlePairDevice"},
40 {23, nullptr, "BleUnPairDevice"},
41 {24, nullptr, "BleUnPairDevice2"},
42 {25, nullptr, "BleGetPairedDevices"},
43 {26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"},
44 {27, nullptr, "GetGattServices"},
45 {28, nullptr, "GetGattService"},
46 {29, nullptr, "GetGattIncludedServices"},
47 {30, nullptr, "GetBelongingGattService"},
48 {31, nullptr, "GetGattCharacteristics"},
49 {32, nullptr, "GetGattDescriptors"},
50 {33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"},
51 {34, nullptr, "ConfigureBleMtu"},
52 {35, nullptr, "GetBleMtu"},
53 {36, nullptr, "RegisterBleGattDataPath"},
54 {37, nullptr, "UnregisterBleGattDataPath"},
55 };
56 // clang-format on
57 RegisterHandlers(functions);
58
59 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
60 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
61 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
62 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
63 }
64
65 ~IBtmUserCore() override {
66 service_context.CloseEvent(scan_event);
67 service_context.CloseEvent(connection_event);
68 service_context.CloseEvent(service_discovery_event);
69 service_context.CloseEvent(config_event);
70 }
71
72private:
73 void AcquireBleScanEvent(HLERequestContext& ctx) {
74 LOG_WARNING(Service_BTM, "(STUBBED) called");
75
76 IPC::ResponseBuilder rb{ctx, 3, 1};
77 rb.Push(ResultSuccess);
78 rb.Push(true);
79 rb.PushCopyObjects(scan_event->GetReadableEvent());
80 }
81
82 void AcquireBleConnectionEvent(HLERequestContext& ctx) {
83 LOG_WARNING(Service_BTM, "(STUBBED) called");
84
85 IPC::ResponseBuilder rb{ctx, 3, 1};
86 rb.Push(ResultSuccess);
87 rb.Push(true);
88 rb.PushCopyObjects(connection_event->GetReadableEvent());
89 }
90
91 void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) {
92 LOG_WARNING(Service_BTM, "(STUBBED) called");
93
94 IPC::ResponseBuilder rb{ctx, 3, 1};
95 rb.Push(ResultSuccess);
96 rb.Push(true);
97 rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
98 }
99
100 void AcquireBleMtuConfigEvent(HLERequestContext& ctx) {
101 LOG_WARNING(Service_BTM, "(STUBBED) called");
102
103 IPC::ResponseBuilder rb{ctx, 3, 1};
104 rb.Push(ResultSuccess);
105 rb.Push(true);
106 rb.PushCopyObjects(config_event->GetReadableEvent());
107 }
108
109 KernelHelpers::ServiceContext service_context;
110
111 Kernel::KEvent* scan_event;
112 Kernel::KEvent* connection_event;
113 Kernel::KEvent* service_discovery_event;
114 Kernel::KEvent* config_event;
115};
116
117class BTM_USR final : public ServiceFramework<BTM_USR> {
118public:
119 explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
120 // clang-format off
121 static const FunctionInfo functions[] = {
122 {0, &BTM_USR::GetCore, "GetCore"},
123 };
124 // clang-format on
125 RegisterHandlers(functions);
126 }
127
128private:
129 void GetCore(HLERequestContext& ctx) {
130 LOG_WARNING(Service_BTM, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<IBtmUserCore>(system);
135 }
136};
137
138class BTM final : public ServiceFramework<BTM> {
139public:
140 explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} {
141 // clang-format off 18 // clang-format off
142 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
143 {0, nullptr, "GetState"}, 20 {0, nullptr, "GetState"},
@@ -232,144 +109,13 @@ public:
232 } 109 }
233}; 110};
234 111
235class BTM_DBG final : public ServiceFramework<BTM_DBG> {
236public:
237 explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
238 // clang-format off
239 static const FunctionInfo functions[] = {
240 {0, nullptr, "AcquireDiscoveryEvent"},
241 {1, nullptr, "StartDiscovery"},
242 {2, nullptr, "CancelDiscovery"},
243 {3, nullptr, "GetDeviceProperty"},
244 {4, nullptr, "CreateBond"},
245 {5, nullptr, "CancelBond"},
246 {6, nullptr, "SetTsiMode"},
247 {7, nullptr, "GeneralTest"},
248 {8, nullptr, "HidConnect"},
249 {9, nullptr, "GeneralGet"},
250 {10, nullptr, "GetGattClientDisconnectionReason"},
251 {11, nullptr, "GetBleConnectionParameter"},
252 {12, nullptr, "GetBleConnectionParameterRequest"},
253 {13, nullptr, "Unknown13"},
254 };
255 // clang-format on
256
257 RegisterHandlers(functions);
258 }
259};
260
261class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
262public:
263 explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
264 // clang-format off
265 static const FunctionInfo functions[] = {
266 {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
267 {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
268 {2, nullptr, "ClearGamepadPairingDatabase"},
269 {3, nullptr, "GetPairedGamepadCount"},
270 {4, nullptr, "EnableRadio"},
271 {5, nullptr, "DisableRadio"},
272 {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
273 {7, nullptr, "AcquireRadioEvent"},
274 {8, nullptr, "AcquireGamepadPairingEvent"},
275 {9, nullptr, "IsGamepadPairingStarted"},
276 {10, nullptr, "StartAudioDeviceDiscovery"},
277 {11, nullptr, "StopAudioDeviceDiscovery"},
278 {12, nullptr, "IsDiscoveryingAudioDevice"},
279 {13, nullptr, "GetDiscoveredAudioDevice"},
280 {14, nullptr, "AcquireAudioDeviceConnectionEvent"},
281 {15, nullptr, "ConnectAudioDevice"},
282 {16, nullptr, "IsConnectingAudioDevice"},
283 {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
284 {18, nullptr, "DisconnectAudioDevice"},
285 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
286 {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"},
287 {21, nullptr, "RemoveAudioDevicePairing"},
288 {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
289 {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
290 };
291 // clang-format on
292
293 RegisterHandlers(functions);
294 }
295
296private:
297 void IsRadioEnabled(HLERequestContext& ctx) {
298 LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
299
300 IPC::ResponseBuilder rb{ctx, 3};
301 rb.Push(ResultSuccess);
302 rb.Push(true);
303 }
304
305 void StartGamepadPairing(HLERequestContext& ctx) {
306 LOG_WARNING(Service_BTM, "(STUBBED) called");
307 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(ResultSuccess);
309 }
310
311 void CancelGamepadPairing(HLERequestContext& ctx) {
312 LOG_WARNING(Service_BTM, "(STUBBED) called");
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(ResultSuccess);
315 }
316
317 void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
318 LOG_WARNING(Service_BTM, "(STUBBED) called");
319 IPC::ResponseBuilder rb{ctx, 2};
320 rb.Push(ResultSuccess);
321 }
322
323 void GetConnectedAudioDevices(HLERequestContext& ctx) {
324 LOG_WARNING(Service_BTM, "(STUBBED) called");
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(ResultSuccess);
327 rb.Push<u32>(0);
328 }
329
330 void GetPairedAudioDevices(HLERequestContext& ctx) {
331 LOG_WARNING(Service_BTM, "(STUBBED) called");
332 IPC::ResponseBuilder rb{ctx, 3};
333 rb.Push(ResultSuccess);
334 rb.Push<u32>(0);
335 }
336
337 void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
338 LOG_WARNING(Service_BTM, "(STUBBED) called");
339 IPC::ResponseBuilder rb{ctx, 2};
340 rb.Push(ResultSuccess);
341 }
342};
343
344class BTM_SYS final : public ServiceFramework<BTM_SYS> {
345public:
346 explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
347 // clang-format off
348 static const FunctionInfo functions[] = {
349 {0, &BTM_SYS::GetCore, "GetCore"},
350 };
351 // clang-format on
352
353 RegisterHandlers(functions);
354 }
355
356private:
357 void GetCore(HLERequestContext& ctx) {
358 LOG_WARNING(Service_BTM, "called");
359
360 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
361 rb.Push(ResultSuccess);
362 rb.PushIpcInterface<IBtmSystemCore>(system);
363 }
364};
365
366void LoopProcess(Core::System& system) { 112void LoopProcess(Core::System& system) {
367 auto server_manager = std::make_unique<ServerManager>(system); 113 auto server_manager = std::make_unique<ServerManager>(system);
368 114
369 server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system)); 115 server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system));
370 server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system)); 116 server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system));
371 server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system)); 117 server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system));
372 server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system)); 118 server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system));
373 ServerManager::RunServer(std::move(server_manager)); 119 ServerManager::RunServer(std::move(server_manager));
374} 120}
375 121
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
index a99b34364..0bf77d053 100644
--- a/src/core/hle/service/btm/btm.h
+++ b/src/core/hle/service/btm/btm.h
@@ -3,10 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6namespace Service::SM {
7class ServiceManager;
8}
9
10namespace Core { 6namespace Core {
11class System; 7class System;
12}; 8};
diff --git a/src/core/hle/service/btm/btm_debug.cpp b/src/core/hle/service/btm/btm_debug.cpp
new file mode 100644
index 000000000..4d61d2641
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/btm/btm_debug.h"
5
6namespace Service::BTM {
7
8IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AcquireDiscoveryEvent"},
12 {1, nullptr, "StartDiscovery"},
13 {2, nullptr, "CancelDiscovery"},
14 {3, nullptr, "GetDeviceProperty"},
15 {4, nullptr, "CreateBond"},
16 {5, nullptr, "CancelBond"},
17 {6, nullptr, "SetTsiMode"},
18 {7, nullptr, "GeneralTest"},
19 {8, nullptr, "HidConnect"},
20 {9, nullptr, "GeneralGet"},
21 {10, nullptr, "GetGattClientDisconnectionReason"},
22 {11, nullptr, "GetBleConnectionParameter"},
23 {12, nullptr, "GetBleConnectionParameterRequest"},
24 {13, nullptr, "Unknown13"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29}
30
31IBtmDebug::~IBtmDebug() = default;
32
33} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_debug.h b/src/core/hle/service/btm/btm_debug.h
new file mode 100644
index 000000000..bf4f7e14f
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14
15class IBtmDebug final : public ServiceFramework<IBtmDebug> {
16public:
17 explicit IBtmDebug(Core::System& system_);
18 ~IBtmDebug() override;
19};
20
21} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.cpp b/src/core/hle/service/btm/btm_system.cpp
new file mode 100644
index 000000000..99718a7b0
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system.h"
6#include "core/hle/service/btm/btm_system_core.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/service.h"
9
10namespace Service::BTM {
11
12IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, C<&IBtmSystem::GetCore>, "GetCore"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IBtmSystem::~IBtmSystem() = default;
23
24Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) {
25 LOG_WARNING(Service_BTM, "called");
26
27 *out_interface = std::make_shared<IBtmSystemCore>(system);
28 R_SUCCEED();
29}
30
31} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.h b/src/core/hle/service/btm/btm_system.h
new file mode 100644
index 000000000..fe1c6dbd7
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmSystemCore;
15
16class IBtmSystem final : public ServiceFramework<IBtmSystem> {
17public:
18 explicit IBtmSystem(Core::System& system_);
19 ~IBtmSystem() override;
20
21private:
22 Result GetCore(OutInterface<IBtmSystemCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.cpp b/src/core/hle/service/btm/btm_system_core.cpp
new file mode 100644
index 000000000..4bc8a9e8b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system_core.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/set/system_settings_server.h"
8#include "core/hle/service/sm/sm.h"
9
10namespace Service::BTM {
11
12IBtmSystemCore::IBtmSystemCore(Core::System& system_)
13 : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"},
17 {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"},
18 {2, nullptr, "ClearGamepadPairingDatabase"},
19 {3, nullptr, "GetPairedGamepadCount"},
20 {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"},
21 {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"},
22 {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"},
23 {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"},
24 {8, nullptr, "AcquireGamepadPairingEvent"},
25 {9, nullptr, "IsGamepadPairingStarted"},
26 {10, nullptr, "StartAudioDeviceDiscovery"},
27 {11, nullptr, "StopAudioDeviceDiscovery"},
28 {12, nullptr, "IsDiscoveryingAudioDevice"},
29 {13, nullptr, "GetDiscoveredAudioDevice"},
30 {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
31 {15, nullptr, "ConnectAudioDevice"},
32 {16, nullptr, "IsConnectingAudioDevice"},
33 {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"},
34 {18, nullptr, "DisconnectAudioDevice"},
35 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
36 {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"},
37 {21, nullptr, "RemoveAudioDevicePairing"},
38 {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"},
39 {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"}
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44 radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent");
45 audio_device_connection_event =
46 service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent");
47
48 m_set_sys =
49 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
50}
51
52IBtmSystemCore::~IBtmSystemCore() {
53 service_context.CloseEvent(radio_event);
54 service_context.CloseEvent(audio_device_connection_event);
55}
56
57Result IBtmSystemCore::StartGamepadPairing() {
58 LOG_WARNING(Service_BTM, "(STUBBED) called");
59 R_SUCCEED();
60}
61
62Result IBtmSystemCore::CancelGamepadPairing() {
63 LOG_WARNING(Service_BTM, "(STUBBED) called");
64 R_SUCCEED();
65}
66
67Result IBtmSystemCore::EnableRadio() {
68 LOG_DEBUG(Service_BTM, "called");
69
70 R_RETURN(m_set_sys->SetBluetoothEnableFlag(true));
71}
72Result IBtmSystemCore::DisableRadio() {
73 LOG_DEBUG(Service_BTM, "called");
74
75 R_RETURN(m_set_sys->SetBluetoothEnableFlag(false));
76}
77
78Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) {
79 LOG_DEBUG(Service_BTM, "called");
80
81 R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled));
82}
83
84Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
85 OutCopyHandle<Kernel::KReadableEvent> out_event) {
86 LOG_WARNING(Service_BTM, "(STUBBED) called");
87
88 *out_is_valid = true;
89 *out_event = &radio_event->GetReadableEvent();
90 R_SUCCEED();
91}
92
93Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
94 OutCopyHandle<Kernel::KReadableEvent> out_event) {
95 LOG_WARNING(Service_BTM, "(STUBBED) called");
96
97 *out_event = &audio_device_connection_event->GetReadableEvent();
98 R_SUCCEED();
99}
100
101Result IBtmSystemCore::GetConnectedAudioDevices(
102 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
103 LOG_WARNING(Service_BTM, "(STUBBED) called");
104
105 *out_count = 0;
106 R_SUCCEED();
107}
108
109Result IBtmSystemCore::GetPairedAudioDevices(
110 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
111 LOG_WARNING(Service_BTM, "(STUBBED) called");
112
113 *out_count = 0;
114 R_SUCCEED();
115}
116
117Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
118 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
119 R_SUCCEED();
120}
121
122Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
123 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
124 R_SUCCEED();
125}
126
127} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.h b/src/core/hle/service/btm/btm_system_core.h
new file mode 100644
index 000000000..06498b21e
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.h
@@ -0,0 +1,60 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::Set {
20class ISystemSettingsServer;
21}
22
23namespace Service::BTM {
24
25class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
26public:
27 explicit IBtmSystemCore(Core::System& system_);
28 ~IBtmSystemCore() override;
29
30private:
31 Result StartGamepadPairing();
32 Result CancelGamepadPairing();
33 Result EnableRadio();
34 Result DisableRadio();
35 Result IsRadioEnabled(Out<bool> out_is_enabled);
36
37 Result AcquireRadioEvent(Out<bool> out_is_valid,
38 OutCopyHandle<Kernel::KReadableEvent> out_event);
39
40 Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
41
42 Result GetConnectedAudioDevices(
43 Out<s32> out_count,
44 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
45
46 Result GetPairedAudioDevices(
47 Out<s32> out_count,
48 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
49
50 Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
51 Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
52
53 KernelHelpers::ServiceContext service_context;
54
55 Kernel::KEvent* radio_event;
56 Kernel::KEvent* audio_device_connection_event;
57 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
58};
59
60} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.cpp b/src/core/hle/service/btm/btm_user.cpp
new file mode 100644
index 000000000..d2e228f8d
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_user.h"
6#include "core/hle/service/btm/btm_user_core.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::BTM {
10
11IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&IBtmUser::GetCore>, "GetCore"},
15 };
16 // clang-format on
17
18 RegisterHandlers(functions);
19}
20
21IBtmUser::~IBtmUser() = default;
22
23Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) {
24 LOG_WARNING(Service_BTM, "called");
25
26 *out_interface = std::make_shared<IBtmUserCore>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.h b/src/core/hle/service/btm/btm_user.h
new file mode 100644
index 000000000..d9ee5db45
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmUserCore;
15
16class IBtmUser final : public ServiceFramework<IBtmUser> {
17public:
18 explicit IBtmUser(Core::System& system_);
19 ~IBtmUser() override;
20
21private:
22 Result GetCore(OutInterface<IBtmUserCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.cpp b/src/core/hle/service/btm/btm_user_core.cpp
new file mode 100644
index 000000000..6f9fa589b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.cpp
@@ -0,0 +1,103 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm_user_core.h"
10#include "core/hle/service/cmif_serialization.h"
11
12namespace Service::BTM {
13
14IBtmUserCore::IBtmUserCore(Core::System& system_)
15 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, C<&IBtmUserCore::AcquireBleScanEvent>, "AcquireBleScanEvent"},
19 {1, nullptr, "GetBleScanFilterParameter"},
20 {2, nullptr, "GetBleScanFilterParameter2"},
21 {3, nullptr, "StartBleScanForGeneral"},
22 {4, nullptr, "StopBleScanForGeneral"},
23 {5, nullptr, "GetBleScanResultsForGeneral"},
24 {6, nullptr, "StartBleScanForPaired"},
25 {7, nullptr, "StopBleScanForPaired"},
26 {8, nullptr, "StartBleScanForSmartDevice"},
27 {9, nullptr, "StopBleScanForSmartDevice"},
28 {10, nullptr, "GetBleScanResultsForSmartDevice"},
29 {17, C<&IBtmUserCore::AcquireBleConnectionEvent>, "AcquireBleConnectionEvent"},
30 {18, nullptr, "BleConnect"},
31 {19, nullptr, "BleDisconnect"},
32 {20, nullptr, "BleGetConnectionState"},
33 {21, nullptr, "AcquireBlePairingEvent"},
34 {22, nullptr, "BlePairDevice"},
35 {23, nullptr, "BleUnPairDevice"},
36 {24, nullptr, "BleUnPairDevice2"},
37 {25, nullptr, "BleGetPairedDevices"},
38 {26, C<&IBtmUserCore::AcquireBleServiceDiscoveryEvent>, "AcquireBleServiceDiscoveryEvent"},
39 {27, nullptr, "GetGattServices"},
40 {28, nullptr, "GetGattService"},
41 {29, nullptr, "GetGattIncludedServices"},
42 {30, nullptr, "GetBelongingGattService"},
43 {31, nullptr, "GetGattCharacteristics"},
44 {32, nullptr, "GetGattDescriptors"},
45 {33, C<&IBtmUserCore::AcquireBleMtuConfigEvent>, "AcquireBleMtuConfigEvent"},
46 {34, nullptr, "ConfigureBleMtu"},
47 {35, nullptr, "GetBleMtu"},
48 {36, nullptr, "RegisterBleGattDataPath"},
49 {37, nullptr, "UnregisterBleGattDataPath"},
50 };
51 // clang-format on
52 RegisterHandlers(functions);
53
54 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
55 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
56 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
57 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
58}
59
60IBtmUserCore::~IBtmUserCore() {
61 service_context.CloseEvent(scan_event);
62 service_context.CloseEvent(connection_event);
63 service_context.CloseEvent(service_discovery_event);
64 service_context.CloseEvent(config_event);
65}
66
67Result IBtmUserCore::AcquireBleScanEvent(Out<bool> out_is_valid,
68 OutCopyHandle<Kernel::KReadableEvent> out_event) {
69 LOG_WARNING(Service_BTM, "(STUBBED) called");
70
71 *out_is_valid = true;
72 *out_event = &scan_event->GetReadableEvent();
73 R_SUCCEED();
74}
75
76Result IBtmUserCore::AcquireBleConnectionEvent(Out<bool> out_is_valid,
77 OutCopyHandle<Kernel::KReadableEvent> out_event) {
78 LOG_WARNING(Service_BTM, "(STUBBED) called");
79
80 *out_is_valid = true;
81 *out_event = &connection_event->GetReadableEvent();
82 R_SUCCEED();
83}
84
85Result IBtmUserCore::AcquireBleServiceDiscoveryEvent(
86 Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event) {
87 LOG_WARNING(Service_BTM, "(STUBBED) called");
88
89 *out_is_valid = true;
90 *out_event = &service_discovery_event->GetReadableEvent();
91 R_SUCCEED();
92}
93
94Result IBtmUserCore::AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
95 OutCopyHandle<Kernel::KReadableEvent> out_event) {
96 LOG_WARNING(Service_BTM, "(STUBBED) called");
97
98 *out_is_valid = true;
99 *out_event = &config_event->GetReadableEvent();
100 R_SUCCEED();
101}
102
103} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.h b/src/core/hle/service/btm/btm_user_core.h
new file mode 100644
index 000000000..dc0a22e81
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::BTM {
20
21class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
22public:
23 explicit IBtmUserCore(Core::System& system_);
24 ~IBtmUserCore() override;
25
26private:
27 Result AcquireBleScanEvent(Out<bool> out_is_valid,
28 OutCopyHandle<Kernel::KReadableEvent> out_event);
29
30 Result AcquireBleConnectionEvent(Out<bool> out_is_valid,
31 OutCopyHandle<Kernel::KReadableEvent> out_event);
32
33 Result AcquireBleServiceDiscoveryEvent(Out<bool> out_is_valid,
34 OutCopyHandle<Kernel::KReadableEvent> out_event);
35
36 Result AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
37 OutCopyHandle<Kernel::KReadableEvent> out_event);
38
39 KernelHelpers::ServiceContext service_context;
40
41 Kernel::KEvent* scan_event;
42 Kernel::KEvent* connection_event;
43 Kernel::KEvent* service_discovery_event;
44 Kernel::KEvent* config_event;
45};
46
47} // namespace Service::BTM
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index f24682c34..5a5f610f3 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -415,7 +415,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
415 auto& buffer = temp[OutBufferIndex]; 415 auto& buffer = temp[OutBufferIndex];
416 const size_t size = buffer.size(); 416 const size_t size = buffer.size();
417 417
418 if (ctx.CanWriteBuffer(OutBufferIndex)) { 418 if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); 420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { 421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
index 39690018b..8483394d0 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -3,82 +3,34 @@
3 3
4#include "core/file_sys/fs_filesystem.h" 4#include "core/file_sys/fs_filesystem.h"
5#include "core/file_sys/savedata_factory.h" 5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
7#include "core/hle/service/ipc_helpers.h"
8 8
9namespace Service::FileSystem { 9namespace Service::FileSystem {
10 10
11template <typename T> 11IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
12static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
13 const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
14 entries.reserve(entries.size() + new_data.size());
15
16 for (const auto& new_entry : new_data) {
17 auto name = new_entry->GetName();
18
19 if (type == FileSys::DirectoryEntryType::File &&
20 name == FileSys::GetSaveDataSizeFileName()) {
21 continue;
22 }
23
24 entries.emplace_back(name, static_cast<s8>(type),
25 type == FileSys::DirectoryEntryType::Directory ? 0
26 : new_entry->GetSize());
27 }
28}
29
30IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
31 FileSys::OpenDirectoryMode mode) 12 FileSys::OpenDirectoryMode mode)
32 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 13 : ServiceFramework{system_, "IDirectory"},
14 backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
33 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
34 {0, &IDirectory::Read, "Read"}, 16 {0, D<&IDirectory::Read>, "Read"},
35 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 17 {1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
36 }; 18 };
37 RegisterHandlers(functions); 19 RegisterHandlers(functions);
38
39 // TODO(DarkLordZach): Verify that this is the correct behavior.
40 // Build entry index now to save time later.
41 if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
42 BuildEntryIndex(entries, backend->GetSubdirectories(),
43 FileSys::DirectoryEntryType::Directory);
44 }
45 if (True(mode & FileSys::OpenDirectoryMode::File)) {
46 BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
47 }
48} 20}
49 21
50void IDirectory::Read(HLERequestContext& ctx) { 22Result IDirectory::Read(
23 Out<s64> out_count,
24 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
51 LOG_DEBUG(Service_FS, "called."); 25 LOG_DEBUG(Service_FS, "called.");
52 26
53 // Calculate how many entries we can fit in the output buffer 27 R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
54 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
55
56 // Cap at total number of entries.
57 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
58
59 // Determine data start and end
60 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
61 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
62 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
63
64 next_entry_index += actual_entries;
65
66 // Write the data to memory
67 ctx.WriteBuffer(begin, range_size);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(ResultSuccess);
71 rb.Push(actual_entries);
72} 28}
73 29
74void IDirectory::GetEntryCount(HLERequestContext& ctx) { 30Result IDirectory::GetEntryCount(Out<s64> out_count) {
75 LOG_DEBUG(Service_FS, "called"); 31 LOG_DEBUG(Service_FS, "called");
76 32
77 u64 count = entries.size() - next_entry_index; 33 R_RETURN(backend->GetEntryCount(out_count));
78
79 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(ResultSuccess);
81 rb.Push(count);
82} 34}
83 35
84} // namespace Service::FileSystem 36} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
index 793ecfcd7..b6251f7fd 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_directory.h"
6#include "core/file_sys/vfs/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 9#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
9 11
@@ -15,16 +17,15 @@ namespace Service::FileSystem {
15 17
16class IDirectory final : public ServiceFramework<IDirectory> { 18class IDirectory final : public ServiceFramework<IDirectory> {
17public: 19public:
18 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, 20 explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
19 FileSys::OpenDirectoryMode mode); 21 FileSys::OpenDirectoryMode mode);
20 22
21private: 23private:
22 FileSys::VirtualDir backend; 24 std::unique_ptr<FileSys::Fsa::IDirectory> backend;
23 std::vector<FileSys::DirectoryEntry> entries;
24 u64 next_entry_index = 0;
25 25
26 void Read(HLERequestContext& ctx); 26 Result Read(Out<s64> out_count,
27 void GetEntryCount(HLERequestContext& ctx); 27 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
28 Result GetEntryCount(Out<s64> out_count);
28}; 29};
29 30
30} // namespace Service::FileSystem 31} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
index 9a18f6ec5..a355d46ae 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -2,126 +2,64 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h" 6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) 10IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"}, 14 {0, D<&IFile::Read>, "Read"},
14 {1, &IFile::Write, "Write"}, 15 {1, D<&IFile::Write>, "Write"},
15 {2, &IFile::Flush, "Flush"}, 16 {2, D<&IFile::Flush>, "Flush"},
16 {3, &IFile::SetSize, "SetSize"}, 17 {3, D<&IFile::SetSize>, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"}, 18 {4, D<&IFile::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 19 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"}, 20 {6, nullptr, "OperateRangeWithBuffer"},
20 }; 21 };
22 // clang-format on
21 RegisterHandlers(functions); 23 RegisterHandlers(functions);
22} 24}
23 25
24void IFile::Read(HLERequestContext& ctx) { 26Result IFile::Read(
25 IPC::RequestParser rp{ctx}; 27 FileSys::ReadOption option, Out<s64> out_size, s64 offset,
26 const u64 option = rp.Pop<u64>(); 28 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
27 const s64 offset = rp.Pop<s64>(); 29 s64 size) {
28 const s64 length = rp.Pop<s64>(); 30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
29 31 size);
30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
31
32 // Error checking
33 if (length < 0) {
34 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
35 IPC::ResponseBuilder rb{ctx, 2};
36 rb.Push(FileSys::ResultInvalidSize);
37 return;
38 }
39 if (offset < 0) {
40 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(FileSys::ResultInvalidOffset);
43 return;
44 }
45 32
46 // Read the data from the Storage backend 33 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset); 34 R_RETURN(
48 35 backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
49 // Write the data to memory
50 ctx.WriteBuffer(output);
51
52 IPC::ResponseBuilder rb{ctx, 4};
53 rb.Push(ResultSuccess);
54 rb.Push(static_cast<u64>(output.size()));
55} 36}
56 37
57void IFile::Write(HLERequestContext& ctx) { 38Result IFile::Write(
58 IPC::RequestParser rp{ctx}; 39 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
59 const u64 option = rp.Pop<u64>(); 40 FileSys::WriteOption option, s64 offset, s64 size) {
60 const s64 offset = rp.Pop<s64>(); 41 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
61 const s64 length = rp.Pop<s64>(); 42 size);
62
63 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
64
65 // Error checking
66 if (length < 0) {
67 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(FileSys::ResultInvalidSize);
70 return;
71 }
72 if (offset < 0) {
73 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(FileSys::ResultInvalidOffset);
76 return;
77 }
78
79 const auto data = ctx.ReadBuffer();
80 43
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length, 44 R_RETURN(backend->Write(offset, buffer.data(), size, option));
82 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
83 length, data.size());
84
85 // Write the data to the Storage backend
86 const auto write_size =
87 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
88 const std::size_t written = backend->Write(data.data(), write_size, offset);
89
90 ASSERT_MSG(static_cast<s64>(written) == length,
91 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
92 written);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96} 45}
97 46
98void IFile::Flush(HLERequestContext& ctx) { 47Result IFile::Flush() {
99 LOG_DEBUG(Service_FS, "called"); 48 LOG_DEBUG(Service_FS, "called");
100 49
101 // Exists for SDK compatibiltity -- No need to flush file. 50 R_RETURN(backend->Flush());
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105} 51}
106 52
107void IFile::SetSize(HLERequestContext& ctx) { 53Result IFile::SetSize(s64 size) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size); 54 LOG_DEBUG(Service_FS, "called, size={}", size);
111 55
112 backend->Resize(size); 56 R_RETURN(backend->SetSize(size));
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116} 57}
117 58
118void IFile::GetSize(HLERequestContext& ctx) { 59Result IFile::GetSize(Out<s64> out_size) {
119 const u64 size = backend->GetSize(); 60 LOG_DEBUG(Service_FS, "called");
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121 61
122 IPC::ResponseBuilder rb{ctx, 4}; 62 R_RETURN(backend->GetSize(out_size));
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125} 63}
126 64
127} // namespace Service::FileSystem 65} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
index 5e5430c67..e8599ee2f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_file.h"
7#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
@@ -10,16 +12,21 @@ namespace Service::FileSystem {
10 12
11class IFile final : public ServiceFramework<IFile> { 13class IFile final : public ServiceFramework<IFile> {
12public: 14public:
13 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); 15 explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
14 16
15private: 17private:
16 FileSys::VirtualFile backend; 18 std::unique_ptr<FileSys::Fsa::IFile> backend;
17 19
18 void Read(HLERequestContext& ctx); 20 Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
19 void Write(HLERequestContext& ctx); 21 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
20 void Flush(HLERequestContext& ctx); 22 out_buffer,
21 void SetSize(HLERequestContext& ctx); 23 s64 size);
22 void GetSize(HLERequestContext& ctx); 24 Result Write(
25 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
26 FileSys::WriteOption option, s64 offset, s64 size);
27 Result Flush();
28 Result SetSize(s64 size);
29 Result GetSize(Out<s64> out_size);
23}; 30};
24 31
25} // namespace Service::FileSystem 32} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
index efa394dd1..d881e144d 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -2,261 +2,172 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/string_util.h" 4#include "common/string_util.h"
5#include "core/file_sys/fssrv/fssrv_sf_path.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h" 8#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 9#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9 10
10namespace Service::FileSystem { 11namespace Service::FileSystem {
11 12
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 13IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 14 : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
14 size_)} { 15 dir_)},
16 size_getter{std::move(size_getter_)} {
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"}, 18 {0, D<&IFileSystem::CreateFile>, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 19 {1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, 20 {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, 21 {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, 22 {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"}, 23 {5, D<&IFileSystem::RenameFile>, "RenameFile"},
22 {6, nullptr, "RenameDirectory"}, 24 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"}, 25 {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"}, 26 {8, D<&IFileSystem::OpenFile>, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, 27 {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"}, 28 {10, D<&IFileSystem::Commit>, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, 29 {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, 30 {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, 31 {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, 32 {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"}, 33 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, 34 {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
33 }; 35 };
34 RegisterHandlers(functions); 36 RegisterHandlers(functions);
35} 37}
36 38
37void IFileSystem::CreateFile(HLERequestContext& ctx) { 39Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
38 IPC::RequestParser rp{ctx}; 40 s32 option, s64 size) {
41 LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
39 42
40 const auto file_buffer = ctx.ReadBuffer(); 43 R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
41 const std::string name = Common::StringFromBuffer(file_buffer);
42
43 const u64 file_mode = rp.Pop<u64>();
44 const u32 file_size = rp.Pop<u32>();
45
46 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
47 file_size);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(backend.CreateFile(name, file_size));
51} 44}
52 45
53void IFileSystem::DeleteFile(HLERequestContext& ctx) { 46Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
54 const auto file_buffer = ctx.ReadBuffer(); 47 LOG_DEBUG(Service_FS, "called. file={}", path->str);
55 const std::string name = Common::StringFromBuffer(file_buffer);
56 48
57 LOG_DEBUG(Service_FS, "called. file={}", name); 49 R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61} 50}
62 51
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) { 52Result IFileSystem::CreateDirectory(
64 const auto file_buffer = ctx.ReadBuffer(); 53 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
65 const std::string name = Common::StringFromBuffer(file_buffer); 54 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68 55
69 IPC::ResponseBuilder rb{ctx, 2}; 56 R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
70 rb.Push(backend.CreateDirectory(name));
71} 57}
72 58
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { 59Result IFileSystem::DeleteDirectory(
74 const auto file_buffer = ctx.ReadBuffer(); 60 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
75 const std::string name = Common::StringFromBuffer(file_buffer); 61 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78 62
79 IPC::ResponseBuilder rb{ctx, 2}; 63 R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
80 rb.Push(backend.DeleteDirectory(name));
81} 64}
82 65
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { 66Result IFileSystem::DeleteDirectoryRecursively(
84 const auto file_buffer = ctx.ReadBuffer(); 67 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
85 const std::string name = Common::StringFromBuffer(file_buffer); 68 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
86 69
87 LOG_DEBUG(Service_FS, "called. directory={}", name); 70 R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91} 71}
92 72
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { 73Result IFileSystem::CleanDirectoryRecursively(
94 const auto file_buffer = ctx.ReadBuffer(); 74 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
95 const std::string name = Common::StringFromBuffer(file_buffer); 75 LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98 76
99 IPC::ResponseBuilder rb{ctx, 2}; 77 R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
100 rb.Push(backend.CleanDirectoryRecursively(name));
101} 78}
102 79
103void IFileSystem::RenameFile(HLERequestContext& ctx) { 80Result IFileSystem::RenameFile(
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); 81 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); 82 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
106 83 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108 84
109 IPC::ResponseBuilder rb{ctx, 2}; 85 R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
110 rb.Push(backend.RenameFile(src_name, dst_name));
111} 86}
112 87
113void IFileSystem::OpenFile(HLERequestContext& ctx) { 88Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
114 IPC::RequestParser rp{ctx}; 89 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
115 90 u32 mode) {
116 const auto file_buffer = ctx.ReadBuffer(); 91 LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
117 const std::string name = Common::StringFromBuffer(file_buffer);
118
119 const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
120
121 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
122 92
123 FileSys::VirtualFile vfs_file{}; 93 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode); 94 R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
125 if (result != ResultSuccess) { 95 static_cast<FileSys::OpenMode>(mode)));
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(result);
128 return;
129 }
130
131 auto file = std::make_shared<IFile>(system, vfs_file);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(ResultSuccess);
135 rb.PushIpcInterface<IFile>(std::move(file));
136}
137
138void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 96
141 const auto file_buffer = ctx.ReadBuffer(); 97 *out_interface = std::make_shared<IFile>(system, vfs_file);
142 const std::string name = Common::StringFromBuffer(file_buffer); 98 R_SUCCEED();
143 const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); 99}
144 100
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); 101Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
102 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
103 u32 mode) {
104 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
146 105
147 FileSys::VirtualDir vfs_dir{}; 106 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name); 107 R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
149 if (result != ResultSuccess) { 108 static_cast<FileSys::OpenDirectoryMode>(mode)));
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(result);
152 return;
153 }
154
155 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(ResultSuccess);
159 rb.PushIpcInterface<IDirectory>(std::move(directory));
160}
161 109
162void IFileSystem::GetEntryType(HLERequestContext& ctx) { 110 *out_interface = std::make_shared<IDirectory>(system, vfs_dir,
163 const auto file_buffer = ctx.ReadBuffer(); 111 static_cast<FileSys::OpenDirectoryMode>(mode));
164 const std::string name = Common::StringFromBuffer(file_buffer); 112 R_SUCCEED();
113}
165 114
166 LOG_DEBUG(Service_FS, "called. file={}", name); 115Result IFileSystem::GetEntryType(
116 Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
117 LOG_DEBUG(Service_FS, "called. file={}", path->str);
167 118
168 FileSys::DirectoryEntryType vfs_entry_type{}; 119 FileSys::DirectoryEntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name); 120 R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
170 if (result != ResultSuccess) { 121
171 IPC::ResponseBuilder rb{ctx, 2}; 122 *out_type = static_cast<u32>(vfs_entry_type);
172 rb.Push(result); 123 R_SUCCEED();
173 return;
174 }
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
179} 124}
180 125
181void IFileSystem::Commit(HLERequestContext& ctx) { 126Result IFileSystem::Commit() {
182 LOG_WARNING(Service_FS, "(STUBBED) called"); 127 LOG_WARNING(Service_FS, "(STUBBED) called");
183 128
184 IPC::ResponseBuilder rb{ctx, 2}; 129 R_SUCCEED();
185 rb.Push(ResultSuccess);
186} 130}
187 131
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { 132Result IFileSystem::GetFreeSpaceSize(
133 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
189 LOG_DEBUG(Service_FS, "called"); 134 LOG_DEBUG(Service_FS, "called");
190 135
191 IPC::ResponseBuilder rb{ctx, 4}; 136 *out_size = size_getter.get_free_size();
192 rb.Push(ResultSuccess); 137 R_SUCCEED();
193 rb.Push(size.get_free_size());
194} 138}
195 139
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { 140Result IFileSystem::GetTotalSpaceSize(
141 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
197 LOG_DEBUG(Service_FS, "called"); 142 LOG_DEBUG(Service_FS, "called");
198 143
199 IPC::ResponseBuilder rb{ctx, 4}; 144 *out_size = size_getter.get_total_size();
200 rb.Push(ResultSuccess); 145 R_SUCCEED();
201 rb.Push(size.get_total_size());
202} 146}
203 147
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { 148Result IFileSystem::GetFileTimeStampRaw(
205 const auto file_buffer = ctx.ReadBuffer(); 149 Out<FileSys::FileTimeStampRaw> out_timestamp,
206 const std::string name = Common::StringFromBuffer(file_buffer); 150 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
207 151 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209 152
210 FileSys::FileTimeStampRaw vfs_timestamp{}; 153 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); 154 R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
212 if (result != ResultSuccess) { 155
213 IPC::ResponseBuilder rb{ctx, 2}; 156 *out_timestamp = vfs_timestamp;
214 rb.Push(result); 157 R_SUCCEED();
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221} 158}
222 159
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { 160Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
224 LOG_WARNING(Service_FS, "(STUBBED) called"); 161 LOG_WARNING(Service_FS, "(STUBBED) called");
225 162
226 struct FileSystemAttribute { 163 FileSys::FileSystemAttribute savedata_attribute{};
227 u8 dir_entry_name_length_max_defined;
228 u8 file_entry_name_length_max_defined;
229 u8 dir_path_name_length_max_defined;
230 u8 file_path_name_length_max_defined;
231 INSERT_PADDING_BYTES_NOINIT(0x5);
232 u8 utf16_dir_entry_name_length_max_defined;
233 u8 utf16_file_entry_name_length_max_defined;
234 u8 utf16_dir_path_name_length_max_defined;
235 u8 utf16_file_path_name_length_max_defined;
236 INSERT_PADDING_BYTES_NOINIT(0x18);
237 s32 dir_entry_name_length_max;
238 s32 file_entry_name_length_max;
239 s32 dir_path_name_length_max;
240 s32 file_path_name_length_max;
241 INSERT_PADDING_WORDS_NOINIT(0x5);
242 s32 utf16_dir_entry_name_length_max;
243 s32 utf16_file_entry_name_length_max;
244 s32 utf16_dir_path_name_length_max;
245 s32 utf16_file_path_name_length_max;
246 INSERT_PADDING_WORDS_NOINIT(0x18);
247 INSERT_PADDING_WORDS_NOINIT(0x1);
248 };
249 static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
250
251 FileSystemAttribute savedata_attribute{};
252 savedata_attribute.dir_entry_name_length_max_defined = true; 164 savedata_attribute.dir_entry_name_length_max_defined = true;
253 savedata_attribute.file_entry_name_length_max_defined = true; 165 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40; 166 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40; 167 savedata_attribute.file_entry_name_length_max = 0x40;
256 168
257 IPC::ResponseBuilder rb{ctx, 50}; 169 *out_attribute = savedata_attribute;
258 rb.Push(ResultSuccess); 170 R_SUCCEED();
259 rb.PushRaw(savedata_attribute);
260} 171}
261 172
262} // namespace Service::FileSystem 173} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
index b06b3ef0e..dd069f36f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -3,36 +3,58 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fsa/fs_i_filesystem.h"
6#include "core/file_sys/vfs/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h" 12#include "core/hle/service/filesystem/fsp/fsp_types.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
10 14
15namespace FileSys::Sf {
16struct Path;
17}
18
11namespace Service::FileSystem { 19namespace Service::FileSystem {
12 20
21class IFile;
22class IDirectory;
23
13class IFileSystem final : public ServiceFramework<IFileSystem> { 24class IFileSystem final : public ServiceFramework<IFileSystem> {
14public: 25public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); 26 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
16 27
17 void CreateFile(HLERequestContext& ctx); 28 Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
18 void DeleteFile(HLERequestContext& ctx); 29 s64 size);
19 void CreateDirectory(HLERequestContext& ctx); 30 Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
20 void DeleteDirectory(HLERequestContext& ctx); 31 Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx); 32 Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
22 void CleanDirectoryRecursively(HLERequestContext& ctx); 33 Result DeleteDirectoryRecursively(
23 void RenameFile(HLERequestContext& ctx); 34 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
24 void OpenFile(HLERequestContext& ctx); 35 Result CleanDirectoryRecursively(
25 void OpenDirectory(HLERequestContext& ctx); 36 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
26 void GetEntryType(HLERequestContext& ctx); 37 Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
27 void Commit(HLERequestContext& ctx); 38 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
28 void GetFreeSpaceSize(HLERequestContext& ctx); 39 Result OpenFile(OutInterface<IFile> out_interface,
29 void GetTotalSpaceSize(HLERequestContext& ctx); 40 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
30 void GetFileTimeStampRaw(HLERequestContext& ctx); 41 Result OpenDirectory(OutInterface<IDirectory> out_interface,
31 void GetFileSystemAttribute(HLERequestContext& ctx); 42 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
43 u32 mode);
44 Result GetEntryType(Out<u32> out_type,
45 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
46 Result Commit();
47 Result GetFreeSpaceSize(Out<s64> out_size,
48 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
49 Result GetTotalSpaceSize(Out<s64> out_size,
50 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
51 Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
52 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
53 Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
32 54
33private: 55private:
34 VfsDirectoryServiceWrapper backend; 56 std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
35 SizeGetter size; 57 SizeGetter size_getter;
36}; 58};
37 59
38} // namespace Service::FileSystem 60} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
new file mode 100644
index 000000000..626328234
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
6#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
7
8namespace Service::FileSystem {
9
10IMultiCommitManager::IMultiCommitManager(Core::System& system_)
11 : ServiceFramework{system_, "IMultiCommitManager"} {
12 static const FunctionInfo functions[] = {
13 {1, D<&IMultiCommitManager::Add>, "Add"},
14 {2, D<&IMultiCommitManager::Commit>, "Commit"},
15 };
16 RegisterHandlers(functions);
17}
18
19IMultiCommitManager::~IMultiCommitManager() = default;
20
21Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
22 LOG_WARNING(Service_FS, "(STUBBED) called");
23
24 R_SUCCEED();
25}
26
27Result IMultiCommitManager::Commit() {
28 LOG_WARNING(Service_FS, "(STUBBED) called");
29
30 R_SUCCEED();
31}
32
33} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
new file mode 100644
index 000000000..8ebf7c7d9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/service.h"
8
9namespace Service::FileSystem {
10
11class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
12public:
13 explicit IMultiCommitManager(Core::System& system_);
14 ~IMultiCommitManager() override;
15
16private:
17 Result Add(std::shared_ptr<IFileSystem> filesystem);
18 Result Commit();
19
20 FileSys::VirtualFile backend;
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
new file mode 100644
index 000000000..ff823586b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
@@ -0,0 +1,161 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
8#include "core/hle/service/filesystem/save_data_controller.h"
9
10namespace Service::FileSystem {
11
12ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
13 std::shared_ptr<SaveDataController> save_data_controller_,
14 FileSys::SaveDataSpaceId space)
15 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
16 save_data_controller_} {
17 static const FunctionInfo functions[] = {
18 {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
19 };
20 RegisterHandlers(functions);
21
22 FindAllSaves(space);
23}
24
25ISaveDataInfoReader::~ISaveDataInfoReader() = default;
26
27static u64 stoull_be(std::string_view str) {
28 if (str.size() != 16) {
29 return 0;
30 }
31
32 const auto bytes = Common::HexStringToArray<0x8>(str);
33 u64 out{};
34 std::memcpy(&out, bytes.data(), sizeof(u64));
35
36 return Common::swap64(out);
37}
38
39Result ISaveDataInfoReader::ReadSaveDataInfo(
40 Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
41 LOG_DEBUG(Service_FS, "called");
42
43 // Calculate how many entries we can fit in the output buffer
44 const u64 count_entries = out_entries.size();
45
46 // Cap at total number of entries.
47 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
48
49 // Determine data start and end
50 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
51 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
52 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
53
54 next_entry_index += actual_entries;
55
56 // Write the data to memory
57 std::memcpy(out_entries.data(), begin, range_size);
58 *out_count = actual_entries;
59
60 R_SUCCEED();
61}
62
63void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
64 FileSys::VirtualDir save_root{};
65 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
66
67 if (result != ResultSuccess || save_root == nullptr) {
68 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
69 return;
70 }
71
72 for (const auto& type : save_root->GetSubdirectories()) {
73 if (type->GetName() == "save") {
74 FindNormalSaves(space, type);
75 } else if (space == FileSys::SaveDataSpaceId::Temporary) {
76 FindTemporaryStorageSaves(space, type);
77 }
78 }
79}
80
81void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
82 const FileSys::VirtualDir& type) {
83 for (const auto& save_id : type->GetSubdirectories()) {
84 for (const auto& user_id : save_id->GetSubdirectories()) {
85 // Skip non user id subdirectories
86 if (user_id->GetName().size() != 0x20) {
87 continue;
88 }
89
90 const auto save_id_numeric = stoull_be(save_id->GetName());
91 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
92 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
93
94 if (save_id_numeric != 0) {
95 // System Save Data
96 info.emplace_back(SaveDataInfo{
97 0,
98 space,
99 FileSys::SaveDataType::System,
100 {},
101 user_id_numeric,
102 save_id_numeric,
103 0,
104 user_id->GetSize(),
105 {},
106 {},
107 });
108
109 continue;
110 }
111
112 for (const auto& title_id : user_id->GetSubdirectories()) {
113 const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
114 [](u8 val) { return val == 0; });
115 info.emplace_back(SaveDataInfo{
116 0,
117 space,
118 device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
119 {},
120 user_id_numeric,
121 save_id_numeric,
122 stoull_be(title_id->GetName()),
123 title_id->GetSize(),
124 {},
125 {},
126 });
127 }
128 }
129 }
130}
131
132void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
133 const FileSys::VirtualDir& type) {
134 for (const auto& user_id : type->GetSubdirectories()) {
135 // Skip non user id subdirectories
136 if (user_id->GetName().size() != 0x20) {
137 continue;
138 }
139 for (const auto& title_id : user_id->GetSubdirectories()) {
140 if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
141 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
142 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
143
144 info.emplace_back(SaveDataInfo{
145 0,
146 space,
147 FileSys::SaveDataType::Temporary,
148 {},
149 user_id_numeric,
150 stoull_be(type->GetName()),
151 stoull_be(title_id->GetName()),
152 title_id->GetSize(),
153 {},
154 {},
155 });
156 }
157 }
158 }
159}
160
161} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
new file mode 100644
index 000000000..e45ad852b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7#include "common/common_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class SaveDataController;
14
15class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
16public:
17 explicit ISaveDataInfoReader(Core::System& system_,
18 std::shared_ptr<SaveDataController> save_data_controller_,
19 FileSys::SaveDataSpaceId space);
20 ~ISaveDataInfoReader() override;
21
22 struct SaveDataInfo {
23 u64_le save_id_unknown;
24 FileSys::SaveDataSpaceId space;
25 FileSys::SaveDataType type;
26 INSERT_PADDING_BYTES(0x6);
27 std::array<u8, 0x10> user_id;
28 u64_le save_id;
29 u64_le title_id;
30 u64_le save_image_size;
31 u16_le index;
32 FileSys::SaveDataRank rank;
33 INSERT_PADDING_BYTES(0x25);
34 };
35 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
36
37 Result ReadSaveDataInfo(Out<u64> out_count,
38 OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
39
40private:
41 void FindAllSaves(FileSys::SaveDataSpaceId space);
42 void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
43 void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
44
45 std::shared_ptr<SaveDataController> save_data_controller;
46 std::vector<SaveDataInfo> info;
47 u64 next_entry_index = 0;
48};
49
50} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
index 98223c1f9..213f19808 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -2,61 +2,44 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 6#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) 10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"}, 13 {0, D<&IStorage::Read>, "Read"},
14 {1, nullptr, "Write"}, 14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"}, 15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"}, 16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"}, 17 {4, D<&IStorage::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 18 {5, nullptr, "OperateRange"},
19 }; 19 };
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23void IStorage::Read(HLERequestContext& ctx) { 23Result IStorage::Read(
24 IPC::RequestParser rp{ctx}; 24 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
25 const s64 offset = rp.Pop<s64>(); 25 s64 offset, s64 length) {
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); 26 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29 27
30 // Error checking 28 R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
31 if (length < 0) { 29 R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
32 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
33 IPC::ResponseBuilder rb{ctx, 2};
34 rb.Push(FileSys::ResultInvalidSize);
35 return;
36 }
37 if (offset < 0) {
38 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(FileSys::ResultInvalidOffset);
41 return;
42 }
43 30
44 // Read the data from the Storage backend 31 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset); 32 backend->Read(out_bytes.data(), length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48 33
49 IPC::ResponseBuilder rb{ctx, 2}; 34 R_SUCCEED();
50 rb.Push(ResultSuccess);
51} 35}
52 36
53void IStorage::GetSize(HLERequestContext& ctx) { 37Result IStorage::GetSize(Out<u64> out_size) {
54 const u64 size = backend->GetSize(); 38 *out_size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size); 39
40 LOG_DEBUG(Service_FS, "called, size={}", *out_size);
56 41
57 IPC::ResponseBuilder rb{ctx, 4}; 42 R_SUCCEED();
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60} 43}
61 44
62} // namespace Service::FileSystem 45} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
index cb5bebcc9..74d879386 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs/vfs.h" 6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
@@ -16,8 +17,10 @@ public:
16private: 17private:
17 FileSys::VirtualFile backend; 18 FileSys::VirtualFile backend;
18 19
19 void Read(HLERequestContext& ctx); 20 Result Read(
20 void GetSize(HLERequestContext& ctx); 21 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
22 s64 offset, s64 length);
23 Result GetSize(Out<u64> out_size);
21}; 24};
22 25
23} // namespace Service::FileSystem 26} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2d49f30c8..223284255 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -27,10 +27,14 @@
27#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
28#include "core/file_sys/vfs/vfs.h" 28#include "core/file_sys/vfs/vfs.h"
29#include "core/hle/result.h" 29#include "core/hle/result.h"
30#include "core/hle/service/cmif_serialization.h"
30#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
31#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 32#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
33#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
34#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
32#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 35#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
33#include "core/hle/service/filesystem/fsp/fsp_srv.h" 36#include "core/hle/service/filesystem/fsp/fsp_srv.h"
37#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
34#include "core/hle/service/filesystem/romfs_controller.h" 38#include "core/hle/service/filesystem/romfs_controller.h"
35#include "core/hle/service/filesystem/save_data_controller.h" 39#include "core/hle/service/filesystem/save_data_controller.h"
36#include "core/hle/service/hle_ipc.h" 40#include "core/hle/service/hle_ipc.h"
@@ -39,182 +43,6 @@
39#include "core/reporter.h" 43#include "core/reporter.h"
40 44
41namespace Service::FileSystem { 45namespace Service::FileSystem {
42enum class FileSystemProxyType : u8 {
43 Code = 0,
44 Rom = 1,
45 Logo = 2,
46 Control = 3,
47 Manual = 4,
48 Meta = 5,
49 Data = 6,
50 Package = 7,
51 RegisteredUpdate = 8,
52};
53
54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
55public:
56 explicit ISaveDataInfoReader(Core::System& system_,
57 std::shared_ptr<SaveDataController> save_data_controller_,
58 FileSys::SaveDataSpaceId space)
59 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
60 save_data_controller_} {
61 static const FunctionInfo functions[] = {
62 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
63 };
64 RegisterHandlers(functions);
65
66 FindAllSaves(space);
67 }
68
69 void ReadSaveDataInfo(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_FS, "called");
71
72 // Calculate how many entries we can fit in the output buffer
73 const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
74
75 // Cap at total number of entries.
76 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
77
78 // Determine data start and end
79 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
80 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
81 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
82
83 next_entry_index += actual_entries;
84
85 // Write the data to memory
86 ctx.WriteBuffer(begin, range_size);
87
88 IPC::ResponseBuilder rb{ctx, 4};
89 rb.Push(ResultSuccess);
90 rb.Push<u64>(actual_entries);
91 }
92
93private:
94 static u64 stoull_be(std::string_view str) {
95 if (str.size() != 16)
96 return 0;
97
98 const auto bytes = Common::HexStringToArray<0x8>(str);
99 u64 out{};
100 std::memcpy(&out, bytes.data(), sizeof(u64));
101
102 return Common::swap64(out);
103 }
104
105 void FindAllSaves(FileSys::SaveDataSpaceId space) {
106 FileSys::VirtualDir save_root{};
107 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
108
109 if (result != ResultSuccess || save_root == nullptr) {
110 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
111 return;
112 }
113
114 for (const auto& type : save_root->GetSubdirectories()) {
115 if (type->GetName() == "save") {
116 for (const auto& save_id : type->GetSubdirectories()) {
117 for (const auto& user_id : save_id->GetSubdirectories()) {
118 // Skip non user id subdirectories
119 if (user_id->GetName().size() != 0x20) {
120 continue;
121 }
122
123 const auto save_id_numeric = stoull_be(save_id->GetName());
124 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
125 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
126
127 if (save_id_numeric != 0) {
128 // System Save Data
129 info.emplace_back(SaveDataInfo{
130 0,
131 space,
132 FileSys::SaveDataType::SystemSaveData,
133 {},
134 user_id_numeric,
135 save_id_numeric,
136 0,
137 user_id->GetSize(),
138 {},
139 {},
140 });
141
142 continue;
143 }
144
145 for (const auto& title_id : user_id->GetSubdirectories()) {
146 const auto device =
147 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
148 [](u8 val) { return val == 0; });
149 info.emplace_back(SaveDataInfo{
150 0,
151 space,
152 device ? FileSys::SaveDataType::DeviceSaveData
153 : FileSys::SaveDataType::SaveData,
154 {},
155 user_id_numeric,
156 save_id_numeric,
157 stoull_be(title_id->GetName()),
158 title_id->GetSize(),
159 {},
160 {},
161 });
162 }
163 }
164 }
165 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
166 // Temporary Storage
167 for (const auto& user_id : type->GetSubdirectories()) {
168 // Skip non user id subdirectories
169 if (user_id->GetName().size() != 0x20) {
170 continue;
171 }
172 for (const auto& title_id : user_id->GetSubdirectories()) {
173 if (!title_id->GetFiles().empty() ||
174 !title_id->GetSubdirectories().empty()) {
175 auto user_id_numeric =
176 Common::HexStringToArray<0x10>(user_id->GetName());
177 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
178
179 info.emplace_back(SaveDataInfo{
180 0,
181 space,
182 FileSys::SaveDataType::TemporaryStorage,
183 {},
184 user_id_numeric,
185 stoull_be(type->GetName()),
186 stoull_be(title_id->GetName()),
187 title_id->GetSize(),
188 {},
189 {},
190 });
191 }
192 }
193 }
194 }
195 }
196 }
197
198 struct SaveDataInfo {
199 u64_le save_id_unknown;
200 FileSys::SaveDataSpaceId space;
201 FileSys::SaveDataType type;
202 INSERT_PADDING_BYTES(0x6);
203 std::array<u8, 0x10> user_id;
204 u64_le save_id;
205 u64_le title_id;
206 u64_le save_image_size;
207 u16_le index;
208 FileSys::SaveDataRank rank;
209 INSERT_PADDING_BYTES(0x25);
210 };
211 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
212
213 ProcessId process_id = 0;
214 std::shared_ptr<SaveDataController> save_data_controller;
215 std::vector<SaveDataInfo> info;
216 u64 next_entry_index = 0;
217};
218 46
219FSP_SRV::FSP_SRV(Core::System& system_) 47FSP_SRV::FSP_SRV(Core::System& system_)
220 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, 48 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +50,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
222 // clang-format off 50 // clang-format off
223 static const FunctionInfo functions[] = { 51 static const FunctionInfo functions[] = {
224 {0, nullptr, "OpenFileSystem"}, 52 {0, nullptr, "OpenFileSystem"},
225 {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, 53 {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
226 {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, 54 {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
227 {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, 55 {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
228 {8, nullptr, "OpenFileSystemWithId"}, 56 {8, nullptr, "OpenFileSystemWithId"},
229 {9, nullptr, "OpenDataFileSystemByApplicationId"}, 57 {9, nullptr, "OpenDataFileSystemByApplicationId"},
230 {11, nullptr, "OpenBisFileSystem"}, 58 {11, nullptr, "OpenBisFileSystem"},
231 {12, nullptr, "OpenBisStorage"}, 59 {12, nullptr, "OpenBisStorage"},
232 {13, nullptr, "InvalidateBisCache"}, 60 {13, nullptr, "InvalidateBisCache"},
233 {17, nullptr, "OpenHostFileSystem"}, 61 {17, nullptr, "OpenHostFileSystem"},
234 {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, 62 {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
235 {19, nullptr, "FormatSdCardFileSystem"}, 63 {19, nullptr, "FormatSdCardFileSystem"},
236 {21, nullptr, "DeleteSaveDataFileSystem"}, 64 {21, nullptr, "DeleteSaveDataFileSystem"},
237 {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, 65 {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
238 {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, 66 {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
239 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, 67 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
240 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, 68 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
241 {26, nullptr, "FormatSdCardDryRun"}, 69 {26, nullptr, "FormatSdCardDryRun"},
@@ -245,30 +73,30 @@ FSP_SRV::FSP_SRV(Core::System& system_)
245 {31, nullptr, "OpenGameCardFileSystem"}, 73 {31, nullptr, "OpenGameCardFileSystem"},
246 {32, nullptr, "ExtendSaveDataFileSystem"}, 74 {32, nullptr, "ExtendSaveDataFileSystem"},
247 {33, nullptr, "DeleteCacheStorage"}, 75 {33, nullptr, "DeleteCacheStorage"},
248 {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, 76 {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
249 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, 77 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
250 {36, nullptr, "OpenHostFileSystemWithOption"}, 78 {36, nullptr, "OpenHostFileSystemWithOption"},
251 {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, 79 {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
252 {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, 80 {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
253 {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, 81 {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
254 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, 82 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
255 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 83 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
256 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 84 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
257 {60, nullptr, "OpenSaveDataInfoReader"}, 85 {60, nullptr, "OpenSaveDataInfoReader"},
258 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 86 {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
259 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, 87 {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
260 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 88 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
261 {65, nullptr, "UpdateSaveDataMacForDebug"}, 89 {65, nullptr, "UpdateSaveDataMacForDebug"},
262 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 90 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
263 {67, nullptr, "FindSaveDataWithFilter"}, 91 {67, D<&FSP_SRV::FindSaveDataWithFilter>, "FindSaveDataWithFilter"},
264 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, 92 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
265 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, 93 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
266 {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, 94 {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
267 {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, 95 {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
268 {80, nullptr, "OpenSaveDataMetaFile"}, 96 {80, nullptr, "OpenSaveDataMetaFile"},
269 {81, nullptr, "OpenSaveDataTransferManager"}, 97 {81, nullptr, "OpenSaveDataTransferManager"},
270 {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, 98 {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
271 {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"}, 99 {83, D<&FSP_SRV::OpenSaveDataTransferProhibiter>, "OpenSaveDataTransferProhibiter"},
272 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, 100 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
273 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, 101 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
274 {86, nullptr, "OpenSaveDataMover"}, 102 {86, nullptr, "OpenSaveDataMover"},
@@ -279,12 +107,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
279 {110, nullptr, "OpenContentStorageFileSystem"}, 107 {110, nullptr, "OpenContentStorageFileSystem"},
280 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 108 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
281 {130, nullptr, "OpenCustomStorageFileSystem"}, 109 {130, nullptr, "OpenCustomStorageFileSystem"},
282 {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, 110 {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
283 {201, nullptr, "OpenDataStorageByProgramId"}, 111 {201, nullptr, "OpenDataStorageByProgramId"},
284 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, 112 {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
285 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, 113 {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
286 {204, nullptr, "OpenDataFileSystemByProgramIndex"}, 114 {204, nullptr, "OpenDataFileSystemByProgramIndex"},
287 {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, 115 {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
288 {206, nullptr, "OpenDataStorageByPath"}, 116 {206, nullptr, "OpenDataStorageByPath"},
289 {400, nullptr, "OpenDeviceOperator"}, 117 {400, nullptr, "OpenDeviceOperator"},
290 {500, nullptr, "OpenSdCardDetectionEventNotifier"}, 118 {500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +152,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
324 {1000, nullptr, "SetBisRootForHost"}, 152 {1000, nullptr, "SetBisRootForHost"},
325 {1001, nullptr, "SetSaveDataSize"}, 153 {1001, nullptr, "SetSaveDataSize"},
326 {1002, nullptr, "SetSaveDataRootPath"}, 154 {1002, nullptr, "SetSaveDataRootPath"},
327 {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, 155 {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
328 {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, 156 {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
329 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, 157 {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
330 {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, 158 {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
331 {1007, nullptr, "RegisterUpdatePartition"}, 159 {1007, nullptr, "RegisterUpdatePartition"},
332 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 160 {1008, nullptr, "OpenRegisteredUpdatePartition"},
333 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 161 {1009, nullptr, "GetAndClearMemoryReportInfo"},
334 {1010, nullptr, "SetDataStorageRedirectTarget"}, 162 {1010, nullptr, "SetDataStorageRedirectTarget"},
335 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, 163 {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
336 {1012, nullptr, "GetFsStackUsage"}, 164 {1012, nullptr, "GetFsStackUsage"},
337 {1013, nullptr, "UnsetSaveDataRootPath"}, 165 {1013, nullptr, "UnsetSaveDataRootPath"},
338 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 166 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
339 {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"}, 167 {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
340 {1017, nullptr, "OutputApplicationInfoAccessLog"}, 168 {1017, nullptr, "OutputApplicationInfoAccessLog"},
341 {1018, nullptr, "SetDebugOption"}, 169 {1018, nullptr, "SetDebugOption"},
342 {1019, nullptr, "UnsetDebugOption"}, 170 {1019, nullptr, "UnsetDebugOption"},
343 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 171 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
344 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 172 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
345 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 173 {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
346 {1300, nullptr, "OpenBisWiper"}, 174 {1300, nullptr, "OpenBisWiper"},
347 }; 175 };
348 // clang-format on 176 // clang-format on
@@ -355,234 +183,192 @@ FSP_SRV::FSP_SRV(Core::System& system_)
355 183
356FSP_SRV::~FSP_SRV() = default; 184FSP_SRV::~FSP_SRV() = default;
357 185
358void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { 186Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
359 current_process_id = ctx.GetPID(); 187 current_process_id = *pid;
360 188
361 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); 189 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
362 190
363 const auto res = 191 R_RETURN(
364 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); 192 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
365
366 IPC::ResponseBuilder rb{ctx, 2};
367 rb.Push(res);
368} 193}
369 194
370void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 195Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
371 IPC::RequestParser rp{ctx}; 196 FileSystemProxyType type, u64 open_program_id) {
372 197 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
373 struct InputParameters { 198 open_program_id);
374 FileSystemProxyType type;
375 u64 program_id;
376 };
377 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
378
379 const auto params = rp.PopRaw<InputParameters>();
380 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
381 params.program_id);
382 199
383 // FIXME: many issues with this 200 // FIXME: many issues with this
384 ASSERT(params.type == FileSystemProxyType::Manual); 201 ASSERT(type == FileSystemProxyType::Manual);
385 const auto manual_romfs = romfs_controller->OpenPatchedRomFS( 202 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
386 params.program_id, FileSys::ContentRecordType::HtmlDocument); 203 open_program_id, FileSys::ContentRecordType::HtmlDocument);
387 204
388 ASSERT(manual_romfs != nullptr); 205 ASSERT(manual_romfs != nullptr);
389 206
390 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); 207 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
391 ASSERT(extracted_romfs != nullptr); 208 ASSERT(extracted_romfs != nullptr);
392 209
393 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 210 *out_interface = std::make_shared<IFileSystem>(
394 rb.Push(ResultSuccess); 211 system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
395 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs, 212
396 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); 213 R_SUCCEED();
397} 214}
398 215
399void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 216Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
400 LOG_DEBUG(Service_FS, "called"); 217 LOG_DEBUG(Service_FS, "called");
401 218
402 FileSys::VirtualDir sdmc_dir{}; 219 FileSys::VirtualDir sdmc_dir{};
403 fsc.OpenSDMC(&sdmc_dir); 220 fsc.OpenSDMC(&sdmc_dir);
404 221
405 auto filesystem = std::make_shared<IFileSystem>( 222 *out_interface = std::make_shared<IFileSystem>(
406 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 223 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
407 224
408 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 225 R_SUCCEED();
409 rb.Push(ResultSuccess);
410 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
411} 226}
412 227
413void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { 228Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
414 IPC::RequestParser rp{ctx}; 229 FileSys::SaveDataAttribute save_struct, u128 uid) {
415
416 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
417 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
418 u128 uid = rp.PopRaw<u128>();
419
420 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), 230 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
421 uid[1], uid[0]); 231 uid[1], uid[0]);
422 232
423 FileSys::VirtualDir save_data_dir{}; 233 FileSys::VirtualDir save_data_dir{};
424 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, 234 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
425 save_struct); 235 save_struct));
426
427 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(ResultSuccess);
429} 236}
430 237
431void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 238Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
432 IPC::RequestParser rp{ctx}; 239 FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct) {
433
434 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
435 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
436
437 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); 240 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
438 241
439 FileSys::VirtualDir save_data_dir{}; 242 FileSys::VirtualDir save_data_dir{};
440 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, 243 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
441 save_struct); 244 save_struct));
442
443 IPC::ResponseBuilder rb{ctx, 2};
444 rb.Push(ResultSuccess);
445} 245}
446 246
447void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { 247Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
448 IPC::RequestParser rp{ctx}; 248 FileSys::SaveDataSpaceId space_id,
449 249 FileSys::SaveDataAttribute attribute) {
450 struct Parameters {
451 FileSys::SaveDataSpaceId space_id;
452 FileSys::SaveDataAttribute attribute;
453 };
454
455 const auto parameters = rp.PopRaw<Parameters>();
456
457 LOG_INFO(Service_FS, "called."); 250 LOG_INFO(Service_FS, "called.");
458 251
459 FileSys::VirtualDir dir{}; 252 FileSys::VirtualDir dir{};
460 auto result = 253 R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
461 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
462 if (result != ResultSuccess) {
463 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
464 rb.Push(FileSys::ResultTargetNotFound);
465 return;
466 }
467 254
468 FileSys::StorageId id{}; 255 FileSys::StorageId id{};
469 switch (parameters.space_id) { 256 switch (space_id) {
470 case FileSys::SaveDataSpaceId::NandUser: 257 case FileSys::SaveDataSpaceId::User:
471 id = FileSys::StorageId::NandUser; 258 id = FileSys::StorageId::NandUser;
472 break; 259 break;
473 case FileSys::SaveDataSpaceId::SdCardSystem: 260 case FileSys::SaveDataSpaceId::SdSystem:
474 case FileSys::SaveDataSpaceId::SdCardUser: 261 case FileSys::SaveDataSpaceId::SdUser:
475 id = FileSys::StorageId::SdCard; 262 id = FileSys::StorageId::SdCard;
476 break; 263 break;
477 case FileSys::SaveDataSpaceId::NandSystem: 264 case FileSys::SaveDataSpaceId::System:
478 id = FileSys::StorageId::NandSystem; 265 id = FileSys::StorageId::NandSystem;
479 break; 266 break;
480 case FileSys::SaveDataSpaceId::TemporaryStorage: 267 case FileSys::SaveDataSpaceId::Temporary:
481 case FileSys::SaveDataSpaceId::ProperSystem: 268 case FileSys::SaveDataSpaceId::ProperSystem:
482 case FileSys::SaveDataSpaceId::SafeMode: 269 case FileSys::SaveDataSpaceId::SafeMode:
483 ASSERT(false); 270 ASSERT(false);
484 } 271 }
485 272
486 auto filesystem = 273 *out_interface =
487 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); 274 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
488 275
489 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 276 R_SUCCEED();
490 rb.Push(ResultSuccess);
491 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
492} 277}
493 278
494void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 279Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
280 FileSys::SaveDataSpaceId space_id,
281 FileSys::SaveDataAttribute attribute) {
495 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 282 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
496 OpenSaveDataFileSystem(ctx); 283 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
497} 284}
498 285
499void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { 286Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
287 FileSys::SaveDataSpaceId space_id,
288 FileSys::SaveDataAttribute attribute) {
500 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 289 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
501 OpenSaveDataFileSystem(ctx); 290 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
502} 291}
503 292
504void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { 293Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
505 IPC::RequestParser rp{ctx}; 294 OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
506 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
507 LOG_INFO(Service_FS, "called, space={}", space); 295 LOG_INFO(Service_FS, "called, space={}", space);
508 296
509 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 297 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
510 rb.Push(ResultSuccess); 298
511 rb.PushIpcInterface<ISaveDataInfoReader>( 299 R_SUCCEED();
512 std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
513} 300}
514 301
515void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { 302Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
303 OutInterface<ISaveDataInfoReader> out_interface) {
516 LOG_WARNING(Service_FS, "(STUBBED) called"); 304 LOG_WARNING(Service_FS, "(STUBBED) called");
517 305
518 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 306 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
519 rb.Push(ResultSuccess); 307 FileSys::SaveDataSpaceId::Temporary);
520 rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
521 FileSys::SaveDataSpaceId::TemporaryStorage);
522}
523 308
524void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 309 R_SUCCEED();
525 LOG_WARNING(Service_FS, "(STUBBED) called."); 310}
526 311
527 IPC::ResponseBuilder rb{ctx, 2}; 312Result FSP_SRV::FindSaveDataWithFilter(Out<s64> out_count,
528 rb.Push(ResultSuccess); 313 OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
314 FileSys::SaveDataSpaceId space_id,
315 FileSys::SaveDataFilter filter) {
316 LOG_WARNING(Service_FS, "(STUBBED) called");
317 R_THROW(FileSys::ResultTargetNotFound);
529} 318}
530 319
531void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { 320Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
532 IPC::RequestParser rp{ctx}; 321 LOG_WARNING(Service_FS, "(STUBBED) called.");
533 322
534 struct Parameters { 323 R_SUCCEED();
535 FileSys::SaveDataSpaceId space_id; 324}
536 FileSys::SaveDataAttribute attribute;
537 };
538 325
539 const auto parameters = rp.PopRaw<Parameters>(); 326Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
327 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
328 InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
540 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 329 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
541 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 330 // In an earlier version of the code, this was returned as an out argument, but this is not
331 // correct
332 [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
542 333
543 LOG_WARNING(Service_FS, 334 LOG_WARNING(Service_FS,
544 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" 335 "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
545 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" 336 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
546 "attribute.type={}, attribute.rank={}, attribute.index={}", 337 "attribute.type={}, attribute.rank={}, attribute.index={}",
547 flags, parameters.space_id, parameters.attribute.title_id, 338 flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
548 parameters.attribute.user_id[1], parameters.attribute.user_id[0], 339 attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
549 parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, 340
550 parameters.attribute.index); 341 R_SUCCEED();
551
552 IPC::ResponseBuilder rb{ctx, 3};
553 rb.Push(ResultSuccess);
554 rb.Push(flags);
555} 342}
556 343
557void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { 344Result FSP_SRV::OpenSaveDataTransferProhibiter(
345 OutInterface<ISaveDataTransferProhibiter> out_prohibiter, u64 id) {
346 LOG_WARNING(Service_FS, "(STUBBED) called, id={:016X}", id);
347 *out_prohibiter = std::make_shared<ISaveDataTransferProhibiter>(system);
348 R_SUCCEED();
349}
350
351Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
558 LOG_DEBUG(Service_FS, "called"); 352 LOG_DEBUG(Service_FS, "called");
559 353
560 if (!romfs) { 354 if (!romfs) {
561 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); 355 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
562 if (!current_romfs) { 356 if (!current_romfs) {
563 // TODO (bunnei): Find the right error code to use here 357 // TODO (bunnei): Find the right error code to use here
564 LOG_CRITICAL(Service_FS, "no file system interface available!"); 358 LOG_CRITICAL(Service_FS, "No file system interface available!");
565 IPC::ResponseBuilder rb{ctx, 2}; 359 R_RETURN(ResultUnknown);
566 rb.Push(ResultUnknown);
567 return;
568 } 360 }
569 361
570 romfs = current_romfs; 362 romfs = current_romfs;
571 } 363 }
572 364
573 auto storage = std::make_shared<IStorage>(system, romfs); 365 *out_interface = std::make_shared<IStorage>(system, romfs);
574 366
575 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 367 R_SUCCEED();
576 rb.Push(ResultSuccess);
577 rb.PushIpcInterface<IStorage>(std::move(storage));
578} 368}
579 369
580void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { 370Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
581 IPC::RequestParser rp{ctx}; 371 FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
582 const auto storage_id = rp.PopRaw<FileSys::StorageId>();
583 const auto unknown = rp.PopRaw<u32>();
584 const auto title_id = rp.PopRaw<u64>();
585
586 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 372 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
587 storage_id, unknown, title_id); 373 storage_id, unknown, title_id);
588 374
@@ -592,19 +378,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
592 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 378 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
593 379
594 if (archive != nullptr) { 380 if (archive != nullptr) {
595 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 381 *out_interface = std::make_shared<IStorage>(system, archive);
596 rb.Push(ResultSuccess); 382 R_SUCCEED();
597 rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
598 return;
599 } 383 }
600 384
601 // TODO(DarkLordZach): Find the right error code to use here 385 // TODO(DarkLordZach): Find the right error code to use here
602 LOG_ERROR(Service_FS, 386 LOG_ERROR(Service_FS,
603 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 387 "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
604 storage_id); 388 storage_id);
605 IPC::ResponseBuilder rb{ctx, 2}; 389 R_RETURN(ResultUnknown);
606 rb.Push(ResultUnknown);
607 return;
608 } 390 }
609 391
610 const FileSys::PatchManager pm{title_id, fsc, content_provider}; 392 const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +396,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
614 auto storage = std::make_shared<IStorage>( 396 auto storage = std::make_shared<IStorage>(
615 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); 397 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
616 398
617 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 399 *out_interface = std::move(storage);
618 rb.Push(ResultSuccess); 400 R_SUCCEED();
619 rb.PushIpcInterface<IStorage>(std::move(storage));
620} 401}
621 402
622void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { 403Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
623 IPC::RequestParser rp{ctx}; 404 FileSys::StorageId storage_id, u64 title_id) {
624 405 LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
625 const auto storage_id = rp.PopRaw<FileSys::StorageId>(); 406 title_id);
626 const auto title_id = rp.PopRaw<u64>();
627
628 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
629 407
630 IPC::ResponseBuilder rb{ctx, 2}; 408 R_RETURN(FileSys::ResultTargetNotFound);
631 rb.Push(FileSys::ResultTargetNotFound);
632} 409}
633 410
634void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { 411Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
635 IPC::RequestParser rp{ctx}; 412 u8 program_index) {
636
637 const auto program_index = rp.PopRaw<u8>();
638
639 LOG_DEBUG(Service_FS, "called, program_index={}", program_index); 413 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
640 414
641 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( 415 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +417,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
643 417
644 if (!patched_romfs) { 418 if (!patched_romfs) {
645 // TODO: Find the right error code to use here 419 // TODO: Find the right error code to use here
646 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); 420 LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
647 421 R_RETURN(ResultUnknown);
648 IPC::ResponseBuilder rb{ctx, 2};
649 rb.Push(ResultUnknown);
650 return;
651 } 422 }
652 423
653 auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); 424 *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
654 425
655 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 426 R_SUCCEED();
656 rb.Push(ResultSuccess);
657 rb.PushIpcInterface<IStorage>(std::move(storage));
658} 427}
659 428
660void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { 429Result FSP_SRV::DisableAutoSaveDataCreation() {
661 LOG_DEBUG(Service_FS, "called"); 430 LOG_DEBUG(Service_FS, "called");
662 431
663 save_data_controller->SetAutoCreate(false); 432 save_data_controller->SetAutoCreate(false);
664 433
665 IPC::ResponseBuilder rb{ctx, 2}; 434 R_SUCCEED();
666 rb.Push(ResultSuccess);
667} 435}
668 436
669void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { 437Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
670 IPC::RequestParser rp{ctx}; 438 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
671 access_log_mode = rp.PopEnum<AccessLogMode>();
672 439
673 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); 440 access_log_mode = access_log_mode_;
674 441
675 IPC::ResponseBuilder rb{ctx, 2}; 442 R_SUCCEED();
676 rb.Push(ResultSuccess);
677} 443}
678 444
679void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { 445Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
680 LOG_DEBUG(Service_FS, "called"); 446 LOG_DEBUG(Service_FS, "called");
681 447
682 IPC::ResponseBuilder rb{ctx, 3}; 448 *out_access_log_mode = access_log_mode;
683 rb.Push(ResultSuccess);
684 rb.PushEnum(access_log_mode);
685}
686 449
687void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { 450 R_SUCCEED();
688 const auto raw = ctx.ReadBufferCopy(); 451}
689 auto log = Common::StringFromFixedZeroTerminatedBuffer(
690 reinterpret_cast<const char*>(raw.data()), raw.size());
691 452
453Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
692 LOG_DEBUG(Service_FS, "called"); 454 LOG_DEBUG(Service_FS, "called");
693 455
456 auto log = Common::StringFromFixedZeroTerminatedBuffer(
457 reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
694 reporter.SaveFSAccessLog(log); 458 reporter.SaveFSAccessLog(log);
695 459
696 IPC::ResponseBuilder rb{ctx, 2}; 460 R_SUCCEED();
697 rb.Push(ResultSuccess);
698} 461}
699 462
700void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { 463Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
701 LOG_DEBUG(Service_FS, "called"); 464 Out<u32> out_access_log_program_index) {
465 LOG_DEBUG(Service_FS, "(STUBBED) called");
702 466
703 IPC::ResponseBuilder rb{ctx, 4}; 467 *out_access_log_version = AccessLogVersion::Latest;
704 rb.Push(ResultSuccess); 468 *out_access_log_program_index = access_log_program_index;
705 rb.PushEnum(AccessLogVersion::Latest); 469
706 rb.Push(access_log_program_index); 470 R_SUCCEED();
707} 471}
708 472
709void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) { 473Result FSP_SRV::FlushAccessLogOnSdCard() {
710 LOG_DEBUG(Service_FS, "(STUBBED) called"); 474 LOG_DEBUG(Service_FS, "(STUBBED) called");
711 475
712 IPC::ResponseBuilder rb{ctx, 2}; 476 R_SUCCEED();
713 rb.Push(ResultSuccess);
714} 477}
715 478
716void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { 479Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
717 IPC::RequestParser rp{ctx};
718 const auto index{rp.Pop<s32>()};
719
720 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); 480 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
721 481
722 IPC::ResponseBuilder rb{ctx, 6}; 482 *out_data_size = 0;
723 rb.Push(ResultSuccess); 483 *out_journal_size = 0;
724 rb.Push(s64{0});
725 rb.Push(s64{0});
726}
727
728class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
729public:
730 explicit IMultiCommitManager(Core::System& system_)
731 : ServiceFramework{system_, "IMultiCommitManager"} {
732 static const FunctionInfo functions[] = {
733 {1, &IMultiCommitManager::Add, "Add"},
734 {2, &IMultiCommitManager::Commit, "Commit"},
735 };
736 RegisterHandlers(functions);
737 }
738
739private:
740 FileSys::VirtualFile backend;
741
742 void Add(HLERequestContext& ctx) {
743 LOG_WARNING(Service_FS, "(STUBBED) called");
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(ResultSuccess);
747 }
748 484
749 void Commit(HLERequestContext& ctx) { 485 R_SUCCEED();
750 LOG_WARNING(Service_FS, "(STUBBED) called"); 486}
751
752 IPC::ResponseBuilder rb{ctx, 2};
753 rb.Push(ResultSuccess);
754 }
755};
756 487
757void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { 488Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
758 LOG_DEBUG(Service_FS, "called"); 489 LOG_DEBUG(Service_FS, "called");
759 490
760 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 491 *out_interface = std::make_shared<IMultiCommitManager>(system);
761 rb.Push(ResultSuccess); 492
762 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); 493 R_SUCCEED();
763} 494}
764 495
765} // namespace Service::FileSystem 496} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 59406e6f9..83d9cb51c 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -4,6 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/fs_save_data_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/filesystem/fsp/fsp_types.h"
7#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
8 11
9namespace Core { 12namespace Core {
@@ -20,6 +23,12 @@ namespace Service::FileSystem {
20class RomFsController; 23class RomFsController;
21class SaveDataController; 24class SaveDataController;
22 25
26class IFileSystem;
27class ISaveDataInfoReader;
28class ISaveDataTransferProhibiter;
29class IStorage;
30class IMultiCommitManager;
31
23enum class AccessLogVersion : u32 { 32enum class AccessLogVersion : u32 {
24 V7_0_0 = 2, 33 V7_0_0 = 2,
25 34
@@ -38,30 +47,51 @@ public:
38 ~FSP_SRV() override; 47 ~FSP_SRV() override;
39 48
40private: 49private:
41 void SetCurrentProcess(HLERequestContext& ctx); 50 Result SetCurrentProcess(ClientProcessId pid);
42 void OpenFileSystemWithPatch(HLERequestContext& ctx); 51 Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
43 void OpenSdCardFileSystem(HLERequestContext& ctx); 52 FileSystemProxyType type, u64 open_program_id);
44 void CreateSaveDataFileSystem(HLERequestContext& ctx); 53 Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
45 void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 54 Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
46 void OpenSaveDataFileSystem(HLERequestContext& ctx); 55 FileSys::SaveDataAttribute save_struct, u128 uid);
47 void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 56 Result CreateSaveDataFileSystemBySystemSaveDataId(
48 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 57 FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct);
49 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 58 Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
50 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); 59 FileSys::SaveDataSpaceId space_id,
51 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 60 FileSys::SaveDataAttribute attribute);
52 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 61 Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
53 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 62 FileSys::SaveDataSpaceId space_id,
54 void OpenDataStorageByDataId(HLERequestContext& ctx); 63 FileSys::SaveDataAttribute attribute);
55 void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); 64 Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
56 void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); 65 FileSys::SaveDataSpaceId space_id,
57 void DisableAutoSaveDataCreation(HLERequestContext& ctx); 66 FileSys::SaveDataAttribute attribute);
58 void SetGlobalAccessLogMode(HLERequestContext& ctx); 67 Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
59 void GetGlobalAccessLogMode(HLERequestContext& ctx); 68 FileSys::SaveDataSpaceId space);
60 void OutputAccessLogToSdCard(HLERequestContext& ctx); 69 Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
61 void FlushAccessLogOnSdCard(HLERequestContext& ctx); 70 Result FindSaveDataWithFilter(Out<s64> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
62 void GetProgramIndexForAccessLog(HLERequestContext& ctx); 71 FileSys::SaveDataSpaceId space_id,
63 void OpenMultiCommitManager(HLERequestContext& ctx); 72 FileSys::SaveDataFilter filter);
64 void GetCacheStorageSize(HLERequestContext& ctx); 73 Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
74 Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
75 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
76 InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
77 OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
78 Result OpenSaveDataTransferProhibiter(OutInterface<ISaveDataTransferProhibiter> out_prohibiter,
79 u64 id);
80 Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
81 Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
82 FileSys::StorageId storage_id, u32 unknown, u64 title_id);
83 Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
84 FileSys::StorageId storage_id, u64 title_id);
85 Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
86 Result DisableAutoSaveDataCreation();
87 Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
88 Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
89 Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
90 Result FlushAccessLogOnSdCard();
91 Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
92 Out<u32> out_access_log_program_index);
93 Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
94 Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
65 95
66 FileSystemController& fsc; 96 FileSystemController& fsc;
67 const FileSys::ContentProvider& content_provider; 97 const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_types.h
index 253f866db..294da6a2d 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_util.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_types.h
@@ -7,6 +7,18 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10enum class FileSystemProxyType : u8 {
11 Code = 0,
12 Rom = 1,
13 Logo = 2,
14 Control = 3,
15 Manual = 4,
16 Meta = 5,
17 Data = 6,
18 Package = 7,
19 RegisteredUpdate = 8,
20};
21
10struct SizeGetter { 22struct SizeGetter {
11 std::function<u64()> get_free_size; 23 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size; 24 std::function<u64()> get_total_size;
diff --git a/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
new file mode 100644
index 000000000..d8d6289fe
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
@@ -0,0 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
5
6namespace Service::FileSystem {
7
8ISaveDataTransferProhibiter::ISaveDataTransferProhibiter(Core::System& system_)
9 : ServiceFramework{system_, "ISaveDataTransferProhibiter"} {}
10
11ISaveDataTransferProhibiter::~ISaveDataTransferProhibiter() = default;
12
13} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
new file mode 100644
index 000000000..d206e1dea
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::FileSystem {
9
10class ISaveDataTransferProhibiter : public ServiceFramework<ISaveDataTransferProhibiter> {
11public:
12 explicit ISaveDataTransferProhibiter(Core::System& system_);
13 ~ISaveDataTransferProhibiter() override;
14};
15
16} // namespace Service::FileSystem
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index aeb849efa..38e62761b 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -42,13 +42,13 @@ public:
42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, 42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
43 {10702, nullptr, "AddPlayHistory"}, 43 {10702, nullptr, "AddPlayHistory"},
44 {11000, nullptr, "GetProfileImageUrl"}, 44 {11000, nullptr, "GetProfileImageUrl"},
45 {20100, nullptr, "GetFriendCount"}, 45 {20100, &IFriendService::GetFriendCount, "GetFriendCount"},
46 {20101, nullptr, "GetNewlyFriendCount"}, 46 {20101, &IFriendService::GetNewlyFriendCount, "GetNewlyFriendCount"},
47 {20102, nullptr, "GetFriendDetailedInfo"}, 47 {20102, nullptr, "GetFriendDetailedInfo"},
48 {20103, nullptr, "SyncFriendList"}, 48 {20103, nullptr, "SyncFriendList"},
49 {20104, nullptr, "RequestSyncFriendList"}, 49 {20104, nullptr, "RequestSyncFriendList"},
50 {20110, nullptr, "LoadFriendSetting"}, 50 {20110, nullptr, "LoadFriendSetting"},
51 {20200, nullptr, "GetReceivedFriendRequestCount"}, 51 {20200, &IFriendService::GetReceivedFriendRequestCount, "GetReceivedFriendRequestCount"},
52 {20201, nullptr, "GetFriendRequestList"}, 52 {20201, nullptr, "GetFriendRequestList"},
53 {20300, nullptr, "GetFriendCandidateList"}, 53 {20300, nullptr, "GetFriendCandidateList"},
54 {20301, nullptr, "GetNintendoNetworkIdInfo"}, 54 {20301, nullptr, "GetNintendoNetworkIdInfo"},
@@ -61,14 +61,14 @@ public:
61 {20501, nullptr, "GetRelationship"}, 61 {20501, nullptr, "GetRelationship"},
62 {20600, nullptr, "GetUserPresenceView"}, 62 {20600, nullptr, "GetUserPresenceView"},
63 {20700, nullptr, "GetPlayHistoryList"}, 63 {20700, nullptr, "GetPlayHistoryList"},
64 {20701, nullptr, "GetPlayHistoryStatistics"}, 64 {20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"},
65 {20800, nullptr, "LoadUserSetting"}, 65 {20800, nullptr, "LoadUserSetting"},
66 {20801, nullptr, "SyncUserSetting"}, 66 {20801, nullptr, "SyncUserSetting"},
67 {20900, nullptr, "RequestListSummaryOverlayNotification"}, 67 {20900, nullptr, "RequestListSummaryOverlayNotification"},
68 {21000, nullptr, "GetExternalApplicationCatalog"}, 68 {21000, nullptr, "GetExternalApplicationCatalog"},
69 {22000, nullptr, "GetReceivedFriendInvitationList"}, 69 {22000, nullptr, "GetReceivedFriendInvitationList"},
70 {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"}, 70 {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
71 {22010, nullptr, "GetReceivedFriendInvitationCountCache"}, 71 {22010, &IFriendService::GetReceivedFriendInvitationCountCache, "GetReceivedFriendInvitationCountCache"},
72 {30100, nullptr, "DropFriendNewlyFlags"}, 72 {30100, nullptr, "DropFriendNewlyFlags"},
73 {30101, nullptr, "DeleteFriend"}, 73 {30101, nullptr, "DeleteFriend"},
74 {30110, nullptr, "DropFriendNewlyFlag"}, 74 {30110, nullptr, "DropFriendNewlyFlag"},
@@ -144,6 +144,33 @@ private:
144 rb.PushCopyObjects(completion_event->GetReadableEvent()); 144 rb.PushCopyObjects(completion_event->GetReadableEvent());
145 } 145 }
146 146
147 void GetFriendList(HLERequestContext& ctx) {
148 IPC::RequestParser rp{ctx};
149 const auto friend_offset = rp.Pop<u32>();
150 const auto uuid = rp.PopRaw<Common::UUID>();
151 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
152 const auto pid = rp.Pop<u64>();
153 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
154 uuid.RawString(), pid);
155
156 IPC::ResponseBuilder rb{ctx, 3};
157 rb.Push(ResultSuccess);
158
159 rb.Push<u32>(0); // Friend count
160 // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
161 }
162
163 void CheckFriendListAvailability(HLERequestContext& ctx) {
164 IPC::RequestParser rp{ctx};
165 const auto uuid{rp.PopRaw<Common::UUID>()};
166
167 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
168
169 IPC::ResponseBuilder rb{ctx, 3};
170 rb.Push(ResultSuccess);
171 rb.Push(true);
172 }
173
147 void GetBlockedUserListIds(HLERequestContext& ctx) { 174 void GetBlockedUserListIds(HLERequestContext& ctx) {
148 // This is safe to stub, as there should be no adverse consequences from reporting no 175 // This is safe to stub, as there should be no adverse consequences from reporting no
149 // blocked users. 176 // blocked users.
@@ -153,6 +180,17 @@ private:
153 rb.Push<u32>(0); // Indicates there are no blocked users 180 rb.Push<u32>(0); // Indicates there are no blocked users
154 } 181 }
155 182
183 void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
184 IPC::RequestParser rp{ctx};
185 const auto uuid{rp.PopRaw<Common::UUID>()};
186
187 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
188
189 IPC::ResponseBuilder rb{ctx, 3};
190 rb.Push(ResultSuccess);
191 rb.Push(true);
192 }
193
156 void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) { 194 void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) {
157 // Stub used by Splatoon 2 195 // Stub used by Splatoon 2
158 LOG_WARNING(Service_Friend, "(STUBBED) called"); 196 LOG_WARNING(Service_Friend, "(STUBBED) called");
@@ -179,42 +217,43 @@ private:
179 rb.Push(ResultSuccess); 217 rb.Push(ResultSuccess);
180 } 218 }
181 219
182 void GetFriendList(HLERequestContext& ctx) { 220 void GetFriendCount(HLERequestContext& ctx) {
183 IPC::RequestParser rp{ctx}; 221 LOG_DEBUG(Service_Friend, "(STUBBED) called");
184 const auto friend_offset = rp.Pop<u32>();
185 const auto uuid = rp.PopRaw<Common::UUID>();
186 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
187 const auto pid = rp.Pop<u64>();
188 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
189 uuid.RawString(), pid);
190 222
191 IPC::ResponseBuilder rb{ctx, 3}; 223 IPC::ResponseBuilder rb{ctx, 3};
192 rb.Push(ResultSuccess); 224 rb.Push(ResultSuccess);
193 225 rb.Push(0);
194 rb.Push<u32>(0); // Friend count
195 // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
196 } 226 }
197 227
198 void CheckFriendListAvailability(HLERequestContext& ctx) { 228 void GetNewlyFriendCount(HLERequestContext& ctx) {
199 IPC::RequestParser rp{ctx}; 229 LOG_DEBUG(Service_Friend, "(STUBBED) called");
200 const auto uuid{rp.PopRaw<Common::UUID>()};
201 230
202 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); 231 IPC::ResponseBuilder rb{ctx, 3};
232 rb.Push(ResultSuccess);
233 rb.Push(0);
234 }
235
236 void GetReceivedFriendRequestCount(HLERequestContext& ctx) {
237 LOG_DEBUG(Service_Friend, "(STUBBED) called");
203 238
204 IPC::ResponseBuilder rb{ctx, 3}; 239 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess); 240 rb.Push(ResultSuccess);
206 rb.Push(true); 241 rb.Push(0);
207 } 242 }
208 243
209 void CheckBlockedUserListAvailability(HLERequestContext& ctx) { 244 void GetPlayHistoryStatistics(HLERequestContext& ctx) {
210 IPC::RequestParser rp{ctx}; 245 LOG_ERROR(Service_Friend, "(STUBBED) called, check in out");
211 const auto uuid{rp.PopRaw<Common::UUID>()};
212 246
213 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); 247 IPC::ResponseBuilder rb{ctx, 2};
248 rb.Push(ResultSuccess);
249 }
250
251 void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) {
252 LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out");
214 253
215 IPC::ResponseBuilder rb{ctx, 3}; 254 IPC::ResponseBuilder rb{ctx, 3};
216 rb.Push(ResultSuccess); 255 rb.Push(ResultSuccess);
217 rb.Push(true); 256 rb.Push(0);
218 } 257 }
219 258
220 KernelHelpers::ServiceContext service_context; 259 KernelHelpers::ServiceContext service_context;
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp
index ec9b0efb1..b801faef2 100644
--- a/src/core/hle/service/glue/time/static.cpp
+++ b/src/core/hle/service/glue/time/static.cpp
@@ -142,16 +142,18 @@ Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
142} 142}
143 143
144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { 144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
145 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 145 SCOPE_EXIT {
146 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
147 };
146 148
147 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); 149 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value));
148} 150}
149 151
150Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 152Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
151 Out<bool> out_automatic_correction) { 153 Out<bool> out_automatic_correction) {
152 SCOPE_EXIT({ 154 SCOPE_EXIT {
153 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); 155 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction);
154 }); 156 };
155 157
156 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( 158 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
157 out_automatic_correction)); 159 out_automatic_correction));
@@ -166,21 +168,27 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
166} 168}
167 169
168Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { 170Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
169 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); }); 171 SCOPE_EXIT {
172 LOG_DEBUG(Service_Time, "called. out_year={}", *out_year);
173 };
170 174
171 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time", 175 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time",
172 "standard_user_clock_initial_year")); 176 "standard_user_clock_initial_year"));
173} 177}
174 178
175Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 179Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
176 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 180 SCOPE_EXIT {
181 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
182 };
177 183
178 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); 184 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
179} 185}
180 186
181Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 187Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
182 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 188 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 189 SCOPE_EXIT {
190 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
191 };
184 192
185 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 193 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
186 out_time_point)); 194 out_time_point));
@@ -188,15 +196,18 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
188 196
189Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 197Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
190 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) { 198 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
191 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 199 SCOPE_EXIT {
200 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
201 };
192 202
193 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); 203 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
194} 204}
195 205
196Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, 206Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
197 Service::PSC::Time::TimeType type) { 207 Service::PSC::Time::TimeType type) {
198 SCOPE_EXIT( 208 SCOPE_EXIT {
199 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 209 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
210 };
200 211
201 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); 212 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
202} 213}
@@ -205,11 +216,11 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
205 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, 216 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
206 const Service::PSC::Time::SystemClockContext& user_context, 217 const Service::PSC::Time::SystemClockContext& user_context,
207 const Service::PSC::Time::SystemClockContext& network_context) { 218 const Service::PSC::Time::SystemClockContext& network_context) {
208 SCOPE_EXIT({ 219 SCOPE_EXIT {
209 LOG_DEBUG(Service_Time, 220 LOG_DEBUG(Service_Time,
210 "called. type={} out_snapshot={} user_context={} network_context={}", type, 221 "called. type={} out_snapshot={} user_context={} network_context={}", type,
211 *out_snapshot, user_context, network_context); 222 *out_snapshot, user_context, network_context);
212 }); 223 };
213 224
214 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( 225 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(
215 type, out_snapshot, user_context, network_context)); 226 type, out_snapshot, user_context, network_context));
@@ -218,14 +229,18 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
218Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time, 229Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time,
219 InClockSnapshot a, 230 InClockSnapshot a,
220 InClockSnapshot b) { 231 InClockSnapshot b) {
221 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 232 SCOPE_EXIT {
233 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
234 };
222 235
223 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); 236 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
224} 237}
225 238
226Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 239Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
227 InClockSnapshot b) { 240 InClockSnapshot b) {
228 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 241 SCOPE_EXIT {
242 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
243 };
229 244
230 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); 245 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
231} 246}
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
index 36f163419..f4d0c87d5 100644
--- a/src/core/hle/service/glue/time/time_zone.cpp
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -57,7 +57,9 @@ TimeZoneService::~TimeZoneService() = default;
57 57
58Result TimeZoneService::GetDeviceLocationName( 58Result TimeZoneService::GetDeviceLocationName(
59 Out<Service::PSC::Time::LocationName> out_location_name) { 59 Out<Service::PSC::Time::LocationName> out_location_name) {
60 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 60 SCOPE_EXIT {
61 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
62 };
61 63
62 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); 64 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
63} 65}
@@ -94,7 +96,9 @@ Result TimeZoneService::SetDeviceLocationName(
94} 96}
95 97
96Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 98Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
97 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 99 SCOPE_EXIT {
100 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
101 };
98 102
99 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); 103 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
100} 104}
@@ -102,10 +106,10 @@ Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
102Result TimeZoneService::LoadLocationNameList( 106Result TimeZoneService::LoadLocationNameList(
103 Out<u32> out_count, 107 Out<u32> out_count,
104 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) { 108 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
105 SCOPE_EXIT({ 109 SCOPE_EXIT {
106 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}", 110 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
107 index, *out_count, out_names[0], out_names[1]); 111 index, *out_count, out_names[0], out_names[1]);
108 }); 112 };
109 113
110 std::scoped_lock l{m_mutex}; 114 std::scoped_lock l{m_mutex};
111 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); 115 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
@@ -124,7 +128,9 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
124 128
125Result TimeZoneService::GetTimeZoneRuleVersion( 129Result TimeZoneService::GetTimeZoneRuleVersion(
126 Out<Service::PSC::Time::RuleVersion> out_rule_version) { 130 Out<Service::PSC::Time::RuleVersion> out_rule_version) {
127 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 131 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
133 };
128 134
129 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); 135 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
130} 136}
@@ -132,10 +138,10 @@ Result TimeZoneService::GetTimeZoneRuleVersion(
132Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 138Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
133 Out<Service::PSC::Time::LocationName> location_name, 139 Out<Service::PSC::Time::LocationName> location_name,
134 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 140 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
135 SCOPE_EXIT({ 141 SCOPE_EXIT {
136 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name, 142 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name,
137 *out_time_point); 143 *out_time_point);
138 }); 144 };
139 145
140 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point)); 146 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point));
141} 147}
@@ -178,10 +184,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
178Result TimeZoneService::ToCalendarTime( 184Result TimeZoneService::ToCalendarTime(
179 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 185 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
180 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) { 186 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) {
181 SCOPE_EXIT({ 187 SCOPE_EXIT {
182 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 188 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
183 *out_calendar_time, *out_additional_info); 189 *out_calendar_time, *out_additional_info);
184 }); 190 };
185 191
186 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); 192 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
187} 193}
@@ -189,10 +195,10 @@ Result TimeZoneService::ToCalendarTime(
189Result TimeZoneService::ToCalendarTimeWithMyRule( 195Result TimeZoneService::ToCalendarTimeWithMyRule(
190 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 196 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
191 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) { 197 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) {
192 SCOPE_EXIT({ 198 SCOPE_EXIT {
193 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 199 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
194 *out_calendar_time, *out_additional_info); 200 *out_calendar_time, *out_additional_info);
195 }); 201 };
196 202
197 R_RETURN( 203 R_RETURN(
198 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); 204 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
@@ -202,11 +208,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
202 OutArray<s64, BufferAttr_HipcPointer> out_times, 208 OutArray<s64, BufferAttr_HipcPointer> out_times,
203 const Service::PSC::Time::CalendarTime& calendar_time, 209 const Service::PSC::Time::CalendarTime& calendar_time,
204 InRule rule) { 210 InRule rule) {
205 SCOPE_EXIT({ 211 SCOPE_EXIT {
206 LOG_DEBUG(Service_Time, 212 LOG_DEBUG(Service_Time,
207 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 213 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
208 calendar_time, *out_count, out_times[0], out_times[1]); 214 calendar_time, *out_count, out_times[0], out_times[1]);
209 }); 215 };
210 216
211 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); 217 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
212} 218}
@@ -214,11 +220,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
214Result TimeZoneService::ToPosixTimeWithMyRule( 220Result TimeZoneService::ToPosixTimeWithMyRule(
215 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, 221 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
216 const Service::PSC::Time::CalendarTime& calendar_time) { 222 const Service::PSC::Time::CalendarTime& calendar_time) {
217 SCOPE_EXIT({ 223 SCOPE_EXIT {
218 LOG_DEBUG(Service_Time, 224 LOG_DEBUG(Service_Time,
219 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 225 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
220 calendar_time, *out_count, out_times[0], out_times[1]); 226 calendar_time, *out_count, out_times[0], out_times[1]);
221 }); 227 };
222 228
223 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); 229 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
224} 230}
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 7126a1dcd..b0cd63d72 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -201,7 +201,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
201 {1269, nullptr, "DeleteButtonConfigStorageLeft"}, 201 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
202 {1270, nullptr, "DeleteButtonConfigStorageRight"}, 202 {1270, nullptr, "DeleteButtonConfigStorageRight"},
203 {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"}, 203 {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"},
204 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, 204 {1272, &IHidSystemServer::IsAnyCustomButtonConfigEnabled, "IsAnyCustomButtonConfigEnabled"},
205 {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, 205 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
206 {1274, nullptr, "SetDefaultButtonConfig"}, 206 {1274, nullptr, "SetDefaultButtonConfig"},
207 {1275, nullptr, "SetAllDefaultButtonConfig"}, 207 {1275, nullptr, "SetAllDefaultButtonConfig"},
@@ -926,6 +926,16 @@ void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
926 rb.Push(is_enabled); 926 rb.Push(is_enabled);
927} 927}
928 928
929void IHidSystemServer::IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx) {
930 const bool is_enabled = false;
931
932 LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
933
934 IPC::ResponseBuilder rb{ctx, 3};
935 rb.Push(ResultSuccess);
936 rb.Push(is_enabled);
937}
938
929std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { 939std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
930 resource_manager->Initialize(); 940 resource_manager->Initialize();
931 return resource_manager; 941 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 738313e08..1a4f244d7 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -77,6 +77,7 @@ private:
77 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); 77 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
78 void SetForceHandheldStyleVibration(HLERequestContext& ctx); 78 void SetForceHandheldStyleVibration(HLERequestContext& ctx);
79 void IsUsingCustomButtonConfig(HLERequestContext& ctx); 79 void IsUsingCustomButtonConfig(HLERequestContext& ctx);
80 void IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx);
80 81
81 std::shared_ptr<ResourceManager> GetResourceManager(); 82 std::shared_ptr<ResourceManager> GetResourceManager();
82 83
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 98a79365d..c14b24142 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -18,8 +18,8 @@ public:
18 explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} { 18 explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "SaveCurrentSetting"}, 21 {0, &LBL::SaveCurrentSetting, "SaveCurrentSetting"},
22 {1, nullptr, "LoadCurrentSetting"}, 22 {1, &LBL::LoadCurrentSetting, "LoadCurrentSetting"},
23 {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"}, 23 {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"},
24 {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"}, 24 {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"},
25 {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"}, 25 {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
@@ -47,7 +47,7 @@ public:
47 {26, &LBL::EnableVrMode, "EnableVrMode"}, 47 {26, &LBL::EnableVrMode, "EnableVrMode"},
48 {27, &LBL::DisableVrMode, "DisableVrMode"}, 48 {27, &LBL::DisableVrMode, "DisableVrMode"},
49 {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, 49 {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
50 {29, nullptr, "IsAutoBrightnessControlSupported"}, 50 {29, &LBL::IsAutoBrightnessControlSupported, "IsAutoBrightnessControlSupported"},
51 }; 51 };
52 // clang-format on 52 // clang-format on
53 53
@@ -60,6 +60,20 @@ private:
60 On = 1, 60 On = 1,
61 }; 61 };
62 62
63 void SaveCurrentSetting(HLERequestContext& ctx) {
64 LOG_WARNING(Service_LBL, "(STUBBED) called");
65
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(ResultSuccess);
68 }
69
70 void LoadCurrentSetting(HLERequestContext& ctx) {
71 LOG_WARNING(Service_LBL, "(STUBBED) called");
72
73 IPC::ResponseBuilder rb{ctx, 2};
74 rb.Push(ResultSuccess);
75 }
76
63 void SetCurrentBrightnessSetting(HLERequestContext& ctx) { 77 void SetCurrentBrightnessSetting(HLERequestContext& ctx) {
64 IPC::RequestParser rp{ctx}; 78 IPC::RequestParser rp{ctx};
65 auto brightness = rp.Pop<float>(); 79 auto brightness = rp.Pop<float>();
@@ -310,6 +324,14 @@ private:
310 rb.Push(vr_mode_enabled); 324 rb.Push(vr_mode_enabled);
311 } 325 }
312 326
327 void IsAutoBrightnessControlSupported(HLERequestContext& ctx) {
328 LOG_DEBUG(Service_LBL, "called");
329
330 IPC::ResponseBuilder rb{ctx, 3};
331 rb.Push(ResultSuccess);
332 rb.Push<u8>(auto_brightness_supported);
333 }
334
313 bool vr_mode_enabled = false; 335 bool vr_mode_enabled = false;
314 float current_brightness = 1.0f; 336 float current_brightness = 1.0f;
315 float ambient_light_value = 0.0f; 337 float ambient_light_value = 0.0f;
@@ -317,7 +339,8 @@ private:
317 bool dimming = true; 339 bool dimming = true;
318 bool backlight_enabled = true; 340 bool backlight_enabled = true;
319 bool update_instantly = false; 341 bool update_instantly = false;
320 bool auto_brightness = false; // TODO(ogniK): Move to system settings 342 bool auto_brightness = false;
343 bool auto_brightness_supported = true; // TODO(ogniK): Move to system settings
321}; 344};
322 345
323void LoopProcess(Core::System& system) { 346void LoopProcess(Core::System& system) {
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index 94a8243b5..2dd3e9f89 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/psc/time/steady_clock.h" 14#include "core/hle/service/psc/time/steady_clock.h"
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "core/hle/service/set/system_settings_server.h"
16#include "core/hle/service/sm/sm.h" 17#include "core/hle/service/sm/sm.h"
17#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
18#include "hid_core/hid_util.h" 19#include "hid_core/hid_util.h"
@@ -32,6 +33,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
32 } 33 }
33 34
34 is_initialized = false; 35 is_initialized = false;
36
37 m_set_sys =
38 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
35} 39}
36 40
37DeviceManager ::~DeviceManager() { 41DeviceManager ::~DeviceManager() {
@@ -774,8 +778,8 @@ Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const
774} 778}
775 779
776Result DeviceManager::IsNfcEnabled() const { 780Result DeviceManager::IsNfcEnabled() const {
777 // TODO: This calls nn::settings::detail::GetNfcEnableFlag 781 bool is_enabled{};
778 const bool is_enabled = true; 782 R_TRY(m_set_sys->GetNfcEnableFlag(&is_enabled));
779 if (!is_enabled) { 783 if (!is_enabled) {
780 return ResultNfcDisabled; 784 return ResultNfcDisabled;
781 } 785 }
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index c56a2fbda..6c0e6b255 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -15,6 +15,10 @@
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "hid_core/hid_types.h" 16#include "hid_core/hid_types.h"
17 17
18namespace Service::Set {
19class ISystemSettingsServer;
20}
21
18namespace Service::NFC { 22namespace Service::NFC {
19class NfcDevice; 23class NfcDevice;
20 24
@@ -98,6 +102,7 @@ private:
98 Core::System& system; 102 Core::System& system;
99 KernelHelpers::ServiceContext service_context; 103 KernelHelpers::ServiceContext service_context;
100 Kernel::KEvent* availability_change_event; 104 Kernel::KEvent* availability_change_event;
105 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
101}; 106};
102 107
103} // namespace Service::NFC 108} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 30ae989b9..9d4808dbe 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -57,7 +57,7 @@ public:
57 {1, &NfcInterface::Finalize, "FinalizeOld"}, 57 {1, &NfcInterface::Finalize, "FinalizeOld"},
58 {2, &NfcInterface::GetState, "GetStateOld"}, 58 {2, &NfcInterface::GetState, "GetStateOld"},
59 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"}, 59 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
60 {100, nullptr, "SetNfcEnabledOld"}, 60 {100, &NfcInterface::SetNfcEnabled, "SetNfcEnabledOld"},
61 {400, &NfcInterface::Initialize, "Initialize"}, 61 {400, &NfcInterface::Initialize, "Initialize"},
62 {401, &NfcInterface::Finalize, "Finalize"}, 62 {401, &NfcInterface::Finalize, "Finalize"},
63 {402, &NfcInterface::GetState, "GetState"}, 63 {402, &NfcInterface::GetState, "GetState"},
@@ -71,7 +71,7 @@ public:
71 {410, &NfcInterface::GetTagInfo, "GetTagInfo"}, 71 {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
72 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"}, 72 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
73 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"}, 73 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
74 {500, nullptr, "SetNfcEnabled"}, 74 {500, &NfcInterface::SetNfcEnabled, "SetNfcEnabled"},
75 {510, nullptr, "OutputTestWave"}, 75 {510, nullptr, "OutputTestWave"},
76 {1000, &NfcInterface::ReadMifare, "ReadMifare"}, 76 {1000, &NfcInterface::ReadMifare, "ReadMifare"},
77 {1001, &NfcInterface::WriteMifare, "WriteMifare"}, 77 {1001, &NfcInterface::WriteMifare, "WriteMifare"},
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 3e2c7deab..c28e55431 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -13,13 +13,18 @@
13#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/nfc/nfc_types.h" 14#include "core/hle/service/nfc/nfc_types.h"
15#include "core/hle/service/nfp/nfp_result.h" 15#include "core/hle/service/nfp/nfp_result.h"
16#include "core/hle/service/set/system_settings_server.h"
17#include "core/hle/service/sm/sm.h"
16#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
17 19
18namespace Service::NFC { 20namespace Service::NFC {
19 21
20NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend) 22NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
21 : ServiceFramework{system_, name}, service_context{system_, service_name}, 23 : ServiceFramework{system_, name}, service_context{system_, service_name},
22 backend_type{service_backend} {} 24 backend_type{service_backend} {
25 m_set_sys =
26 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
27}
23 28
24NfcInterface ::~NfcInterface() = default; 29NfcInterface ::~NfcInterface() = default;
25 30
@@ -65,11 +70,11 @@ void NfcInterface::GetState(HLERequestContext& ctx) {
65void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) { 70void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
66 LOG_DEBUG(Service_NFC, "called"); 71 LOG_DEBUG(Service_NFC, "called");
67 72
68 // TODO: This calls nn::settings::detail::GetNfcEnableFlag 73 bool is_enabled{};
69 const bool is_enabled = true; 74 const auto result = m_set_sys->GetNfcEnableFlag(&is_enabled);
70 75
71 IPC::ResponseBuilder rb{ctx, 3}; 76 IPC::ResponseBuilder rb{ctx, 3};
72 rb.Push(ResultSuccess); 77 rb.Push(result);
73 rb.Push(is_enabled); 78 rb.Push(is_enabled);
74} 79}
75 80
@@ -212,6 +217,17 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
212 rb.PushCopyObjects(out_event); 217 rb.PushCopyObjects(out_event);
213} 218}
214 219
220void NfcInterface::SetNfcEnabled(HLERequestContext& ctx) {
221 IPC::RequestParser rp{ctx};
222 const auto is_enabled{rp.Pop<bool>()};
223 LOG_DEBUG(Service_NFC, "called, is_enabled={}", is_enabled);
224
225 const auto result = m_set_sys->SetNfcEnableFlag(is_enabled);
226
227 IPC::ResponseBuilder rb{ctx, 2};
228 rb.Push(result);
229}
230
215void NfcInterface::ReadMifare(HLERequestContext& ctx) { 231void NfcInterface::ReadMifare(HLERequestContext& ctx) {
216 IPC::RequestParser rp{ctx}; 232 IPC::RequestParser rp{ctx};
217 const auto device_handle{rp.Pop<u64>()}; 233 const auto device_handle{rp.Pop<u64>()};
diff --git a/src/core/hle/service/nfc/nfc_interface.h b/src/core/hle/service/nfc/nfc_interface.h
index 08be174d8..5cc0d8ec0 100644
--- a/src/core/hle/service/nfc/nfc_interface.h
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -7,6 +7,10 @@
7#include "core/hle/service/nfc/nfc_types.h" 7#include "core/hle/service/nfc/nfc_types.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Service::Set {
11class ISystemSettingsServer;
12}
13
10namespace Service::NFC { 14namespace Service::NFC {
11class DeviceManager; 15class DeviceManager;
12 16
@@ -29,6 +33,7 @@ public:
29 void AttachActivateEvent(HLERequestContext& ctx); 33 void AttachActivateEvent(HLERequestContext& ctx);
30 void AttachDeactivateEvent(HLERequestContext& ctx); 34 void AttachDeactivateEvent(HLERequestContext& ctx);
31 void ReadMifare(HLERequestContext& ctx); 35 void ReadMifare(HLERequestContext& ctx);
36 void SetNfcEnabled(HLERequestContext& ctx);
32 void WriteMifare(HLERequestContext& ctx); 37 void WriteMifare(HLERequestContext& ctx);
33 void SendCommandByPassThrough(HLERequestContext& ctx); 38 void SendCommandByPassThrough(HLERequestContext& ctx);
34 39
@@ -44,6 +49,7 @@ protected:
44 BackendType backend_type; 49 BackendType backend_type;
45 State state{State::NonInitialized}; 50 State state{State::NonInitialized};
46 std::shared_ptr<DeviceManager> device_manager = nullptr; 51 std::shared_ptr<DeviceManager> device_manager = nullptr;
52 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
47}; 53};
48 54
49} // namespace Service::NFC 55} // namespace Service::NFC
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index a162e5c54..e54827efe 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -3,22 +3,26 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/kernel_helpers.h"
6#include "core/hle/service/npns/npns.h" 9#include "core/hle/service/npns/npns.h"
7#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
8#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
9 12
10namespace Service::NPNS { 13namespace Service::NPNS {
11 14
12class NPNS_S final : public ServiceFramework<NPNS_S> { 15class INpnsSystem final : public ServiceFramework<INpnsSystem> {
13public: 16public:
14 explicit NPNS_S(Core::System& system_) : ServiceFramework{system_, "npns:s"} { 17 explicit INpnsSystem(Core::System& system_)
18 : ServiceFramework{system_, "npns:s"}, service_context{system, "npns:s"} {
15 // clang-format off 19 // clang-format off
16 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
17 {1, nullptr, "ListenAll"}, 21 {1, nullptr, "ListenAll"},
18 {2, nullptr, "ListenTo"}, 22 {2, C<&INpnsSystem::ListenTo>, "ListenTo"},
19 {3, nullptr, "Receive"}, 23 {3, nullptr, "Receive"},
20 {4, nullptr, "ReceiveRaw"}, 24 {4, nullptr, "ReceiveRaw"},
21 {5, nullptr, "GetReceiveEvent"}, 25 {5, C<&INpnsSystem::GetReceiveEvent>, "GetReceiveEvent"},
22 {6, nullptr, "ListenUndelivered"}, 26 {6, nullptr, "ListenUndelivered"},
23 {7, nullptr, "GetStateChangeEVent"}, 27 {7, nullptr, "GetStateChangeEVent"},
24 {11, nullptr, "SubscribeTopic"}, 28 {11, nullptr, "SubscribeTopic"},
@@ -59,12 +63,34 @@ public:
59 // clang-format on 63 // clang-format on
60 64
61 RegisterHandlers(functions); 65 RegisterHandlers(functions);
66
67 get_receive_event = service_context.CreateEvent("npns:s:GetReceiveEvent");
62 } 68 }
69
70 ~INpnsSystem() override {
71 service_context.CloseEvent(get_receive_event);
72 }
73
74private:
75 Result ListenTo(u32 program_id) {
76 LOG_WARNING(Service_AM, "(STUBBED) called, program_id={}", program_id);
77 R_SUCCEED();
78 }
79
80 Result GetReceiveEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
81 LOG_WARNING(Service_AM, "(STUBBED) called");
82
83 *out_event = &get_receive_event->GetReadableEvent();
84 R_SUCCEED();
85 }
86
87 KernelHelpers::ServiceContext service_context;
88 Kernel::KEvent* get_receive_event;
63}; 89};
64 90
65class NPNS_U final : public ServiceFramework<NPNS_U> { 91class INpnsUser final : public ServiceFramework<INpnsUser> {
66public: 92public:
67 explicit NPNS_U(Core::System& system_) : ServiceFramework{system_, "npns:u"} { 93 explicit INpnsUser(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
68 // clang-format off 94 // clang-format off
69 static const FunctionInfo functions[] = { 95 static const FunctionInfo functions[] = {
70 {1, nullptr, "ListenAll"}, 96 {1, nullptr, "ListenAll"},
@@ -97,8 +123,8 @@ public:
97void LoopProcess(Core::System& system) { 123void LoopProcess(Core::System& system) {
98 auto server_manager = std::make_unique<ServerManager>(system); 124 auto server_manager = std::make_unique<ServerManager>(system);
99 125
100 server_manager->RegisterNamedService("npns:s", std::make_shared<NPNS_S>(system)); 126 server_manager->RegisterNamedService("npns:s", std::make_shared<INpnsSystem>(system));
101 server_manager->RegisterNamedService("npns:u", std::make_shared<NPNS_U>(system)); 127 server_manager->RegisterNamedService("npns:u", std::make_shared<INpnsUser>(system));
102 ServerManager::RunServer(std::move(server_manager)); 128 ServerManager::RunServer(std::move(server_manager));
103} 129}
104 130
diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp
index 2e3a44c0d..7a91727f9 100644
--- a/src/core/hle/service/ns/application_manager_interface.cpp
+++ b/src/core/hle/service/ns/application_manager_interface.cpp
@@ -436,14 +436,14 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
436 436
437Result IApplicationManagerInterface::GetApplicationRightsOnClient( 437Result IApplicationManagerInterface::GetApplicationRightsOnClient(
438 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, 438 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
439 Common::UUID account_id, u32 flags, u64 application_id) { 439 u32 flags, u64 application_id, Uid account_id) {
440 LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}", 440 LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
441 flags, application_id, account_id.FormattedString()); 441 flags, application_id, account_id.uuid.FormattedString());
442 442
443 if (!out_rights.empty()) { 443 if (!out_rights.empty()) {
444 ApplicationRightsOnClient rights{}; 444 ApplicationRightsOnClient rights{};
445 rights.application_id = application_id; 445 rights.application_id = application_id;
446 rights.uid = account_id; 446 rights.uid = account_id.uuid;
447 rights.flags = 0; 447 rights.flags = 0;
448 rights.flags2 = 0; 448 rights.flags2 = 0;
449 449
diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h
index 350ec37ce..f33d269b3 100644
--- a/src/core/hle/service/ns/application_manager_interface.h
+++ b/src/core/hle/service/ns/application_manager_interface.h
@@ -37,7 +37,7 @@ public:
37 InArray<u64, BufferAttr_HipcMapAlias> application_ids); 37 InArray<u64, BufferAttr_HipcMapAlias> application_ids);
38 Result GetApplicationRightsOnClient( 38 Result GetApplicationRightsOnClient(
39 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, 39 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
40 Common::UUID account_id, u32 flags, u64 application_id); 40 u32 flags, u64 application_id, Uid account_id);
41 Result CheckSdCardMountStatus(); 41 Result CheckSdCardMountStatus();
42 Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); 42 Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
43 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id); 43 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h
index 38421b0f4..2dd664c4e 100644
--- a/src/core/hle/service/ns/ns_types.h
+++ b/src/core/hle/service/ns/ns_types.h
@@ -108,4 +108,9 @@ struct ContentPath {
108}; 108};
109static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size."); 109static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size.");
110 110
111struct Uid {
112 alignas(8) Common::UUID uuid;
113};
114static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size.");
115
111} // namespace Service::NS 116} // namespace Service::NS
diff --git a/src/core/hle/service/ns/query_service.cpp b/src/core/hle/service/ns/query_service.cpp
index 946b7fa23..138400541 100644
--- a/src/core/hle/service/ns/query_service.cpp
+++ b/src/core/hle/service/ns/query_service.cpp
@@ -41,8 +41,7 @@ IQueryService::IQueryService(Core::System& system_) : ServiceFramework{system_,
41IQueryService::~IQueryService() = default; 41IQueryService::~IQueryService() = default;
42 42
43Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId( 43Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
44 Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, 44 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id) {
45 u64 application_id) {
46 // TODO(German77): Read statistics of the game 45 // TODO(German77): Read statistics of the game
47 *out_play_statistics = { 46 *out_play_statistics = {
48 .application_id = application_id, 47 .application_id = application_id,
@@ -50,7 +49,7 @@ Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
50 }; 49 };
51 50
52 LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}", 51 LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}",
53 unknown, application_id, account_id.FormattedString()); 52 unknown, application_id, account_id.uuid.FormattedString());
54 R_SUCCEED(); 53 R_SUCCEED();
55} 54}
56 55
diff --git a/src/core/hle/service/ns/query_service.h b/src/core/hle/service/ns/query_service.h
index 6cdbfa277..c4c82b752 100644
--- a/src/core/hle/service/ns/query_service.h
+++ b/src/core/hle/service/ns/query_service.h
@@ -5,6 +5,7 @@
5 5
6#include "common/uuid.h" 6#include "common/uuid.h"
7#include "core/hle/service/cmif_types.h" 7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/ns/ns_types.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
10namespace Service::NS { 11namespace Service::NS {
@@ -29,8 +30,7 @@ public:
29 30
30private: 31private:
31 Result QueryPlayStatisticsByApplicationIdAndUserAccountId( 32 Result QueryPlayStatisticsByApplicationIdAndUserAccountId(
32 Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, 33 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id);
33 u64 application_id);
34}; 34};
35 35
36} // namespace Service::NS 36} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 250d01de3..0265d55f2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -92,11 +92,11 @@ NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_a
92 92
93 bool must_unmark_fail = !is_allocation; 93 bool must_unmark_fail = !is_allocation;
94 const u32 event_id = params.value.raw; 94 const u32 event_id = params.value.raw;
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (must_unmark_fail) { 96 if (must_unmark_fail) {
97 events[event_id].fails = 0; 97 events[event_id].fails = 0;
98 } 98 }
99 }); 99 };
100 100
101 const u32 fence_id = static_cast<u32>(params.fence.id); 101 const u32 fence_id = static_cast<u32>(params.fence.id);
102 102
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 241006cc8..258970fd5 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -154,10 +154,10 @@ void NVDRV::Close(HLERequestContext& ctx) {
154void NVDRV::Initialize(HLERequestContext& ctx) { 154void NVDRV::Initialize(HLERequestContext& ctx) {
155 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 155 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
156 IPC::ResponseBuilder rb{ctx, 3}; 156 IPC::ResponseBuilder rb{ctx, 3};
157 SCOPE_EXIT({ 157 SCOPE_EXIT {
158 rb.Push(ResultSuccess); 158 rb.Push(ResultSuccess);
159 rb.PushEnum(NvResult::Success); 159 rb.PushEnum(NvResult::Success);
160 }); 160 };
161 161
162 if (is_initialized) { 162 if (is_initialized) {
163 // No need to initialize again 163 // No need to initialize again
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h
index f27cbf144..40aa59787 100644
--- a/src/core/hle/service/nvnflinger/display.h
+++ b/src/core/hle/service/nvnflinger/display.h
@@ -3,8 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list>
7
8#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 6#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
9#include "core/hle/service/nvnflinger/hwc_layer.h" 7#include "core/hle/service/nvnflinger/hwc_layer.h"
10 8
@@ -26,18 +24,12 @@ struct Layer {
26}; 24};
27 25
28struct LayerStack { 26struct LayerStack {
29 std::list<Layer> layers; 27 std::vector<std::shared_ptr<Layer>> layers;
30};
31
32struct Display {
33 explicit Display(u64 id_) {
34 id = id_;
35 }
36 28
37 Layer* FindLayer(s32 consumer_id) { 29 std::shared_ptr<Layer> FindLayer(s32 consumer_id) {
38 for (auto& layer : stack.layers) { 30 for (auto& layer : layers) {
39 if (layer.consumer_id == consumer_id) { 31 if (layer->consumer_id == consumer_id) {
40 return &layer; 32 return layer;
41 } 33 }
42 } 34 }
43 35
@@ -45,7 +37,13 @@ struct Display {
45 } 37 }
46 38
47 bool HasLayers() { 39 bool HasLayers() {
48 return !stack.layers.empty(); 40 return !layers.empty();
41 }
42};
43
44struct Display {
45 explicit Display(u64 id_) {
46 id = id_;
49 } 47 }
50 48
51 u64 id; 49 u64 id;
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index 02215a786..f2dfe85a9 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -55,10 +55,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
55 55
56 // Acquire all necessary framebuffers. 56 // Acquire all necessary framebuffers.
57 for (auto& layer : display.stack.layers) { 57 for (auto& layer : display.stack.layers) {
58 auto consumer_id = layer.consumer_id; 58 auto consumer_id = layer->consumer_id;
59 59
60 // Try to fetch the framebuffer (either new or stale). 60 // Try to fetch the framebuffer (either new or stale).
61 const auto result = this->CacheFramebufferLocked(layer, consumer_id); 61 const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
62 62
63 // If we failed, skip this layer. 63 // If we failed, skip this layer.
64 if (result == CacheStatus::NoBufferAvailable) { 64 if (result == CacheStatus::NoBufferAvailable) {
@@ -75,7 +75,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
75 const auto& igbp_buffer = *item.graphic_buffer; 75 const auto& igbp_buffer = *item.graphic_buffer;
76 76
77 // TODO: get proper Z-index from layer 77 // TODO: get proper Z-index from layer
78 if (layer.visible) { 78 if (layer->visible) {
79 composition_stack.emplace_back(HwcLayer{ 79 composition_stack.emplace_back(HwcLayer{
80 .buffer_handle = igbp_buffer.BufferId(), 80 .buffer_handle = igbp_buffer.BufferId(),
81 .offset = igbp_buffer.Offset(), 81 .offset = igbp_buffer.Offset(),
@@ -84,7 +84,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
84 .height = igbp_buffer.Height(), 84 .height = igbp_buffer.Height(),
85 .stride = igbp_buffer.Stride(), 85 .stride = igbp_buffer.Stride(),
86 .z_index = 0, 86 .z_index = 0,
87 .blending = layer.blending, 87 .blending = layer->blending,
88 .transform = static_cast<android::BufferTransformFlags>(item.transform), 88 .transform = static_cast<android::BufferTransformFlags>(item.transform),
89 .crop_rect = item.crop, 89 .crop_rect = item.crop,
90 .acquire_fence = item.fence, 90 .acquire_fence = item.fence,
@@ -134,7 +134,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
134 continue; 134 continue;
135 } 135 }
136 136
137 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { 137 if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
138 // TODO: support release fence 138 // TODO: support release fence
139 // This is needed to prevent screen tearing 139 // This is needed to prevent screen tearing
140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); 140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
@@ -153,7 +153,7 @@ void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_i
153 } 153 }
154 154
155 // Try to release the buffer item. 155 // Try to release the buffer item.
156 auto* const layer = display.FindLayer(consumer_id); 156 const auto layer = display.stack.FindLayer(consumer_id);
157 if (layer && it->second.is_acquired) { 157 if (layer && it->second.is_acquired) {
158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); 158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
159 } 159 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp
index 41a705717..8362b65e5 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.cpp
+++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp
@@ -36,7 +36,7 @@ void SurfaceFlinger::RemoveDisplay(u64 display_id) {
36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
37 u64 display_id) { 37 u64 display_id) {
38 auto* const display = this->FindDisplay(display_id); 38 auto* const display = this->FindDisplay(display_id);
39 if (!display || !display->HasLayers()) { 39 if (!display || !display->stack.HasLayers()) {
40 return false; 40 return false;
41 } 41 }
42 42
@@ -46,19 +46,34 @@ bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_spe
46 return true; 46 return true;
47} 47}
48 48
49void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { 49void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) {
50 auto* const display = this->FindDisplay(display_id);
51 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( 50 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
52 m_server.TryGetBinder(consumer_binder_id)); 51 m_server.TryGetBinder(consumer_binder_id));
53 52 if (!binder) {
54 if (!display || !binder) {
55 return; 53 return;
56 } 54 }
57 55
58 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); 56 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
59 buffer_item_consumer->Connect(false); 57 buffer_item_consumer->Connect(false);
60 58
61 display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); 59 m_layers.layers.emplace_back(
60 std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id));
61}
62
63void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) {
64 std::erase_if(m_layers.layers,
65 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
66}
67
68void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
69 auto* const display = this->FindDisplay(display_id);
70 auto layer = this->FindLayer(consumer_binder_id);
71
72 if (!display || !layer) {
73 return;
74 }
75
76 display->stack.layers.emplace_back(std::move(layer));
62} 77}
63 78
64void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { 79void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
@@ -69,18 +84,18 @@ void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_bi
69 84
70 m_composer.RemoveLayerLocked(*display, consumer_binder_id); 85 m_composer.RemoveLayerLocked(*display, consumer_binder_id);
71 std::erase_if(display->stack.layers, 86 std::erase_if(display->stack.layers,
72 [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); 87 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
73} 88}
74 89
75void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { 90void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
76 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 91 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
77 layer->visible = visible; 92 layer->visible = visible;
78 return; 93 return;
79 } 94 }
80} 95}
81 96
82void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { 97void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
83 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 98 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
84 layer->blending = blending; 99 layer->blending = blending;
85 return; 100 return;
86 } 101 }
@@ -96,9 +111,9 @@ Display* SurfaceFlinger::FindDisplay(u64 display_id) {
96 return nullptr; 111 return nullptr;
97} 112}
98 113
99Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { 114std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
100 for (auto& display : m_displays) { 115 for (auto& layer : m_layers.layers) {
101 if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { 116 if (layer->consumer_id == consumer_binder_id) {
102 return layer; 117 return layer;
103 } 118 }
104 } 119 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h
index d8c53fbda..406281c83 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.h
+++ b/src/core/hle/service/nvnflinger/surface_flinger.h
@@ -36,6 +36,9 @@ public:
36 void RemoveDisplay(u64 display_id); 36 void RemoveDisplay(u64 display_id);
37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
38 38
39 void CreateLayer(s32 consumer_binder_id);
40 void DestroyLayer(s32 consumer_binder_id);
41
39 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); 42 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
40 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); 43 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
41 44
@@ -44,7 +47,7 @@ public:
44 47
45private: 48private:
46 Display* FindDisplay(u64 display_id); 49 Display* FindDisplay(u64 display_id);
47 Layer* FindLayer(s32 consumer_binder_id); 50 std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
48 51
49public: 52public:
50 // TODO: these don't belong here 53 // TODO: these don't belong here
@@ -57,6 +60,7 @@ private:
57 KernelHelpers::ServiceContext m_context; 60 KernelHelpers::ServiceContext m_context;
58 61
59 std::vector<Display> m_displays; 62 std::vector<Display> m_displays;
63 LayerStack m_layers;
60 std::shared_ptr<Nvidia::Module> nvdrv; 64 std::shared_ptr<Nvidia::Module> nvdrv;
61 s32 disp_fd; 65 s32 disp_fd;
62 HardwareComposer m_composer; 66 HardwareComposer m_composer;
diff --git a/src/core/hle/service/olsc/daemon_controller.cpp b/src/core/hle/service/olsc/daemon_controller.cpp
new file mode 100644
index 000000000..7823780a8
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/daemon_controller.h"
6
7namespace Service::OLSC {
8
9IDaemonController::IDaemonController(Core::System& system_)
10 : ServiceFramework{system_, "IDaemonController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IDaemonController::GetAutoTransferEnabledForAccountAndApplication>, "GetAutoTransferEnabledForAccountAndApplication"},
14 {1, nullptr, "SetAutoTransferEnabledForAccountAndApplication"},
15 {2, nullptr, "GetGlobalUploadEnabledForAccount"},
16 {3, nullptr, "SetGlobalUploadEnabledForAccount"},
17 {4, nullptr, "TouchAccount"},
18 {5, nullptr, "GetGlobalDownloadEnabledForAccount"},
19 {6, nullptr, "SetGlobalDownloadEnabledForAccount"},
20 {10, nullptr, "GetForbiddenSaveDataIndication"},
21 {11, nullptr, "GetStopperObject"},
22 {12, nullptr, "GetState"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IDaemonController::~IDaemonController() = default;
30
31Result IDaemonController::GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
32 Common::UUID user_id,
33 u64 application_id) {
34 LOG_WARNING(Service_OLSC, "(STUBBED) called, user_id={} application_id={:016X}",
35 user_id.FormattedString(), application_id);
36 *out_is_enabled = false;
37 R_SUCCEED();
38}
39
40} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/daemon_controller.h b/src/core/hle/service/olsc/daemon_controller.h
new file mode 100644
index 000000000..dfad7f52a
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/uuid.h"
5#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/service.h"
7
8namespace Service::OLSC {
9
10class IDaemonController final : public ServiceFramework<IDaemonController> {
11public:
12 explicit IDaemonController(Core::System& system_);
13 ~IDaemonController() override;
14
15private:
16 Result GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
17 Common::UUID user_id, u64 application_id);
18};
19
20} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.cpp b/src/core/hle/service/olsc/native_handle_holder.cpp
new file mode 100644
index 000000000..3cb5d7b11
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/native_handle_holder.h"
6
7namespace Service::OLSC {
8
9INativeHandleHolder::INativeHandleHolder(Core::System& system_)
10 : ServiceFramework{system_, "INativeHandleHolder"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&INativeHandleHolder::GetNativeHandle>, "GetNativeHandle"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20INativeHandleHolder::~INativeHandleHolder() = default;
21
22Result INativeHandleHolder::GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
23 LOG_WARNING(Service_OLSC, "(STUBBED) called");
24 *out_event = nullptr;
25 R_SUCCEED();
26}
27
28} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.h b/src/core/hle/service/olsc/native_handle_holder.h
new file mode 100644
index 000000000..a44754c20
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Kernel {
8class KReadableEvent;
9}
10
11namespace Service::OLSC {
12
13class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
14public:
15 explicit INativeHandleHolder(Core::System& system_);
16 ~INativeHandleHolder() override;
17
18private:
19 Result GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
20};
21
22} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 889f27c31..18e5ad43f 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -1,226 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/ipc_helpers.h"
5#include "core/hle/service/olsc/olsc.h" 4#include "core/hle/service/olsc/olsc.h"
5#include "core/hle/service/olsc/olsc_service_for_application.h"
6#include "core/hle/service/olsc/olsc_service_for_system_service.h"
6#include "core/hle/service/server_manager.h" 7#include "core/hle/service/server_manager.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Service::OLSC { 10namespace Service::OLSC {
10 11
11class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
12public:
13 explicit IOlscServiceForApplication(Core::System& system_)
14 : ServiceFramework{system_, "olsc:u"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &IOlscServiceForApplication::Initialize, "Initialize"},
18 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
19 {13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
20 {14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
21 {15, nullptr, "SetCustomData"},
22 {16, nullptr, "DeleteSaveDataBackupSetting"},
23 {18, nullptr, "GetSaveDataBackupInfoCache"},
24 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
25 {22, nullptr, "DeleteSaveDataBackupAsync"},
26 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
27 {26, nullptr, "DownloadSaveDataBackupAsync"},
28 {27, nullptr, "UploadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
32 {9015, nullptr, "SetCustomDataForDebug"},
33 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
34 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
35 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
36 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
37 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
38 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43 }
44
45private:
46 void Initialize(HLERequestContext& ctx) {
47 LOG_WARNING(Service_OLSC, "(STUBBED) called");
48
49 initialized = true;
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53 }
54
55 void GetSaveDataBackupSetting(HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 // backup_setting is set to 0 since real value is unknown
59 constexpr u64 backup_setting = 0;
60
61 IPC::ResponseBuilder rb{ctx, 4};
62 rb.Push(ResultSuccess);
63 rb.Push(backup_setting);
64 }
65
66 void SetSaveDataBackupSettingEnabled(HLERequestContext& ctx) {
67 LOG_WARNING(Service_OLSC, "(STUBBED) called");
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(ResultSuccess);
71 }
72
73 bool initialized{};
74};
75
76class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
77public:
78 explicit INativeHandleHolder(Core::System& system_)
79 : ServiceFramework{system_, "INativeHandleHolder"} {
80 // clang-format off
81 static const FunctionInfo functions[] = {
82 {0, nullptr, "GetNativeHandle"},
83 };
84 // clang-format on
85
86 RegisterHandlers(functions);
87 }
88};
89
90class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
91public:
92 explicit ITransferTaskListController(Core::System& system_)
93 : ServiceFramework{system_, "ITransferTaskListController"} {
94 // clang-format off
95 static const FunctionInfo functions[] = {
96 {0, nullptr, "Unknown0"},
97 {1, nullptr, "Unknown1"},
98 {2, nullptr, "Unknown2"},
99 {3, nullptr, "Unknown3"},
100 {4, nullptr, "Unknown4"},
101 {5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
102 {6, nullptr, "Unknown6"},
103 {7, nullptr, "Unknown7"},
104 {8, nullptr, "GetRemoteStorageController"},
105 {9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
106 {10, nullptr, "Unknown10"},
107 {11, nullptr, "Unknown11"},
108 {12, nullptr, "Unknown12"},
109 {13, nullptr, "Unknown13"},
110 {14, nullptr, "Unknown14"},
111 {15, nullptr, "Unknown15"},
112 {16, nullptr, "Unknown16"},
113 {17, nullptr, "Unknown17"},
114 {18, nullptr, "Unknown18"},
115 {19, nullptr, "Unknown19"},
116 {20, nullptr, "Unknown20"},
117 {21, nullptr, "Unknown21"},
118 {22, nullptr, "Unknown22"},
119 {23, nullptr, "Unknown23"},
120 {24, nullptr, "Unknown24"},
121 {25, nullptr, "Unknown25"},
122 };
123 // clang-format on
124
125 RegisterHandlers(functions);
126 }
127
128private:
129 void GetNativeHandleHolder(HLERequestContext& ctx) {
130 LOG_INFO(Service_OLSC, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<INativeHandleHolder>(system);
135 }
136};
137
138class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
139public:
140 explicit IOlscServiceForSystemService(Core::System& system_)
141 : ServiceFramework{system_, "olsc:s"} {
142 // clang-format off
143 static const FunctionInfo functions[] = {
144 {0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
145 {1, nullptr, "OpenRemoteStorageController"},
146 {2, nullptr, "OpenDaemonController"},
147 {10, nullptr, "Unknown10"},
148 {11, nullptr, "Unknown11"},
149 {12, nullptr, "Unknown12"},
150 {13, nullptr, "Unknown13"},
151 {100, nullptr, "ListLastTransferTaskErrorInfo"},
152 {101, nullptr, "GetLastErrorInfoCount"},
153 {102, nullptr, "RemoveLastErrorInfoOld"},
154 {103, nullptr, "GetLastErrorInfo"},
155 {104, nullptr, "GetLastErrorEventHolder"},
156 {105, nullptr, "GetLastTransferTaskErrorInfo"},
157 {200, nullptr, "GetDataTransferPolicyInfo"},
158 {201, nullptr, "RemoveDataTransferPolicyInfo"},
159 {202, nullptr, "UpdateDataTransferPolicyOld"},
160 {203, nullptr, "UpdateDataTransferPolicy"},
161 {204, nullptr, "CleanupDataTransferPolicyInfo"},
162 {205, nullptr, "RequestDataTransferPolicy"},
163 {300, nullptr, "GetAutoTransferSeriesInfo"},
164 {301, nullptr, "UpdateAutoTransferSeriesInfo"},
165 {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
166 {900, nullptr, "CleanupTransferTask"},
167 {902, nullptr, "CleanupSeriesInfoType0"},
168 {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
169 {904, nullptr, "CleanupApplicationAutoTransferSetting"},
170 {905, nullptr, "CleanupErrorHistory"},
171 {906, nullptr, "SetLastError"},
172 {907, nullptr, "AddSaveDataArchiveInfoType0"},
173 {908, nullptr, "RemoveSeriesInfoType0"},
174 {909, nullptr, "GetSeriesInfoType0"},
175 {910, nullptr, "RemoveLastErrorInfo"},
176 {911, nullptr, "CleanupSeriesInfoType1"},
177 {912, nullptr, "RemoveSeriesInfoType1"},
178 {913, nullptr, "GetSeriesInfoType1"},
179 {1000, nullptr, "UpdateIssueOld"},
180 {1010, nullptr, "Unknown1010"},
181 {1011, nullptr, "ListIssueInfoOld"},
182 {1012, nullptr, "GetIssueOld"},
183 {1013, nullptr, "GetIssue2Old"},
184 {1014, nullptr, "GetIssue3Old"},
185 {1020, nullptr, "RepairIssueOld"},
186 {1021, nullptr, "RepairIssueWithUserIdOld"},
187 {1022, nullptr, "RepairIssue2Old"},
188 {1023, nullptr, "RepairIssue3Old"},
189 {1024, nullptr, "Unknown1024"},
190 {1100, nullptr, "UpdateIssue"},
191 {1110, nullptr, "Unknown1110"},
192 {1111, nullptr, "ListIssueInfo"},
193 {1112, nullptr, "GetIssue"},
194 {1113, nullptr, "GetIssue2"},
195 {1114, nullptr, "GetIssue3"},
196 {1120, nullptr, "RepairIssue"},
197 {1121, nullptr, "RepairIssueWithUserId"},
198 {1122, nullptr, "RepairIssue2"},
199 {1123, nullptr, "RepairIssue3"},
200 {1124, nullptr, "Unknown1124"},
201 };
202 // clang-format on
203
204 RegisterHandlers(functions);
205 }
206
207private:
208 void OpenTransferTaskListController(HLERequestContext& ctx) {
209 LOG_INFO(Service_OLSC, "called");
210
211 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
212 rb.Push(ResultSuccess);
213 rb.PushIpcInterface<ITransferTaskListController>(system);
214 }
215};
216
217void LoopProcess(Core::System& system) { 12void LoopProcess(Core::System& system) {
218 auto server_manager = std::make_unique<ServerManager>(system); 13 auto server_manager = std::make_unique<ServerManager>(system);
219 14
220 server_manager->RegisterNamedService("olsc:u", 15 const auto OlscFactoryForApplication = [&] {
221 std::make_shared<IOlscServiceForApplication>(system)); 16 return std::make_shared<IOlscServiceForApplication>(system);
222 server_manager->RegisterNamedService("olsc:s", 17 };
223 std::make_shared<IOlscServiceForSystemService>(system)); 18
19 const auto OlscFactoryForSystemService = [&] {
20 return std::make_shared<IOlscServiceForSystemService>(system);
21 };
22
23 server_manager->RegisterNamedService("olsc:u", OlscFactoryForApplication);
24 server_manager->RegisterNamedService("olsc:s", OlscFactoryForSystemService);
224 25
225 ServerManager::RunServer(std::move(server_manager)); 26 ServerManager::RunServer(std::move(server_manager));
226} 27}
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.cpp b/src/core/hle/service/olsc/olsc_service_for_application.cpp
new file mode 100644
index 000000000..01360f5ef
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.cpp
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/olsc_service_for_application.h"
6
7namespace Service::OLSC {
8
9IOlscServiceForApplication::IOlscServiceForApplication(Core::System& system_)
10 : ServiceFramework{system_, "olsc:u"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IOlscServiceForApplication::Initialize>, "Initialize"},
14 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
15 {13, D<&IOlscServiceForApplication::GetSaveDataBackupSetting>, "GetSaveDataBackupSetting"},
16 {14, D<&IOlscServiceForApplication::SetSaveDataBackupSettingEnabled>, "SetSaveDataBackupSettingEnabled"},
17 {15, nullptr, "SetCustomData"},
18 {16, nullptr, "DeleteSaveDataBackupSetting"},
19 {18, nullptr, "GetSaveDataBackupInfoCache"},
20 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
21 {22, nullptr, "DeleteSaveDataBackupAsync"},
22 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
23 {26, nullptr, "DownloadSaveDataBackupAsync"},
24 {27, nullptr, "UploadSaveDataBackupAsync"},
25 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
26 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
27 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
28 {9015, nullptr, "SetCustomDataForDebug"},
29 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
30 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
31 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
32 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
33 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
34 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IOlscServiceForApplication::~IOlscServiceForApplication() = default;
42
43Result IOlscServiceForApplication::Initialize(ClientProcessId process_id) {
44 LOG_WARNING(Service_OLSC, "(STUBBED) called");
45 initialized = true;
46 R_SUCCEED();
47}
48
49Result IOlscServiceForApplication::GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting) {
50 LOG_WARNING(Service_OLSC, "(STUBBED) called");
51 // backup_setting is set to 0 since real value is unknown
52 *out_save_data_backup_setting = 0;
53 R_SUCCEED();
54}
55
56Result IOlscServiceForApplication::SetSaveDataBackupSettingEnabled(bool enabled,
57 NS::Uid account_id) {
58 LOG_WARNING(Service_OLSC, "(STUBBED) called, enabled={}, account_id={}", enabled,
59 account_id.uuid.FormattedString());
60 R_SUCCEED();
61}
62
63} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.h b/src/core/hle/service/olsc/olsc_service_for_application.h
new file mode 100644
index 000000000..3f9ac7536
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/ns/ns_types.h"
6#include "core/hle/service/service.h"
7
8namespace Service::OLSC {
9
10class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
11public:
12 explicit IOlscServiceForApplication(Core::System& system_);
13 ~IOlscServiceForApplication() override;
14
15private:
16 Result Initialize(ClientProcessId process_id);
17 Result GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting);
18 Result SetSaveDataBackupSettingEnabled(bool enabled, NS::Uid account_id);
19
20 bool initialized{};
21};
22
23} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.cpp b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
new file mode 100644
index 000000000..f027933c9
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
@@ -0,0 +1,117 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/daemon_controller.h"
6#include "core/hle/service/olsc/olsc_service_for_system_service.h"
7#include "core/hle/service/olsc/remote_storage_controller.h"
8#include "core/hle/service/olsc/transfer_task_list_controller.h"
9
10namespace Service::OLSC {
11
12IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_)
13 : ServiceFramework{system_, "olsc:s"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
17 {1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
18 {2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
19 {10, nullptr, "Unknown10"},
20 {11, nullptr, "Unknown11"},
21 {12, nullptr, "Unknown12"},
22 {13, nullptr, "Unknown13"},
23 {100, nullptr, "ListLastTransferTaskErrorInfo"},
24 {101, nullptr, "GetLastErrorInfoCount"},
25 {102, nullptr, "RemoveLastErrorInfoOld"},
26 {103, nullptr, "GetLastErrorInfo"},
27 {104, nullptr, "GetLastErrorEventHolder"},
28 {105, nullptr, "GetLastTransferTaskErrorInfo"},
29 {200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
30 {201, nullptr, "RemoveDataTransferPolicyInfo"},
31 {202, nullptr, "UpdateDataTransferPolicyOld"},
32 {203, nullptr, "UpdateDataTransferPolicy"},
33 {204, nullptr, "CleanupDataTransferPolicyInfo"},
34 {205, nullptr, "RequestDataTransferPolicy"},
35 {300, nullptr, "GetAutoTransferSeriesInfo"},
36 {301, nullptr, "UpdateAutoTransferSeriesInfo"},
37 {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
38 {900, nullptr, "CleanupTransferTask"},
39 {902, nullptr, "CleanupSeriesInfoType0"},
40 {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
41 {904, nullptr, "CleanupApplicationAutoTransferSetting"},
42 {905, nullptr, "CleanupErrorHistory"},
43 {906, nullptr, "SetLastError"},
44 {907, nullptr, "AddSaveDataArchiveInfoType0"},
45 {908, nullptr, "RemoveSeriesInfoType0"},
46 {909, nullptr, "GetSeriesInfoType0"},
47 {910, nullptr, "RemoveLastErrorInfo"},
48 {911, nullptr, "CleanupSeriesInfoType1"},
49 {912, nullptr, "RemoveSeriesInfoType1"},
50 {913, nullptr, "GetSeriesInfoType1"},
51 {1000, nullptr, "UpdateIssueOld"},
52 {1010, nullptr, "Unknown1010"},
53 {1011, nullptr, "ListIssueInfoOld"},
54 {1012, nullptr, "GetIssueOld"},
55 {1013, nullptr, "GetIssue2Old"},
56 {1014, nullptr, "GetIssue3Old"},
57 {1020, nullptr, "RepairIssueOld"},
58 {1021, nullptr, "RepairIssueWithUserIdOld"},
59 {1022, nullptr, "RepairIssue2Old"},
60 {1023, nullptr, "RepairIssue3Old"},
61 {1024, nullptr, "Unknown1024"},
62 {1100, nullptr, "UpdateIssue"},
63 {1110, nullptr, "Unknown1110"},
64 {1111, nullptr, "ListIssueInfo"},
65 {1112, nullptr, "GetIssue"},
66 {1113, nullptr, "GetIssue2"},
67 {1114, nullptr, "GetIssue3"},
68 {1120, nullptr, "RepairIssue"},
69 {1121, nullptr, "RepairIssueWithUserId"},
70 {1122, nullptr, "RepairIssue2"},
71 {1123, nullptr, "RepairIssue3"},
72 {1124, nullptr, "Unknown1124"},
73 {10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
74 };
75 // clang-format on
76
77 RegisterHandlers(functions);
78}
79
80IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
81
82Result IOlscServiceForSystemService::OpenTransferTaskListController(
83 Out<SharedPointer<ITransferTaskListController>> out_interface) {
84 LOG_INFO(Service_OLSC, "called");
85 *out_interface = std::make_shared<ITransferTaskListController>(system);
86 R_SUCCEED();
87}
88
89Result IOlscServiceForSystemService::OpenRemoteStorageController(
90 Out<SharedPointer<IRemoteStorageController>> out_interface) {
91 LOG_INFO(Service_OLSC, "called");
92 *out_interface = std::make_shared<IRemoteStorageController>(system);
93 R_SUCCEED();
94}
95
96Result IOlscServiceForSystemService::OpenDaemonController(
97 Out<SharedPointer<IDaemonController>> out_interface) {
98 LOG_INFO(Service_OLSC, "called");
99 *out_interface = std::make_shared<IDaemonController>(system);
100 R_SUCCEED();
101}
102
103Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(Out<u16> out_policy_info,
104 u64 application_id) {
105 LOG_WARNING(Service_OLSC, "(STUBBED) called");
106 *out_policy_info = 0;
107 R_SUCCEED();
108}
109
110Result IOlscServiceForSystemService::CloneService(
111 Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
112 LOG_INFO(Service_OLSC, "called");
113 *out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
114 R_SUCCEED();
115}
116
117} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.h b/src/core/hle/service/olsc/olsc_service_for_system_service.h
new file mode 100644
index 000000000..13026272a
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class IDaemonController;
10class IRemoteStorageController;
11class ITransferTaskListController;
12
13class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
14public:
15 explicit IOlscServiceForSystemService(Core::System& system_);
16 ~IOlscServiceForSystemService() override;
17
18private:
19 Result OpenTransferTaskListController(
20 Out<SharedPointer<ITransferTaskListController>> out_interface);
21 Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
22 Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
23 Result GetDataTransferPolicyInfo(Out<u16> out_policy_info, u64 application_id);
24 Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
25};
26
27} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.cpp b/src/core/hle/service/olsc/remote_storage_controller.cpp
new file mode 100644
index 000000000..81d9c96ab
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.cpp
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/remote_storage_controller.h"
6
7namespace Service::OLSC {
8
9IRemoteStorageController::IRemoteStorageController(Core::System& system_)
10 : ServiceFramework{system_, "IRemoteStorageController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "GetSaveDataArchiveInfoBySaveDataId"},
14 {1, nullptr, "GetSaveDataArchiveInfoByApplicationId"},
15 {3, nullptr, "GetSaveDataArchiveCount"},
16 {6, nullptr, "CleanupSaveDataArchives"},
17 {7, nullptr, "CreateSaveDataArchiveCacheUpdationTask"},
18 {8, nullptr, "CreateSaveDataArchiveCacheUpdationForSpecifiedApplicationTask"},
19 {9, nullptr, "Delete"},
20 {10, nullptr, "GetSeriesInfo"},
21 {11, nullptr, "CreateDeleteDataTask"},
22 {12, nullptr, "DeleteSeriesInfo"},
23 {13, nullptr, "CreateRegisterNotificationTokenTask"},
24 {14, nullptr, "UpdateSeriesInfo"},
25 {15, nullptr, "RegisterUploadSaveDataTransferTaskForAutonomyRegistration"},
26 {16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
27 {17, nullptr, "ListDataInfo"},
28 {18, nullptr, "GetDataInfo"},
29 {19, nullptr, "Unknown19"},
30 {20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
31 {21, nullptr, "ListSecondarySaves"},
32 {22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
33 {23, nullptr, "TouchSecondarySave"},
34 {24, nullptr, "GetSecondarySaveDataInfo"},
35 {25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
36 {900, nullptr, "Unknown900"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41}
42
43IRemoteStorageController::~IRemoteStorageController() = default;
44
45Result IRemoteStorageController::GetSecondarySave(Out<bool> out_has_secondary_save,
46 Out<std::array<u64, 3>> out_unknown,
47 u64 application_id) {
48 LOG_ERROR(Service_OLSC, "(STUBBED) called, application_id={:016X}", application_id);
49 *out_has_secondary_save = false;
50 *out_unknown = {};
51 R_SUCCEED();
52}
53
54} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.h b/src/core/hle/service/olsc/remote_storage_controller.h
new file mode 100644
index 000000000..e7a0b5244
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.h
@@ -0,0 +1,19 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class IRemoteStorageController final : public ServiceFramework<IRemoteStorageController> {
10public:
11 explicit IRemoteStorageController(Core::System& system_);
12 ~IRemoteStorageController() override;
13
14private:
15 Result GetSecondarySave(Out<bool> out_has_secondary_save, Out<std::array<u64, 3>> out_unknown,
16 u64 application_id);
17};
18
19} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.cpp b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
new file mode 100644
index 000000000..8ea9a0f1e
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/native_handle_holder.h"
6#include "core/hle/service/olsc/transfer_task_list_controller.h"
7
8namespace Service::OLSC {
9
10ITransferTaskListController::ITransferTaskListController(Core::System& system_)
11 : ServiceFramework{system_, "ITransferTaskListController"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, nullptr, "Unknown0"},
15 {1, nullptr, "Unknown1"},
16 {2, nullptr, "Unknown2"},
17 {3, nullptr, "Unknown3"},
18 {4, nullptr, "Unknown4"},
19 {5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
20 {6, nullptr, "Unknown6"},
21 {7, nullptr, "Unknown7"},
22 {8, nullptr, "GetRemoteStorageController"},
23 {9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
24 {10, nullptr, "Unknown10"},
25 {11, nullptr, "Unknown11"},
26 {12, nullptr, "Unknown12"},
27 {13, nullptr, "Unknown13"},
28 {14, nullptr, "Unknown14"},
29 {15, nullptr, "Unknown15"},
30 {16, nullptr, "Unknown16"},
31 {17, nullptr, "Unknown17"},
32 {18, nullptr, "Unknown18"},
33 {19, nullptr, "Unknown19"},
34 {20, nullptr, "Unknown20"},
35 {21, nullptr, "Unknown21"},
36 {22, nullptr, "Unknown22"},
37 {23, nullptr, "Unknown23"},
38 {24, nullptr, "Unknown24"},
39 {25, nullptr, "Unknown25"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ITransferTaskListController::~ITransferTaskListController() = default;
47
48Result ITransferTaskListController::GetNativeHandleHolder(
49 Out<SharedPointer<INativeHandleHolder>> out_holder) {
50 LOG_WARNING(Service_OLSC, "(STUBBED) called");
51 *out_holder = std::make_shared<INativeHandleHolder>(system);
52 R_SUCCEED();
53}
54
55} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.h b/src/core/hle/service/olsc/transfer_task_list_controller.h
new file mode 100644
index 000000000..f10a71375
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class INativeHandleHolder;
10
11class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
12public:
13 explicit ITransferTaskListController(Core::System& system_);
14 ~ITransferTaskListController() override;
15
16private:
17 Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
18};
19
20} // namespace Service::OLSC
diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp
new file mode 100644
index 000000000..f57f2f157
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.cpp
@@ -0,0 +1,434 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/file_sys/control_metadata.h"
6#include "core/file_sys/patch_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/pctl/parental_control_service.h"
9#include "core/hle/service/pctl/pctl_results.h"
10
11namespace Service::PCTL {
12
13IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
14 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
15 service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
16 unlinked_event{service_context}, request_suspension_event{service_context} {
17 // clang-format off
18 static const FunctionInfo functions[] = {
19 {1, D<&IParentalControlService::Initialize>, "Initialize"},
20 {1001, D<&IParentalControlService::CheckFreeCommunicationPermission>, "CheckFreeCommunicationPermission"},
21 {1002, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
22 {1003, D<&IParentalControlService::ConfirmResumeApplicationPermission>, "ConfirmResumeApplicationPermission"},
23 {1004, D<&IParentalControlService::ConfirmSnsPostPermission>, "ConfirmSnsPostPermission"},
24 {1005, nullptr, "ConfirmSystemSettingsPermission"},
25 {1006, D<&IParentalControlService::IsRestrictionTemporaryUnlocked>, "IsRestrictionTemporaryUnlocked"},
26 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
27 {1008, nullptr, "EnterRestrictedSystemSettings"},
28 {1009, nullptr, "LeaveRestrictedSystemSettings"},
29 {1010, D<&IParentalControlService::IsRestrictedSystemSettingsEntered>, "IsRestrictedSystemSettingsEntered"},
30 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
31 {1012, nullptr, "GetRestrictedFeatures"},
32 {1013, D<&IParentalControlService::ConfirmStereoVisionPermission>, "ConfirmStereoVisionPermission"},
33 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
34 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
35 {1016, nullptr, "ConfirmShowNewsPermission"},
36 {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
37 {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
38 {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
39 {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
40 {1033, nullptr, "SetSafetyLevel"},
41 {1034, nullptr, "GetSafetyLevelSettings"},
42 {1035, D<&IParentalControlService::GetCurrentSettings>, "GetCurrentSettings"},
43 {1036, nullptr, "SetCustomSafetyLevelSettings"},
44 {1037, nullptr, "GetDefaultRatingOrganization"},
45 {1038, nullptr, "SetDefaultRatingOrganization"},
46 {1039, D<&IParentalControlService::GetFreeCommunicationApplicationListCount>, "GetFreeCommunicationApplicationListCount"},
47 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
48 {1043, nullptr, "DeleteSettings"},
49 {1044, nullptr, "GetFreeCommunicationApplicationList"},
50 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
51 {1046, nullptr, "DisableFeaturesForReset"},
52 {1047, nullptr, "NotifyApplicationDownloadStarted"},
53 {1048, nullptr, "NotifyNetworkProfileCreated"},
54 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
55 {1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
56 {1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
57 {1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
58 {1064, D<&IParentalControlService::ResetConfirmedStereoVisionPermission>, "ResetConfirmedStereoVisionPermission"},
59 {1065, D<&IParentalControlService::IsStereoVisionPermitted>, "IsStereoVisionPermitted"},
60 {1201, nullptr, "UnlockRestrictionTemporarily"},
61 {1202, nullptr, "UnlockSystemSettingsRestriction"},
62 {1203, nullptr, "SetPinCode"},
63 {1204, nullptr, "GenerateInquiryCode"},
64 {1205, nullptr, "CheckMasterKey"},
65 {1206, D<&IParentalControlService::GetPinCodeLength>, "GetPinCodeLength"},
66 {1207, nullptr, "GetPinCodeChangedEvent"},
67 {1208, nullptr, "GetPinCode"},
68 {1403, D<&IParentalControlService::IsPairingActive>, "IsPairingActive"},
69 {1406, nullptr, "GetSettingsLastUpdated"},
70 {1411, nullptr, "GetPairingAccountInfo"},
71 {1421, nullptr, "GetAccountNickname"},
72 {1424, nullptr, "GetAccountState"},
73 {1425, nullptr, "RequestPostEvents"},
74 {1426, nullptr, "GetPostEventInterval"},
75 {1427, nullptr, "SetPostEventInterval"},
76 {1432, D<&IParentalControlService::GetSynchronizationEvent>, "GetSynchronizationEvent"},
77 {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
78 {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
79 {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
80 {1454, nullptr, "GetPlayTimerRemainingTime"},
81 {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
82 {1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
83 {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
84 {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
85 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
86 {1472, nullptr, "CancelNetworkRequest"},
87 {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
88 {1474, nullptr, "ClearUnlinkedEvent"},
89 {1601, nullptr, "DisableAllFeatures"},
90 {1602, nullptr, "PostEnableAllFeatures"},
91 {1603, nullptr, "IsAllFeaturesDisabled"},
92 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
93 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
94 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
95 {1904, nullptr, "GetExemptApplicationListForDebug"},
96 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
97 {1906, nullptr, "AddToExemptApplicationListForDebug"},
98 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
99 {1908, nullptr, "ClearExemptApplicationListForDebug"},
100 {1941, nullptr, "DeletePairing"},
101 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
102 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
103 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
104 {2001, nullptr, "RequestPairingAsync"},
105 {2002, nullptr, "FinishRequestPairing"},
106 {2003, nullptr, "AuthorizePairingAsync"},
107 {2004, nullptr, "FinishAuthorizePairing"},
108 {2005, nullptr, "RetrievePairingInfoAsync"},
109 {2006, nullptr, "FinishRetrievePairingInfo"},
110 {2007, nullptr, "UnlinkPairingAsync"},
111 {2008, nullptr, "FinishUnlinkPairing"},
112 {2009, nullptr, "GetAccountMiiImageAsync"},
113 {2010, nullptr, "FinishGetAccountMiiImage"},
114 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
115 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
116 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
117 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
118 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
119 {2016, nullptr, "RequestUpdateExemptionListAsync"},
120 };
121 // clang-format on
122 RegisterHandlers(functions);
123}
124
125IParentalControlService::~IParentalControlService() = default;
126
127bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
128 if (states.temporary_unlocked) {
129 return true;
130 }
131 if ((states.application_info.parental_control_flag & 1) == 0) {
132 return true;
133 }
134 if (pin_code[0] == '\0') {
135 return true;
136 }
137 if (!settings.is_free_communication_default_on) {
138 return true;
139 }
140 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
141 // but as we don't have multiproceses support yet, we can just assume our application is
142 // valid for the time being
143 return true;
144}
145
146bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
147 if (states.temporary_unlocked) {
148 return true;
149 }
150 if (pin_code[0] == '\0') {
151 return true;
152 }
153 if (!settings.is_stero_vision_restricted) {
154 return false;
155 }
156 return true;
157}
158
159void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
160 if (settings.disabled) {
161 return;
162 }
163
164 if (pin_code[0] == '\0') {
165 return;
166 }
167 settings.is_stero_vision_restricted = is_restricted;
168}
169
170Result IParentalControlService::Initialize() {
171 LOG_DEBUG(Service_PCTL, "called");
172
173 if (False(capability & (Capability::Application | Capability::System))) {
174 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
175 R_THROW(PCTL::ResultNoCapability);
176 }
177
178 // TODO(ogniK): Recovery flag initialization for pctl:r
179
180 const auto program_id = system.GetApplicationProcessProgramID();
181 if (program_id != 0) {
182 const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
183 system.GetContentProvider()};
184 const auto control = pm.GetControlMetadata();
185 if (control.first) {
186 states.tid_from_event = 0;
187 states.launch_time_valid = false;
188 states.is_suspended = false;
189 states.free_communication = false;
190 states.stereo_vision = false;
191 states.application_info = ApplicationInfo{
192 .application_id = program_id,
193 .age_rating = control.first->GetRatingAge(),
194 .parental_control_flag = control.first->GetParentalControlFlag(),
195 .capability = capability,
196 };
197
198 if (False(capability & (Capability::System | Capability::Recovery))) {
199 // TODO(ogniK): Signal application launch event
200 }
201 }
202 }
203
204 R_SUCCEED();
205}
206
207Result IParentalControlService::CheckFreeCommunicationPermission() {
208 LOG_DEBUG(Service_PCTL, "called");
209
210 if (!CheckFreeCommunicationPermissionImpl()) {
211 R_THROW(PCTL::ResultNoFreeCommunication);
212 } else {
213 states.free_communication = true;
214 R_SUCCEED();
215 }
216}
217
218Result IParentalControlService::ConfirmLaunchApplicationPermission(
219 InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
220 LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
221 application_id);
222 R_SUCCEED();
223}
224
225Result IParentalControlService::ConfirmResumeApplicationPermission(
226 InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
227 LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
228 application_id);
229 R_SUCCEED();
230}
231
232Result IParentalControlService::ConfirmSnsPostPermission() {
233 LOG_WARNING(Service_PCTL, "(STUBBED) called");
234 R_THROW(PCTL::ResultNoFreeCommunication);
235}
236
237Result IParentalControlService::IsRestrictionTemporaryUnlocked(
238 Out<bool> out_is_temporary_unlocked) {
239 *out_is_temporary_unlocked = false;
240 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
241 *out_is_temporary_unlocked);
242 R_SUCCEED();
243}
244
245Result IParentalControlService::IsRestrictedSystemSettingsEntered(
246 Out<bool> out_is_restricted_system_settings_entered) {
247 *out_is_restricted_system_settings_entered = false;
248 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
249 *out_is_restricted_system_settings_entered);
250 R_SUCCEED();
251}
252
253Result IParentalControlService::ConfirmStereoVisionPermission() {
254 LOG_DEBUG(Service_PCTL, "called");
255 states.stereo_vision = true;
256 R_SUCCEED();
257}
258
259Result IParentalControlService::EndFreeCommunication() {
260 LOG_WARNING(Service_PCTL, "(STUBBED) called");
261 R_SUCCEED();
262}
263
264Result IParentalControlService::IsFreeCommunicationAvailable() {
265 LOG_WARNING(Service_PCTL, "(STUBBED) called");
266
267 if (!CheckFreeCommunicationPermissionImpl()) {
268 R_THROW(PCTL::ResultNoFreeCommunication);
269 } else {
270 R_SUCCEED();
271 }
272}
273
274Result IParentalControlService::IsRestrictionEnabled(Out<bool> out_restriction_enabled) {
275 LOG_DEBUG(Service_PCTL, "called");
276
277 if (False(capability & (Capability::Status | Capability::Recovery))) {
278 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
279 *out_restriction_enabled = false;
280 R_THROW(PCTL::ResultNoCapability);
281 }
282
283 *out_restriction_enabled = pin_code[0] != '\0';
284 R_SUCCEED();
285}
286
287Result IParentalControlService::GetSafetyLevel(Out<u32> out_safety_level) {
288 *out_safety_level = 0;
289 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", *out_safety_level);
290 R_SUCCEED();
291}
292
293Result IParentalControlService::GetCurrentSettings(Out<RestrictionSettings> out_settings) {
294 LOG_INFO(Service_PCTL, "called");
295 *out_settings = restriction_settings;
296 R_SUCCEED();
297}
298
299Result IParentalControlService::GetFreeCommunicationApplicationListCount(Out<s32> out_count) {
300 *out_count = 4;
301 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", *out_count);
302 R_SUCCEED();
303}
304
305Result IParentalControlService::ConfirmStereoVisionRestrictionConfigurable() {
306 LOG_DEBUG(Service_PCTL, "called");
307
308 if (False(capability & Capability::StereoVision)) {
309 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
310 R_THROW(PCTL::ResultNoCapability);
311 }
312
313 if (pin_code[0] == '\0') {
314 R_THROW(PCTL::ResultNoRestrictionEnabled);
315 }
316
317 R_SUCCEED();
318}
319
320Result IParentalControlService::IsStereoVisionPermitted(Out<bool> out_is_permitted) {
321 LOG_DEBUG(Service_PCTL, "called");
322
323 if (!ConfirmStereoVisionPermissionImpl()) {
324 *out_is_permitted = false;
325 R_THROW(PCTL::ResultStereoVisionRestricted);
326 } else {
327 *out_is_permitted = true;
328 R_SUCCEED();
329 }
330}
331
332Result IParentalControlService::GetPinCodeLength(Out<s32> out_length) {
333 *out_length = 0;
334 LOG_WARNING(Service_PCTL, "(STUBBED) called, length={}", *out_length);
335 R_SUCCEED();
336}
337
338Result IParentalControlService::IsPairingActive(Out<bool> out_is_pairing_active) {
339 *out_is_pairing_active = false;
340 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", *out_is_pairing_active);
341 R_SUCCEED();
342}
343
344Result IParentalControlService::GetSynchronizationEvent(
345 OutCopyHandle<Kernel::KReadableEvent> out_event) {
346 LOG_INFO(Service_PCTL, "called");
347 *out_event = synchronization_event.GetHandle();
348 R_SUCCEED();
349}
350
351Result IParentalControlService::StartPlayTimer() {
352 LOG_WARNING(Service_PCTL, "(STUBBED) called");
353 R_SUCCEED();
354}
355
356Result IParentalControlService::StopPlayTimer() {
357 LOG_WARNING(Service_PCTL, "(STUBBED) called");
358 R_SUCCEED();
359}
360
361Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled) {
362 *out_is_play_timer_enabled = false;
363 LOG_WARNING(Service_PCTL, "(STUBBED) called, enabled={}", *out_is_play_timer_enabled);
364 R_SUCCEED();
365}
366
367Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
368 *out_is_restricted_by_play_timer = false;
369 LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
370 R_SUCCEED();
371}
372
373Result IParentalControlService::GetPlayTimerSettings(
374 Out<PlayTimerSettings> out_play_timer_settings) {
375 LOG_WARNING(Service_PCTL, "(STUBBED) called");
376 *out_play_timer_settings = {};
377 R_SUCCEED();
378}
379
380Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
381 OutCopyHandle<Kernel::KReadableEvent> out_event) {
382 LOG_INFO(Service_PCTL, "called");
383 *out_event = request_suspension_event.GetHandle();
384 R_SUCCEED();
385}
386
387Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
388 *out_play_timer_alarm_disabled = false;
389 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
390 *out_play_timer_alarm_disabled);
391 R_SUCCEED();
392}
393
394Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
395 LOG_INFO(Service_PCTL, "called");
396 *out_event = unlinked_event.GetHandle();
397 R_SUCCEED();
398}
399
400Result IParentalControlService::GetStereoVisionRestriction(
401 Out<bool> out_stereo_vision_restriction) {
402 LOG_DEBUG(Service_PCTL, "called");
403
404 if (False(capability & Capability::StereoVision)) {
405 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
406 *out_stereo_vision_restriction = false;
407 R_THROW(PCTL::ResultNoCapability);
408 }
409
410 *out_stereo_vision_restriction = settings.is_stero_vision_restricted;
411 R_SUCCEED();
412}
413
414Result IParentalControlService::SetStereoVisionRestriction(bool stereo_vision_restriction) {
415 LOG_DEBUG(Service_PCTL, "called, can_use={}", stereo_vision_restriction);
416
417 if (False(capability & Capability::StereoVision)) {
418 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
419 R_THROW(PCTL::ResultNoCapability);
420 }
421
422 SetStereoVisionRestrictionImpl(stereo_vision_restriction);
423 R_SUCCEED();
424}
425
426Result IParentalControlService::ResetConfirmedStereoVisionPermission() {
427 LOG_DEBUG(Service_PCTL, "called");
428
429 states.stereo_vision = false;
430
431 R_SUCCEED();
432}
433
434} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h
new file mode 100644
index 000000000..03dbaa2e5
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.h
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/os/event.h"
9#include "core/hle/service/pctl/pctl_types.h"
10#include "core/hle/service/service.h"
11
12namespace Service::PCTL {
13
14class IParentalControlService final : public ServiceFramework<IParentalControlService> {
15public:
16 explicit IParentalControlService(Core::System& system_, Capability capability_);
17 ~IParentalControlService() override;
18
19private:
20 bool CheckFreeCommunicationPermissionImpl() const;
21 bool ConfirmStereoVisionPermissionImpl() const;
22 void SetStereoVisionRestrictionImpl(bool is_restricted);
23
24 Result Initialize();
25 Result CheckFreeCommunicationPermission();
26 Result ConfirmLaunchApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
27 u64 nacp_flag, u64 application_id);
28 Result ConfirmResumeApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
29 u64 nacp_flag, u64 application_id);
30 Result ConfirmSnsPostPermission();
31 Result IsRestrictionTemporaryUnlocked(Out<bool> out_is_temporary_unlocked);
32 Result IsRestrictedSystemSettingsEntered(Out<bool> out_is_restricted_system_settings_entered);
33 Result ConfirmStereoVisionPermission();
34 Result EndFreeCommunication();
35 Result IsFreeCommunicationAvailable();
36 Result IsRestrictionEnabled(Out<bool> out_restriction_enabled);
37 Result GetSafetyLevel(Out<u32> out_safety_level);
38 Result GetCurrentSettings(Out<RestrictionSettings> out_settings);
39 Result GetFreeCommunicationApplicationListCount(Out<s32> out_count);
40 Result ConfirmStereoVisionRestrictionConfigurable();
41 Result IsStereoVisionPermitted(Out<bool> out_is_permitted);
42 Result GetPinCodeLength(Out<s32> out_length);
43 Result IsPairingActive(Out<bool> out_is_pairing_active);
44 Result GetSynchronizationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
45 Result StartPlayTimer();
46 Result StopPlayTimer();
47 Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
48 Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
49 Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
50 Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
51 Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
52 Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
53 Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
54 Result SetStereoVisionRestriction(bool stereo_vision_restriction);
55 Result ResetConfirmedStereoVisionPermission();
56
57 struct States {
58 u64 current_tid{};
59 ApplicationInfo application_info{};
60 u64 tid_from_event{};
61 bool launch_time_valid{};
62 bool is_suspended{};
63 bool temporary_unlocked{};
64 bool free_communication{};
65 bool stereo_vision{};
66 };
67
68 struct ParentalControlSettings {
69 bool is_stero_vision_restricted{};
70 bool is_free_communication_default_on{};
71 bool disabled{};
72 };
73
74 States states{};
75 ParentalControlSettings settings{};
76 RestrictionSettings restriction_settings{};
77 std::array<char, 8> pin_code{};
78 Capability capability{};
79
80 KernelHelpers::ServiceContext service_context;
81 Event synchronization_event;
82 Event unlinked_event;
83 Event request_suspension_event;
84};
85
86} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.cpp b/src/core/hle/service/pctl/parental_control_service_factory.cpp
new file mode 100644
index 000000000..7d8f361e9
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/pctl/parental_control_service.h"
6#include "core/hle/service/pctl/parental_control_service_factory.h"
7
8namespace Service::PCTL {
9
10IParentalControlServiceFactory::IParentalControlServiceFactory(Core::System& system_,
11 const char* name_,
12 Capability capability_)
13 : ServiceFramework{system_, name_}, capability{capability_} {
14 static const FunctionInfo functions[] = {
15 {0, D<&IParentalControlServiceFactory::CreateService>, "CreateService"},
16 {1, D<&IParentalControlServiceFactory::CreateServiceWithoutInitialize>,
17 "CreateServiceWithoutInitialize"},
18 };
19 RegisterHandlers(functions);
20}
21
22IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
23
24Result IParentalControlServiceFactory::CreateService(
25 Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
26 LOG_DEBUG(Service_PCTL, "called");
27 // TODO(ogniK): Get application id from process
28 *out_service = std::make_shared<IParentalControlService>(system, capability);
29 R_SUCCEED();
30}
31
32Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
33 Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
34 LOG_DEBUG(Service_PCTL, "called");
35 // TODO(ogniK): Get application id from process
36 *out_service = std::make_shared<IParentalControlService>(system, capability);
37 R_SUCCEED();
38}
39
40} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.h b/src/core/hle/service/pctl/parental_control_service_factory.h
new file mode 100644
index 000000000..362988add
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/pctl/pctl_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PCTL {
11
12class IParentalControlService;
13
14class IParentalControlServiceFactory : public ServiceFramework<IParentalControlServiceFactory> {
15public:
16 explicit IParentalControlServiceFactory(Core::System& system_, const char* name_,
17 Capability capability_);
18 ~IParentalControlServiceFactory() override;
19
20 Result CreateService(Out<SharedPointer<IParentalControlService>> out_service,
21 ClientProcessId process_id);
22 Result CreateServiceWithoutInitialize(Out<SharedPointer<IParentalControlService>> out_service,
23 ClientProcessId process_id);
24
25private:
26 Capability capability{};
27};
28
29void LoopProcess(Core::System& system);
30
31} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 3f47bf094..d92dbe216 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -1,19 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/pctl/parental_control_service_factory.h"
4#include "core/hle/service/pctl/pctl.h" 5#include "core/hle/service/pctl/pctl.h"
6#include "core/hle/service/server_manager.h"
5 7
6namespace Service::PCTL { 8namespace Service::PCTL {
7 9
8PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 10void LoopProcess(Core::System& system) {
9 Capability capability_) 11 auto server_manager = std::make_unique<ServerManager>(system);
10 : Interface{system_, std::move(module_), name, capability_} { 12
11 static const FunctionInfo functions[] = { 13 server_manager->RegisterNamedService("pctl",
12 {0, &PCTL::CreateService, "CreateService"}, 14 std::make_shared<IParentalControlServiceFactory>(
13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 15 system, "pctl",
14 }; 16 Capability::Application | Capability::SnsPost |
15 RegisterHandlers(functions); 17 Capability::Status | Capability::StereoVision));
18 // TODO(ogniK): Implement remaining capabilities
19 server_manager->RegisterNamedService("pctl:a", std::make_shared<IParentalControlServiceFactory>(
20 system, "pctl:a", Capability::None));
21 server_manager->RegisterNamedService("pctl:r", std::make_shared<IParentalControlServiceFactory>(
22 system, "pctl:r", Capability::None));
23 server_manager->RegisterNamedService("pctl:s", std::make_shared<IParentalControlServiceFactory>(
24 system, "pctl:s", Capability::None));
25 ServerManager::RunServer(std::move(server_manager));
16} 26}
17 27
18PCTL::~PCTL() = default;
19} // namespace Service::PCTL 28} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 87f93161e..5f9d03d4d 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -3,19 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/pctl/pctl_module.h"
7
8namespace Core { 6namespace Core {
9class System; 7class System;
10} 8}
11 9
12namespace Service::PCTL { 10namespace Service::PCTL {
13 11
14class PCTL final : public Module::Interface { 12void LoopProcess(Core::System& system);
15public:
16 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
17 Capability capability_);
18 ~PCTL() override;
19};
20 13
21} // namespace Service::PCTL 14} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
deleted file mode 100644
index 6a7fd72bc..000000000
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/pctl/pctl.h"
11#include "core/hle/service/pctl/pctl_module.h"
12#include "core/hle/service/server_manager.h"
13
14namespace Service::PCTL {
15
16namespace Error {
17
18constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
19constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
20constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
21constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
22
23} // namespace Error
24
25class IParentalControlService final : public ServiceFramework<IParentalControlService> {
26public:
27 explicit IParentalControlService(Core::System& system_, Capability capability_)
28 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
29 service_context{system_, "IParentalControlService"} {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {1, &IParentalControlService::Initialize, "Initialize"},
33 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
34 {1002, nullptr, "ConfirmLaunchApplicationPermission"},
35 {1003, nullptr, "ConfirmResumeApplicationPermission"},
36 {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
37 {1005, nullptr, "ConfirmSystemSettingsPermission"},
38 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
39 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
40 {1008, nullptr, "EnterRestrictedSystemSettings"},
41 {1009, nullptr, "LeaveRestrictedSystemSettings"},
42 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
43 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
44 {1012, nullptr, "GetRestrictedFeatures"},
45 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
46 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
47 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
48 {1016, nullptr, "ConfirmShowNewsPermission"},
49 {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
50 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
51 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
52 {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
53 {1033, nullptr, "SetSafetyLevel"},
54 {1034, nullptr, "GetSafetyLevelSettings"},
55 {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
56 {1036, nullptr, "SetCustomSafetyLevelSettings"},
57 {1037, nullptr, "GetDefaultRatingOrganization"},
58 {1038, nullptr, "SetDefaultRatingOrganization"},
59 {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
60 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
61 {1043, nullptr, "DeleteSettings"},
62 {1044, nullptr, "GetFreeCommunicationApplicationList"},
63 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
64 {1046, nullptr, "DisableFeaturesForReset"},
65 {1047, nullptr, "NotifyApplicationDownloadStarted"},
66 {1048, nullptr, "NotifyNetworkProfileCreated"},
67 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
68 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
69 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
70 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
71 {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
72 {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
73 {1201, nullptr, "UnlockRestrictionTemporarily"},
74 {1202, nullptr, "UnlockSystemSettingsRestriction"},
75 {1203, nullptr, "SetPinCode"},
76 {1204, nullptr, "GenerateInquiryCode"},
77 {1205, nullptr, "CheckMasterKey"},
78 {1206, nullptr, "GetPinCodeLength"},
79 {1207, nullptr, "GetPinCodeChangedEvent"},
80 {1208, nullptr, "GetPinCode"},
81 {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
82 {1406, nullptr, "GetSettingsLastUpdated"},
83 {1411, nullptr, "GetPairingAccountInfo"},
84 {1421, nullptr, "GetAccountNickname"},
85 {1424, nullptr, "GetAccountState"},
86 {1425, nullptr, "RequestPostEvents"},
87 {1426, nullptr, "GetPostEventInterval"},
88 {1427, nullptr, "SetPostEventInterval"},
89 {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
90 {1451, nullptr, "StartPlayTimer"},
91 {1452, nullptr, "StopPlayTimer"},
92 {1453, nullptr, "IsPlayTimerEnabled"},
93 {1454, nullptr, "GetPlayTimerRemainingTime"},
94 {1455, nullptr, "IsRestrictedByPlayTimer"},
95 {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
96 {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
97 {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
98 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
99 {1472, nullptr, "CancelNetworkRequest"},
100 {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
101 {1474, nullptr, "ClearUnlinkedEvent"},
102 {1601, nullptr, "DisableAllFeatures"},
103 {1602, nullptr, "PostEnableAllFeatures"},
104 {1603, nullptr, "IsAllFeaturesDisabled"},
105 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
106 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
107 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
108 {1904, nullptr, "GetExemptApplicationListForDebug"},
109 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
110 {1906, nullptr, "AddToExemptApplicationListForDebug"},
111 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
112 {1908, nullptr, "ClearExemptApplicationListForDebug"},
113 {1941, nullptr, "DeletePairing"},
114 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
115 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
116 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
117 {2001, nullptr, "RequestPairingAsync"},
118 {2002, nullptr, "FinishRequestPairing"},
119 {2003, nullptr, "AuthorizePairingAsync"},
120 {2004, nullptr, "FinishAuthorizePairing"},
121 {2005, nullptr, "RetrievePairingInfoAsync"},
122 {2006, nullptr, "FinishRetrievePairingInfo"},
123 {2007, nullptr, "UnlinkPairingAsync"},
124 {2008, nullptr, "FinishUnlinkPairing"},
125 {2009, nullptr, "GetAccountMiiImageAsync"},
126 {2010, nullptr, "FinishGetAccountMiiImage"},
127 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
128 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
129 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
130 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
131 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
132 {2016, nullptr, "RequestUpdateExemptionListAsync"},
133 };
134 // clang-format on
135 RegisterHandlers(functions);
136
137 synchronization_event =
138 service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
139 unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
140 request_suspension_event =
141 service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
142 }
143
144 ~IParentalControlService() {
145 service_context.CloseEvent(synchronization_event);
146 service_context.CloseEvent(unlinked_event);
147 service_context.CloseEvent(request_suspension_event);
148 };
149
150private:
151 bool CheckFreeCommunicationPermissionImpl() const {
152 if (states.temporary_unlocked) {
153 return true;
154 }
155 if ((states.application_info.parental_control_flag & 1) == 0) {
156 return true;
157 }
158 if (pin_code[0] == '\0') {
159 return true;
160 }
161 if (!settings.is_free_communication_default_on) {
162 return true;
163 }
164 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
165 // but as we don't have multiproceses support yet, we can just assume our application is
166 // valid for the time being
167 return true;
168 }
169
170 bool ConfirmStereoVisionPermissionImpl() const {
171 if (states.temporary_unlocked) {
172 return true;
173 }
174 if (pin_code[0] == '\0') {
175 return true;
176 }
177 if (!settings.is_stero_vision_restricted) {
178 return false;
179 }
180 return true;
181 }
182
183 void SetStereoVisionRestrictionImpl(bool is_restricted) {
184 if (settings.disabled) {
185 return;
186 }
187
188 if (pin_code[0] == '\0') {
189 return;
190 }
191 settings.is_stero_vision_restricted = is_restricted;
192 }
193
194 void Initialize(HLERequestContext& ctx) {
195 LOG_DEBUG(Service_PCTL, "called");
196 IPC::ResponseBuilder rb{ctx, 2};
197
198 if (False(capability & (Capability::Application | Capability::System))) {
199 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
200 return;
201 }
202
203 // TODO(ogniK): Recovery flag initialization for pctl:r
204
205 const auto tid = system.GetApplicationProcessProgramID();
206 if (tid != 0) {
207 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
208 system.GetContentProvider()};
209 const auto control = pm.GetControlMetadata();
210 if (control.first) {
211 states.tid_from_event = 0;
212 states.launch_time_valid = false;
213 states.is_suspended = false;
214 states.free_communication = false;
215 states.stereo_vision = false;
216 states.application_info = ApplicationInfo{
217 .tid = tid,
218 .age_rating = control.first->GetRatingAge(),
219 .parental_control_flag = control.first->GetParentalControlFlag(),
220 .capability = capability,
221 };
222
223 if (False(capability & (Capability::System | Capability::Recovery))) {
224 // TODO(ogniK): Signal application launch event
225 }
226 }
227 }
228
229 rb.Push(ResultSuccess);
230 }
231
232 void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
233 LOG_DEBUG(Service_PCTL, "called");
234
235 IPC::ResponseBuilder rb{ctx, 2};
236 if (!CheckFreeCommunicationPermissionImpl()) {
237 rb.Push(Error::ResultNoFreeCommunication);
238 } else {
239 rb.Push(ResultSuccess);
240 }
241
242 states.free_communication = true;
243 }
244
245 void ConfirmSnsPostPermission(HLERequestContext& ctx) {
246 LOG_WARNING(Service_PCTL, "(STUBBED) called");
247
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(Error::ResultNoFreeCommunication);
250 }
251
252 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
253 const bool is_temporary_unlocked = false;
254
255 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
256 is_temporary_unlocked);
257
258 IPC::ResponseBuilder rb{ctx, 3};
259 rb.Push(ResultSuccess);
260 rb.Push<u8>(is_temporary_unlocked);
261 }
262
263 void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
264 LOG_DEBUG(Service_PCTL, "called");
265 states.stereo_vision = true;
266
267 IPC::ResponseBuilder rb{ctx, 2};
268 rb.Push(ResultSuccess);
269 }
270
271 void EndFreeCommunication(HLERequestContext& ctx) {
272 LOG_WARNING(Service_PCTL, "(STUBBED) called");
273
274 IPC::ResponseBuilder rb{ctx, 2};
275 rb.Push(ResultSuccess);
276 }
277
278 void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
279 LOG_WARNING(Service_PCTL, "(STUBBED) called");
280
281 IPC::ResponseBuilder rb{ctx, 2};
282 if (!CheckFreeCommunicationPermissionImpl()) {
283 rb.Push(Error::ResultNoFreeCommunication);
284 } else {
285 rb.Push(ResultSuccess);
286 }
287 }
288
289 void IsRestrictionEnabled(HLERequestContext& ctx) {
290 LOG_DEBUG(Service_PCTL, "called");
291
292 IPC::ResponseBuilder rb{ctx, 3};
293 if (False(capability & (Capability::Status | Capability::Recovery))) {
294 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
295 rb.Push(Error::ResultNoCapability);
296 rb.Push(false);
297 return;
298 }
299
300 rb.Push(pin_code[0] != '\0');
301 }
302
303 void GetSafetyLevel(HLERequestContext& ctx) {
304 const u32 safety_level = 0;
305
306 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
307
308 IPC::ResponseBuilder rb{ctx, 3};
309 rb.Push(ResultSuccess);
310 rb.Push(safety_level);
311 }
312
313 void GetCurrentSettings(HLERequestContext& ctx) {
314 LOG_INFO(Service_PCTL, "called");
315
316 IPC::ResponseBuilder rb{ctx, 3};
317 rb.Push(ResultSuccess);
318 rb.PushRaw(restriction_settings);
319 }
320
321 void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
322 const u32 count = 4;
323
324 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
325
326 IPC::ResponseBuilder rb{ctx, 3};
327 rb.Push(ResultSuccess);
328 rb.Push(count);
329 }
330
331 void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
332 LOG_DEBUG(Service_PCTL, "called");
333
334 IPC::ResponseBuilder rb{ctx, 2};
335
336 if (False(capability & Capability::StereoVision)) {
337 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
338 rb.Push(Error::ResultNoCapability);
339 return;
340 }
341
342 if (pin_code[0] == '\0') {
343 rb.Push(Error::ResultNoRestrictionEnabled);
344 return;
345 }
346
347 rb.Push(ResultSuccess);
348 }
349
350 void IsStereoVisionPermitted(HLERequestContext& ctx) {
351 LOG_DEBUG(Service_PCTL, "called");
352
353 IPC::ResponseBuilder rb{ctx, 3};
354 if (!ConfirmStereoVisionPermissionImpl()) {
355 rb.Push(Error::ResultStereoVisionRestricted);
356 rb.Push(false);
357 } else {
358 rb.Push(ResultSuccess);
359 rb.Push(true);
360 }
361 }
362
363 void IsPairingActive(HLERequestContext& ctx) {
364 const bool is_pairing_active = false;
365
366 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
367
368 IPC::ResponseBuilder rb{ctx, 3};
369 rb.Push(ResultSuccess);
370 rb.Push<u8>(is_pairing_active);
371 }
372
373 void GetSynchronizationEvent(HLERequestContext& ctx) {
374 LOG_INFO(Service_PCTL, "called");
375
376 IPC::ResponseBuilder rb{ctx, 2, 1};
377 rb.Push(ResultSuccess);
378 rb.PushCopyObjects(synchronization_event->GetReadableEvent());
379 }
380
381 void GetPlayTimerSettings(HLERequestContext& ctx) {
382 LOG_WARNING(Service_PCTL, "(STUBBED) called");
383
384 const PlayTimerSettings timer_settings{};
385
386 IPC::ResponseBuilder rb{ctx, 15};
387 rb.Push(ResultSuccess);
388 rb.PushRaw(timer_settings);
389 }
390
391 void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
392 LOG_INFO(Service_PCTL, "called");
393
394 IPC::ResponseBuilder rb{ctx, 2, 1};
395 rb.Push(ResultSuccess);
396 rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
397 }
398
399 void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
400 const bool is_play_timer_alarm_disabled = false;
401
402 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
403 is_play_timer_alarm_disabled);
404
405 IPC::ResponseBuilder rb{ctx, 3};
406 rb.Push(ResultSuccess);
407 rb.Push<u8>(is_play_timer_alarm_disabled);
408 }
409
410 void GetUnlinkedEvent(HLERequestContext& ctx) {
411 LOG_INFO(Service_PCTL, "called");
412
413 IPC::ResponseBuilder rb{ctx, 2, 1};
414 rb.Push(ResultSuccess);
415 rb.PushCopyObjects(unlinked_event->GetReadableEvent());
416 }
417
418 void SetStereoVisionRestriction(HLERequestContext& ctx) {
419 IPC::RequestParser rp{ctx};
420 const auto can_use = rp.Pop<bool>();
421 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
422
423 IPC::ResponseBuilder rb{ctx, 2};
424 if (False(capability & Capability::StereoVision)) {
425 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
426 rb.Push(Error::ResultNoCapability);
427 return;
428 }
429
430 SetStereoVisionRestrictionImpl(can_use);
431 rb.Push(ResultSuccess);
432 }
433
434 void GetStereoVisionRestriction(HLERequestContext& ctx) {
435 LOG_DEBUG(Service_PCTL, "called");
436
437 IPC::ResponseBuilder rb{ctx, 3};
438 if (False(capability & Capability::StereoVision)) {
439 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
440 rb.Push(Error::ResultNoCapability);
441 rb.Push(false);
442 return;
443 }
444
445 rb.Push(ResultSuccess);
446 rb.Push(settings.is_stero_vision_restricted);
447 }
448
449 void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
450 LOG_DEBUG(Service_PCTL, "called");
451
452 states.stereo_vision = false;
453
454 IPC::ResponseBuilder rb{ctx, 2};
455 rb.Push(ResultSuccess);
456 }
457
458 struct ApplicationInfo {
459 u64 tid{};
460 std::array<u8, 32> age_rating{};
461 u32 parental_control_flag{};
462 Capability capability{};
463 };
464
465 struct States {
466 u64 current_tid{};
467 ApplicationInfo application_info{};
468 u64 tid_from_event{};
469 bool launch_time_valid{};
470 bool is_suspended{};
471 bool temporary_unlocked{};
472 bool free_communication{};
473 bool stereo_vision{};
474 };
475
476 struct ParentalControlSettings {
477 bool is_stero_vision_restricted{};
478 bool is_free_communication_default_on{};
479 bool disabled{};
480 };
481
482 // This is nn::pctl::RestrictionSettings
483 struct RestrictionSettings {
484 u8 rating_age;
485 bool sns_post_restriction;
486 bool free_communication_restriction;
487 };
488 static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
489
490 // This is nn::pctl::PlayTimerSettings
491 struct PlayTimerSettings {
492 std::array<u32, 13> settings;
493 };
494 static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
495
496 States states{};
497 ParentalControlSettings settings{};
498 RestrictionSettings restriction_settings{};
499 std::array<char, 8> pin_code{};
500 Capability capability{};
501
502 Kernel::KEvent* synchronization_event;
503 Kernel::KEvent* unlinked_event;
504 Kernel::KEvent* request_suspension_event;
505 KernelHelpers::ServiceContext service_context;
506};
507
508void Module::Interface::CreateService(HLERequestContext& ctx) {
509 LOG_DEBUG(Service_PCTL, "called");
510
511 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
512 rb.Push(ResultSuccess);
513 // TODO(ogniK): Get TID from process
514
515 rb.PushIpcInterface<IParentalControlService>(system, capability);
516}
517
518void Module::Interface::CreateServiceWithoutInitialize(HLERequestContext& ctx) {
519 LOG_DEBUG(Service_PCTL, "called");
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522 rb.Push(ResultSuccess);
523 rb.PushIpcInterface<IParentalControlService>(system, capability);
524}
525
526Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
527 const char* name_, Capability capability_)
528 : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
529
530Module::Interface::~Interface() = default;
531
532void LoopProcess(Core::System& system) {
533 auto server_manager = std::make_unique<ServerManager>(system);
534
535 auto module = std::make_shared<Module>();
536 server_manager->RegisterNamedService(
537 "pctl", std::make_shared<PCTL>(system, module, "pctl",
538 Capability::Application | Capability::SnsPost |
539 Capability::Status | Capability::StereoVision));
540 // TODO(ogniK): Implement remaining capabilities
541 server_manager->RegisterNamedService(
542 "pctl:a", std::make_shared<PCTL>(system, module, "pctl:a", Capability::None));
543 server_manager->RegisterNamedService(
544 "pctl:r", std::make_shared<PCTL>(system, module, "pctl:r", Capability::None));
545 server_manager->RegisterNamedService(
546 "pctl:s", std::make_shared<PCTL>(system, module, "pctl:s", Capability::None));
547 ServerManager::RunServer(std::move(server_manager));
548}
549
550} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.h b/src/core/hle/service/pctl/pctl_module.h
deleted file mode 100644
index dff0d3f08..000000000
--- a/src/core/hle/service/pctl/pctl_module.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::PCTL {
14
15enum class Capability : u32 {
16 None = 0,
17 Application = 1 << 0,
18 SnsPost = 1 << 1,
19 Recovery = 1 << 6,
20 Status = 1 << 8,
21 StereoVision = 1 << 9,
22 System = 1 << 15,
23};
24DECLARE_ENUM_FLAG_OPERATORS(Capability);
25
26class Module final {
27public:
28 class Interface : public ServiceFramework<Interface> {
29 public:
30 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
31 const char* name_, Capability capability_);
32 ~Interface() override;
33
34 void CreateService(HLERequestContext& ctx);
35 void CreateServiceWithoutInitialize(HLERequestContext& ctx);
36
37 protected:
38 std::shared_ptr<Module> module;
39
40 private:
41 Capability capability{};
42 };
43};
44
45void LoopProcess(Core::System& system);
46
47} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_results.h b/src/core/hle/service/pctl/pctl_results.h
new file mode 100644
index 000000000..1fc54727b
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_results.h
@@ -0,0 +1,15 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::PCTL {
9
10constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
11constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
12constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
13constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
14
15} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_types.h b/src/core/hle/service/pctl/pctl_types.h
new file mode 100644
index 000000000..daaecdf48
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_types.h
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7
8namespace Service::PCTL {
9
10enum class Capability : u32 {
11 None = 0,
12 Application = 1 << 0,
13 SnsPost = 1 << 1,
14 Recovery = 1 << 6,
15 Status = 1 << 8,
16 StereoVision = 1 << 9,
17 System = 1 << 15,
18};
19DECLARE_ENUM_FLAG_OPERATORS(Capability);
20
21struct ApplicationInfo {
22 u64 application_id{};
23 std::array<u8, 32> age_rating{};
24 u32 parental_control_flag{};
25 Capability capability{};
26};
27static_assert(sizeof(ApplicationInfo) == 0x30, "ApplicationInfo has incorrect size.");
28
29// This is nn::pctl::RestrictionSettings
30struct RestrictionSettings {
31 u8 rating_age;
32 bool sns_post_restriction;
33 bool free_communication_restriction;
34};
35static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
36
37// This is nn::pctl::PlayTimerSettings
38struct PlayTimerSettings {
39 std::array<u32, 13> settings;
40};
41static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
42
43} // namespace Service::PCTL
diff --git a/src/core/hle/service/psc/ovln/ovln_types.h b/src/core/hle/service/psc/ovln/ovln_types.h
new file mode 100644
index 000000000..343b05dcc
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/ovln_types.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8
9namespace Service::PSC {
10
11using OverlayNotification = std::array<u64, 0x10>;
12static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");
13
14union MessageFlags {
15 u64 raw;
16 BitField<0, 8, u64> message_type;
17 BitField<8, 8, u64> queue_type;
18};
19static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.cpp b/src/core/hle/service/psc/ovln/receiver.cpp
new file mode 100644
index 000000000..85f62816d
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/ovln/receiver.h"
5
6namespace Service::PSC {
7
8IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AddSource"},
12 {1, nullptr, "RemoveSource"},
13 {2, nullptr, "GetReceiveEventHandle"},
14 {3, nullptr, "Receive"},
15 {4, nullptr, "ReceiveWithTick"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IReceiver::~IReceiver() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.h b/src/core/hle/service/psc/ovln/receiver.h
new file mode 100644
index 000000000..c47a4ff7e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IReceiver final : public ServiceFramework<IReceiver> {
11public:
12 explicit IReceiver(Core::System& system_);
13 ~IReceiver() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.cpp b/src/core/hle/service/psc/ovln/receiver_service.cpp
new file mode 100644
index 000000000..bb988e905
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/receiver.h"
6#include "core/hle/service/psc/ovln/receiver_service.h"
7
8namespace Service::PSC {
9
10IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IReceiverService::~IReceiverService() = default;
21
22Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_receiver = std::make_shared<IReceiver>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.h b/src/core/hle/service/psc/ovln/receiver_service.h
new file mode 100644
index 000000000..b3b31ba4a
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IReceiver;
12
13class IReceiverService final : public ServiceFramework<IReceiverService> {
14public:
15 explicit IReceiverService(Core::System& system_);
16 ~IReceiverService() override;
17
18private:
19 Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.cpp b/src/core/hle/service/psc/ovln/sender.cpp
new file mode 100644
index 000000000..3227a56f2
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.cpp
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6
7namespace Service::PSC {
8
9ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, D<&ISender::Send>, "Send"},
13 {1, nullptr, "GetUnreceivedMessageCount"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISender::~ISender() = default;
21
22Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
23 std::string data;
24 for (const auto m : notification) {
25 data += fmt::format("{:016X} ", m);
26 }
27
28 LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
29 R_SUCCEED();
30}
31
32} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.h b/src/core/hle/service/psc/ovln/sender.h
new file mode 100644
index 000000000..c1575428e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/psc/ovln/ovln_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PSC {
11
12class ISender final : public ServiceFramework<ISender> {
13public:
14 explicit ISender(Core::System& system_);
15 ~ISender() override;
16
17private:
18 Result Send(const OverlayNotification& notification, MessageFlags flags);
19};
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.cpp b/src/core/hle/service/psc/ovln/sender_service.cpp
new file mode 100644
index 000000000..18d2c83a3
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6#include "core/hle/service/psc/ovln/sender_service.h"
7
8namespace Service::PSC {
9
10ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&ISenderService::OpenSender>, "OpenSender"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISenderService::~ISenderService() = default;
21
22Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
23 std::array<u64, 2> data) {
24 LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
25 data[0], data[1]);
26 *out_sender = std::make_shared<ISender>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.h b/src/core/hle/service/psc/ovln/sender_service.h
new file mode 100644
index 000000000..10027701f
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class ISender;
12
13class ISenderService final : public ServiceFramework<ISenderService> {
14public:
15 explicit ISenderService(Core::System& system_);
16 ~ISenderService() override;
17
18private:
19 Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
20 std::array<u64, 2> data);
21};
22
23} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.cpp b/src/core/hle/service/psc/pm_control.cpp
new file mode 100644
index 000000000..7dedb7662
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_control.h"
5
6namespace Service::PSC {
7
8IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "DispatchRequest"},
13 {2, nullptr, "GetResult"},
14 {3, nullptr, "GetState"},
15 {4, nullptr, "Cancel"},
16 {5, nullptr, "PrintModuleInformation"},
17 {6, nullptr, "GetModuleInformation"},
18 {10, nullptr, "AcquireStateLock"},
19 {11, nullptr, "HasStateLock"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26IPmControl::~IPmControl() = default;
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.h b/src/core/hle/service/psc/pm_control.h
new file mode 100644
index 000000000..e0ae2f39c
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmControl final : public ServiceFramework<IPmControl> {
11public:
12 explicit IPmControl(Core::System& system_);
13 ~IPmControl() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.cpp b/src/core/hle/service/psc/pm_module.cpp
new file mode 100644
index 000000000..74dc7ed4e
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_module.h"
5
6namespace Service::PSC {
7
8IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "GetRequest"},
13 {2, nullptr, "Acknowledge"},
14 {3, nullptr, "Finalize"},
15 {4, nullptr, "AcknowledgeEx"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IPmModule::~IPmModule() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.h b/src/core/hle/service/psc/pm_module.h
new file mode 100644
index 000000000..b3a2d2584
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmModule final : public ServiceFramework<IPmModule> {
11public:
12 explicit IPmModule(Core::System& system_);
13 ~IPmModule() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.cpp b/src/core/hle/service/psc/pm_service.cpp
new file mode 100644
index 000000000..c4e0ad228
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/pm_module.h"
6#include "core/hle/service/psc/pm_service.h"
7
8namespace Service::PSC {
9
10IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IPmService::GetPmModule>, "GetPmModule"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IPmService::~IPmService() = default;
21
22Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_module = std::make_shared<IPmModule>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.h b/src/core/hle/service/psc/pm_service.h
new file mode 100644
index 000000000..08e14c6f8
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IPmModule;
12
13class IPmService final : public ServiceFramework<IPmService> {
14public:
15 explicit IPmService(Core::System& system_);
16 ~IPmService() override;
17
18private:
19 Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 44310756b..e1762d694 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -1,11 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory> 4#include "core/hle/service/psc/ovln/receiver_service.h"
5 5#include "core/hle/service/psc/ovln/sender_service.h"
6#include "common/logging/log.h" 6#include "core/hle/service/psc/pm_control.h"
7#include "core/core.h" 7#include "core/hle/service/psc/pm_service.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/psc/psc.h" 8#include "core/hle/service/psc/psc.h"
10#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
11#include "core/hle/service/psc/time/power_state_service.h" 10#include "core/hle/service/psc/time/power_state_service.h"
@@ -15,71 +14,13 @@
15 14
16namespace Service::PSC { 15namespace Service::PSC {
17 16
18class IPmControl final : public ServiceFramework<IPmControl> {
19public:
20 explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "Initialize"},
24 {1, nullptr, "DispatchRequest"},
25 {2, nullptr, "GetResult"},
26 {3, nullptr, "GetState"},
27 {4, nullptr, "Cancel"},
28 {5, nullptr, "PrintModuleInformation"},
29 {6, nullptr, "GetModuleInformation"},
30 {10, nullptr, "AcquireStateLock"},
31 {11, nullptr, "HasStateLock"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36 }
37};
38
39class IPmModule final : public ServiceFramework<IPmModule> {
40public:
41 explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
42 // clang-format off
43 static const FunctionInfo functions[] = {
44 {0, nullptr, "Initialize"},
45 {1, nullptr, "GetRequest"},
46 {2, nullptr, "Acknowledge"},
47 {3, nullptr, "Finalize"},
48 {4, nullptr, "AcknowledgeEx"},
49 };
50 // clang-format on
51
52 RegisterHandlers(functions);
53 }
54};
55
56class IPmService final : public ServiceFramework<IPmService> {
57public:
58 explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
59 // clang-format off
60 static const FunctionInfo functions[] = {
61 {0, &IPmService::GetPmModule, "GetPmModule"},
62 };
63 // clang-format on
64
65 RegisterHandlers(functions);
66 }
67
68private:
69 void GetPmModule(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_PSC, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<IPmModule>(system);
75 }
76};
77
78void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
79 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
80 19
81 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); 20 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
82 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); 21 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
22 server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
23 server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));
83 24
84 auto time = std::make_shared<Time::TimeManager>(system); 25 auto time = std::make_shared<Time::TimeManager>(system);
85 26
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index 459137f42..c83d07ca8 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -7,10 +7,6 @@ namespace Core {
7class System; 7class System;
8} 8}
9 9
10namespace Service::SM {
11class ServiceManager;
12}
13
14namespace Service::PSC { 10namespace Service::PSC {
15 11
16void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp
index 24b85cc61..9a0adb295 100644
--- a/src/core/hle/service/psc/time/static.cpp
+++ b/src/core/hle/service/psc/time/static.cpp
@@ -144,7 +144,9 @@ Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
144 144
145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
146 Out<bool> out_is_enabled) { 146 Out<bool> out_is_enabled) {
147 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); }); 147 SCOPE_EXIT {
148 LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled);
149 };
148 150
149 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 151 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
150 152
@@ -180,7 +182,9 @@ Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
180} 182}
181 183
182Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 184Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 185 SCOPE_EXIT {
186 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
187 };
184 188
185 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); 189 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
186 190
@@ -189,7 +193,9 @@ Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> o
189 193
190Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 194Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
191 Out<SteadyClockTimePoint> out_time_point) { 195 Out<SteadyClockTimePoint> out_time_point) {
192 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 196 SCOPE_EXIT {
197 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
198 };
193 199
194 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 200 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
195 201
@@ -200,7 +206,9 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
200 206
201Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 207Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
202 Out<s64> out_time, const SystemClockContext& context) { 208 Out<s64> out_time, const SystemClockContext& context) {
203 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 209 SCOPE_EXIT {
210 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
211 };
204 212
205 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); 213 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
206 214
@@ -219,8 +227,9 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
219} 227}
220 228
221Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) { 229Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
222 SCOPE_EXIT( 230 SCOPE_EXIT {
223 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 231 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
232 };
224 233
225 SystemClockContext user_context{}; 234 SystemClockContext user_context{};
226 R_TRY(m_user_system_clock.GetContext(user_context)); 235 R_TRY(m_user_system_clock.GetContext(user_context));
@@ -234,11 +243,11 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
234Result StaticService::GetClockSnapshotFromSystemClockContext( 243Result StaticService::GetClockSnapshotFromSystemClockContext(
235 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context, 244 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
236 const SystemClockContext& network_context) { 245 const SystemClockContext& network_context) {
237 SCOPE_EXIT({ 246 SCOPE_EXIT {
238 LOG_DEBUG(Service_Time, 247 LOG_DEBUG(Service_Time,
239 "called. type={} user_context={} network_context={} out_snapshot={}", type, 248 "called. type={} user_context={} network_context={} out_snapshot={}", type,
240 user_context, network_context, *out_snapshot); 249 user_context, network_context, *out_snapshot);
241 }); 250 };
242 251
243 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); 252 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
244} 253}
@@ -246,9 +255,9 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
246Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference, 255Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
247 InClockSnapshot a, 256 InClockSnapshot a,
248 InClockSnapshot b) { 257 InClockSnapshot b) {
249 SCOPE_EXIT({ 258 SCOPE_EXIT {
250 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference); 259 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
251 }); 260 };
252 261
253 auto diff_s = 262 auto diff_s =
254 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset); 263 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
@@ -276,7 +285,9 @@ Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64>
276 285
277Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 286Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
278 InClockSnapshot b) { 287 InClockSnapshot b) {
279 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 288 SCOPE_EXIT {
289 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
290 };
280 291
281 s64 time_s{}; 292 s64 time_s{};
282 auto res = 293 auto res =
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp
index 948610a2b..78dcf532c 100644
--- a/src/core/hle/service/psc/time/steady_clock.cpp
+++ b/src/core/hle/service/psc/time/steady_clock.cpp
@@ -29,7 +29,9 @@ SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> man
29} 29}
30 30
31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) { 31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) {
32 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 32 SCOPE_EXIT {
33 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
34 };
33 35
34 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 36 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
35 ResultClockUninitialized); 37 ResultClockUninitialized);
@@ -38,7 +40,9 @@ Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point
38} 40}
39 41
40Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) { 42Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) {
41 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); }); 43 SCOPE_EXIT {
44 LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset);
45 };
42 46
43 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 47 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
44 ResultClockUninitialized); 48 ResultClockUninitialized);
@@ -59,7 +63,9 @@ Result SteadyClock::SetTestOffset(s64 test_offset) {
59} 63}
60 64
61Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { 65Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
62 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 66 SCOPE_EXIT {
67 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
68 };
63 69
64 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 70 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
65 ResultClockUninitialized); 71 ResultClockUninitialized);
@@ -68,7 +74,9 @@ Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
68} 74}
69 75
70Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { 76Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
71 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); }); 77 SCOPE_EXIT {
78 LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected);
79 };
72 80
73 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 81 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
74 ResultClockUninitialized); 82 ResultClockUninitialized);
@@ -78,7 +86,9 @@ Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
78} 86}
79 87
80Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { 88Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
81 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); }); 89 SCOPE_EXIT {
90 LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw);
91 };
82 92
83 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 93 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
84 ResultClockUninitialized); 94 ResultClockUninitialized);
@@ -88,8 +98,9 @@ Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
88} 98}
89 99
90Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) { 100Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) {
91 SCOPE_EXIT( 101 SCOPE_EXIT {
92 { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); }); 102 LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset);
103 };
93 104
94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 105 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
95 ResultClockUninitialized); 106 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp
index b4e9264d8..9f841d8e0 100644
--- a/src/core/hle/service/psc/time/system_clock.cpp
+++ b/src/core/hle/service/psc/time/system_clock.cpp
@@ -26,7 +26,9 @@ SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, boo
26} 26}
27 27
28Result SystemClock::GetCurrentTime(Out<s64> out_time) { 28Result SystemClock::GetCurrentTime(Out<s64> out_time) {
29 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); }); 29 SCOPE_EXIT {
30 LOG_DEBUG(Service_Time, "called. out_time={}", *out_time);
31 };
30 32
31 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 33 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
32 ResultClockUninitialized); 34 ResultClockUninitialized);
@@ -45,7 +47,9 @@ Result SystemClock::SetCurrentTime(s64 time) {
45} 47}
46 48
47Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) { 49Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
48 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); }); 50 SCOPE_EXIT {
51 LOG_DEBUG(Service_Time, "called. out_context={}", *out_context);
52 };
49 53
50 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 54 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
51 ResultClockUninitialized); 55 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp
index 2f80030a4..9e0674f27 100644
--- a/src/core/hle/service/psc/time/time_zone_service.cpp
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -37,7 +37,9 @@ TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore&
37} 37}
38 38
39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) { 39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) {
40 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 40 SCOPE_EXIT {
41 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
42 };
41 43
42 R_RETURN(m_time_zone.GetLocationName(*out_location_name)); 44 R_RETURN(m_time_zone.GetLocationName(*out_location_name));
43} 45}
@@ -50,7 +52,9 @@ Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name)
50} 52}
51 53
52Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 54Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
53 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 55 SCOPE_EXIT {
56 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
57 };
54 58
55 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count)); 59 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count));
56} 60}
@@ -69,17 +73,19 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& l
69} 73}
70 74
71Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) { 75Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) {
72 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 76 SCOPE_EXIT {
77 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
78 };
73 79
74 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version)); 80 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version));
75} 81}
76 82
77Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 83Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
78 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) { 84 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) {
79 SCOPE_EXIT({ 85 SCOPE_EXIT {
80 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}", 86 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}",
81 *out_location_name, *out_time_point); 87 *out_location_name, *out_time_point);
82 }); 88 };
83 89
84 R_TRY(m_time_zone.GetLocationName(*out_location_name)); 90 R_TRY(m_time_zone.GetLocationName(*out_location_name));
85 R_RETURN(m_time_zone.GetTimePoint(*out_time_point)); 91 R_RETURN(m_time_zone.GetTimePoint(*out_time_point));
@@ -116,10 +122,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
116Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, 122Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
117 Out<CalendarAdditionalInfo> out_additional_info, s64 time, 123 Out<CalendarAdditionalInfo> out_additional_info, s64 time,
118 InRule rule) { 124 InRule rule) {
119 SCOPE_EXIT({ 125 SCOPE_EXIT {
120 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 126 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
121 *out_calendar_time, *out_additional_info); 127 *out_calendar_time, *out_additional_info);
122 }); 128 };
123 129
124 R_RETURN( 130 R_RETURN(
125 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get())); 131 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get()));
@@ -128,10 +134,10 @@ Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
128Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, 134Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
129 Out<CalendarAdditionalInfo> out_additional_info, 135 Out<CalendarAdditionalInfo> out_additional_info,
130 s64 time) { 136 s64 time) {
131 SCOPE_EXIT({ 137 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 138 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
133 *out_calendar_time, *out_additional_info); 139 *out_calendar_time, *out_additional_info);
134 }); 140 };
135 141
136 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time)); 142 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time));
137} 143}
@@ -139,11 +145,11 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_
139Result TimeZoneService::ToPosixTime(Out<u32> out_count, 145Result TimeZoneService::ToPosixTime(Out<u32> out_count,
140 OutArray<s64, BufferAttr_HipcPointer> out_times, 146 OutArray<s64, BufferAttr_HipcPointer> out_times,
141 const CalendarTime& calendar_time, InRule rule) { 147 const CalendarTime& calendar_time, InRule rule) {
142 SCOPE_EXIT({ 148 SCOPE_EXIT {
143 LOG_DEBUG(Service_Time, 149 LOG_DEBUG(Service_Time,
144 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 150 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
145 calendar_time, *out_count, out_times[0], out_times[1]); 151 calendar_time, *out_count, out_times[0], out_times[1]);
146 }); 152 };
147 153
148 R_RETURN( 154 R_RETURN(
149 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); 155 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule));
@@ -152,11 +158,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
152Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, 158Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
153 OutArray<s64, BufferAttr_HipcPointer> out_times, 159 OutArray<s64, BufferAttr_HipcPointer> out_times,
154 const CalendarTime& calendar_time) { 160 const CalendarTime& calendar_time) {
155 SCOPE_EXIT({ 161 SCOPE_EXIT {
156 LOG_DEBUG(Service_Time, 162 LOG_DEBUG(Service_Time,
157 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 163 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
158 calendar_time, *out_count, out_times[0], out_times[1]); 164 calendar_time, *out_count, out_times[0], out_times[1]);
159 }); 165 };
160 166
161 R_RETURN( 167 R_RETURN(
162 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); 168 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time));
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 8c7f94c8c..0b41bbcb9 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -177,10 +177,10 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
177 Kernel::KPort::Register(m_system.Kernel(), port); 177 Kernel::KPort::Register(m_system.Kernel(), port);
178 178
179 // Ensure that our reference to the port is closed if we fail to register it. 179 // Ensure that our reference to the port is closed if we fail to register it.
180 SCOPE_EXIT({ 180 SCOPE_EXIT {
181 port->GetClientPort().Close(); 181 port->GetClientPort().Close();
182 port->GetServerPort().Close(); 182 port->GetServerPort().Close();
183 }); 183 };
184 184
185 // Register the object name with the kernel. 185 // Register the object name with the kernel.
186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()), 186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()),
@@ -237,7 +237,9 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre
237} 237}
238 238
239Result ServerManager::LoopProcess() { 239Result ServerManager::LoopProcess() {
240 SCOPE_EXIT({ m_stopped.Set(); }); 240 SCOPE_EXIT {
241 m_stopped.Set();
242 };
241 243
242 R_RETURN(this->LoopProcessImpl()); 244 R_RETURN(this->LoopProcessImpl());
243} 245}
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp
index a2a3e556c..3defa4b31 100644
--- a/src/core/hle/service/services.cpp
+++ b/src/core/hle/service/services.cpp
@@ -46,7 +46,7 @@
46#include "core/hle/service/olsc/olsc.h" 46#include "core/hle/service/olsc/olsc.h"
47#include "core/hle/service/omm/omm.h" 47#include "core/hle/service/omm/omm.h"
48#include "core/hle/service/pcie/pcie.h" 48#include "core/hle/service/pcie/pcie.h"
49#include "core/hle/service/pctl/pctl_module.h" 49#include "core/hle/service/pctl/pctl.h"
50#include "core/hle/service/pcv/pcv.h" 50#include "core/hle/service/pcv/pcv.h"
51#include "core/hle/service/pm/pm.h" 51#include "core/hle/service/pm/pm.h"
52#include "core/hle/service/prepo/prepo.h" 52#include "core/hle/service/prepo/prepo.h"
diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h
index 29664e88c..4fd34f46b 100644
--- a/src/core/hle/service/set/settings_types.h
+++ b/src/core/hle/service/set/settings_types.h
@@ -405,8 +405,7 @@ struct EulaVersion {
405 SystemRegionCode region_code; 405 SystemRegionCode region_code;
406 EulaVersionClockType clock_type; 406 EulaVersionClockType clock_type;
407 INSERT_PADDING_BYTES(0x4); 407 INSERT_PADDING_BYTES(0x4);
408 s64 posix_time; 408 Service::PSC::Time::SystemClockContext system_clock_context;
409 Service::PSC::Time::SteadyClockTimePoint timestamp;
410}; 409};
411static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); 410static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
412 411
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index 93925f783..a4475441e 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -306,6 +306,20 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
306 RegisterHandlers(functions); 306 RegisterHandlers(functions);
307 307
308 SetupSettings(); 308 SetupSettings();
309
310 m_system_settings.region_code =
311 static_cast<SystemRegionCode>(Settings::values.region_index.GetValue());
312
313 // TODO: Remove this when starter applet is fully functional
314 EulaVersion eula_version{
315 .version = 0x10000,
316 .region_code = m_system_settings.region_code,
317 .clock_type = EulaVersionClockType::SteadyClock,
318 .system_clock_context = m_system_settings.user_system_clock_context,
319 };
320 m_system_settings.eula_versions[0] = eula_version;
321 m_system_settings.eula_version_count = 1;
322
309 m_save_thread = 323 m_save_thread =
310 std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); }); 324 std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
311} 325}
diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h
index 52e3595d2..6dd105dd4 100644
--- a/src/core/hle/service/vi/conductor.h
+++ b/src/core/hle/service/vi/conductor.h
@@ -10,6 +10,8 @@
10#include "common/polyfill_thread.h" 10#include "common/polyfill_thread.h"
11#include "common/thread.h" 11#include "common/thread.h"
12 12
13#include "core/hle/service/vi/vsync_manager.h"
14
13namespace Core { 15namespace Core {
14class System; 16class System;
15} 17}
@@ -26,7 +28,6 @@ namespace Service::VI {
26 28
27class Container; 29class Container;
28class DisplayList; 30class DisplayList;
29class VsyncManager;
30 31
31class Conductor { 32class Conductor {
32public: 33public:
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp
index 310a207f1..9074f4ae0 100644
--- a/src/core/hle/service/vi/container.cpp
+++ b/src/core/hle/service/vi/container.cpp
@@ -43,11 +43,7 @@ void Container::OnTerminate() {
43 43
44 m_is_shut_down = true; 44 m_is_shut_down = true;
45 45
46 m_layers.ForEachLayer([&](auto& layer) { 46 m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); });
47 if (layer.IsOpen()) {
48 this->DestroyBufferQueueLocked(&layer);
49 }
50 });
51 47
52 m_displays.ForEachDisplay( 48 m_displays.ForEachDisplay(
53 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); 49 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
@@ -161,16 +157,29 @@ Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner
161 auto* const display = m_displays.GetDisplayById(display_id); 157 auto* const display = m_displays.GetDisplayById(display_id);
162 R_UNLESS(display != nullptr, VI::ResultNotFound); 158 R_UNLESS(display != nullptr, VI::ResultNotFound);
163 159
164 auto* const layer = m_layers.CreateLayer(owner_aruid, display); 160 s32 consumer_binder_id, producer_binder_id;
161 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
162
163 auto* const layer =
164 m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
165 R_UNLESS(layer != nullptr, VI::ResultNotFound); 165 R_UNLESS(layer != nullptr, VI::ResultNotFound);
166 166
167 m_surface_flinger->CreateLayer(consumer_binder_id);
168
167 *out_layer_id = layer->GetId(); 169 *out_layer_id = layer->GetId();
168 R_SUCCEED(); 170 R_SUCCEED();
169} 171}
170 172
171Result Container::DestroyLayerLocked(u64 layer_id) { 173Result Container::DestroyLayerLocked(u64 layer_id) {
172 R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); 174 auto* const layer = m_layers.GetLayerById(layer_id);
173 R_THROW(VI::ResultNotFound); 175 R_UNLESS(layer != nullptr, VI::ResultNotFound);
176
177 m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
178 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
179 layer->GetProducerBinderId());
180 m_layers.DestroyLayer(layer_id);
181
182 R_SUCCEED();
174} 183}
175 184
176Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { 185Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
@@ -181,7 +190,12 @@ Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64
181 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); 190 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
182 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); 191 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
183 192
184 this->CreateBufferQueueLocked(layer); 193 layer->Open();
194
195 if (auto* display = layer->GetDisplay(); display != nullptr) {
196 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
197 }
198
185 *out_producer_binder_id = layer->GetProducerBinderId(); 199 *out_producer_binder_id = layer->GetProducerBinderId();
186 200
187 R_SUCCEED(); 201 R_SUCCEED();
@@ -192,30 +206,14 @@ Result Container::CloseLayerLocked(u64 layer_id) {
192 R_UNLESS(layer != nullptr, VI::ResultNotFound); 206 R_UNLESS(layer != nullptr, VI::ResultNotFound);
193 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); 207 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
194 208
195 this->DestroyBufferQueueLocked(layer);
196
197 R_SUCCEED();
198}
199
200void Container::CreateBufferQueueLocked(Layer* layer) {
201 s32 consumer_binder_id, producer_binder_id;
202 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
203 layer->Open(consumer_binder_id, producer_binder_id);
204
205 if (auto* display = layer->GetDisplay(); display != nullptr) {
206 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
207 }
208}
209
210void Container::DestroyBufferQueueLocked(Layer* layer) {
211 if (auto* display = layer->GetDisplay(); display != nullptr) { 209 if (auto* display = layer->GetDisplay(); display != nullptr) {
212 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), 210 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
213 layer->GetConsumerBinderId()); 211 layer->GetConsumerBinderId());
214 } 212 }
215 213
216 layer->Close(); 214 layer->Close();
217 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), 215
218 layer->GetProducerBinderId()); 216 R_SUCCEED();
219} 217}
220 218
221bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 219bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h
index cd0d2ca86..5eac4d77d 100644
--- a/src/core/hle/service/vi/container.h
+++ b/src/core/hle/service/vi/container.h
@@ -72,9 +72,6 @@ private:
72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); 72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
73 Result CloseLayerLocked(u64 layer_id); 73 Result CloseLayerLocked(u64 layer_id);
74 74
75 void CreateBufferQueueLocked(Layer* layer);
76 void DestroyBufferQueueLocked(Layer* layer);
77
78public: 75public:
79 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 76 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
80 77
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h
index b85c8df61..e4c9c9864 100644
--- a/src/core/hle/service/vi/layer.h
+++ b/src/core/hle/service/vi/layer.h
@@ -13,29 +13,31 @@ class Layer {
13public: 13public:
14 constexpr Layer() = default; 14 constexpr Layer() = default;
15 15
16 void Initialize(u64 id, u64 owner_aruid, Display* display) { 16 void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id,
17 s32 producer_binder_id) {
17 m_id = id; 18 m_id = id;
18 m_owner_aruid = owner_aruid; 19 m_owner_aruid = owner_aruid;
19 m_display = display; 20 m_display = display;
21 m_consumer_binder_id = consumer_binder_id;
22 m_producer_binder_id = producer_binder_id;
20 m_is_initialized = true; 23 m_is_initialized = true;
21 } 24 }
22 25
23 void Finalize() { 26 void Finalize() {
24 m_id = {}; 27 m_id = {};
28 m_owner_aruid = {};
25 m_display = {}; 29 m_display = {};
30 m_consumer_binder_id = {};
31 m_producer_binder_id = {};
26 m_is_initialized = {}; 32 m_is_initialized = {};
27 } 33 }
28 34
29 void Open(s32 consumer_binder_id, s32 producer_binder_id) { 35 void Open() {
30 m_consumer_binder_id = consumer_binder_id;
31 m_producer_binder_id = producer_binder_id;
32 m_is_open = true; 36 m_is_open = true;
33 } 37 }
34 38
35 void Close() { 39 void Close() {
36 m_producer_binder_id = {}; 40 m_is_open = false;
37 m_consumer_binder_id = {};
38 m_is_open = {};
39 } 41 }
40 42
41 u64 GetId() const { 43 u64 GetId() const {
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h
index 1738ede9a..4afca6f40 100644
--- a/src/core/hle/service/vi/layer_list.h
+++ b/src/core/hle/service/vi/layer_list.h
@@ -11,13 +11,15 @@ class LayerList {
11public: 11public:
12 constexpr LayerList() = default; 12 constexpr LayerList() = default;
13 13
14 Layer* CreateLayer(u64 owner_aruid, Display* display) { 14 Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id,
15 s32 producer_binder_id) {
15 Layer* const layer = GetFreeLayer(); 16 Layer* const layer = GetFreeLayer();
16 if (!layer) { 17 if (!layer) {
17 return nullptr; 18 return nullptr;
18 } 19 }
19 20
20 layer->Initialize(++m_next_id, owner_aruid, display); 21 layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id,
22 producer_binder_id);
21 return layer; 23 return layer;
22 } 24 }
23 25
diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp
index 869b18961..12cba16fa 100644
--- a/src/core/hle/service/vi/shared_buffer_manager.cpp
+++ b/src/core/hle/service/vi/shared_buffer_manager.cpp
@@ -285,7 +285,7 @@ void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
285 auto& session = it->second; 285 auto& session = it->second;
286 286
287 // Destroy the layer. 287 // Destroy the layer.
288 R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); 288 m_container.DestroyStrayLayer(session.layer_id);
289 289
290 // Close nvmap handle. 290 // Close nvmap handle.
291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); 291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -322,8 +322,6 @@ Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, 322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
323 std::array<s32, 4>& out_slot_indexes, 323 std::array<s32, 4>& out_slot_indexes,
324 s64* out_target_slot, u64 layer_id) { 324 s64* out_target_slot, u64 layer_id) {
325 std::scoped_lock lk{m_guard};
326
327 // Get the producer. 325 // Get the producer.
328 std::shared_ptr<android::BufferQueueProducer> producer; 326 std::shared_ptr<android::BufferQueueProducer> producer;
329 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 327 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -347,8 +345,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
347 Common::Rectangle<s32> crop_region, 345 Common::Rectangle<s32> crop_region,
348 u32 transform, s32 swap_interval, u64 layer_id, 346 u32 transform, s32 swap_interval, u64 layer_id,
349 s64 slot) { 347 s64 slot) {
350 std::scoped_lock lk{m_guard};
351
352 // Get the producer. 348 // Get the producer.
353 std::shared_ptr<android::BufferQueueProducer> producer; 349 std::shared_ptr<android::BufferQueueProducer> producer;
354 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 350 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -379,8 +375,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
379} 375}
380 376
381Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { 377Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
382 std::scoped_lock lk{m_guard};
383
384 // Get the producer. 378 // Get the producer.
385 std::shared_ptr<android::BufferQueueProducer> producer; 379 std::shared_ptr<android::BufferQueueProducer> producer;
386 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 380 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -394,8 +388,6 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
394 388
395Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, 389Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
396 u64 layer_id) { 390 u64 layer_id) {
397 std::scoped_lock lk{m_guard};
398
399 // Get the producer. 391 // Get the producer.
400 std::shared_ptr<android::BufferQueueProducer> producer; 392 std::shared_ptr<android::BufferQueueProducer> producer;
401 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 393 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 2a32b1276..de27ec49e 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -118,7 +118,9 @@ ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)>
118 mbedtls_sha256_starts_ret(&ctx, 0); 118 mbedtls_sha256_starts_ret(&ctx, 0);
119 119
120 // Ensure we maintain a clean state on exit. 120 // Ensure we maintain a clean state on exit.
121 SCOPE_EXIT({ mbedtls_sha256_free(&ctx); }); 121 SCOPE_EXIT {
122 mbedtls_sha256_free(&ctx);
123 };
122 124
123 // Declare counters. 125 // Declare counters.
124 const size_t total_size = file->GetSize(); 126 const size_t total_size = file->GetSize();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index e10a4601e..8775369a4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -831,11 +831,11 @@ struct Memory::Impl {
831 if (core == sys_core) [[unlikely]] { 831 if (core == sys_core) [[unlikely]] {
832 sys_core_guard.lock(); 832 sys_core_guard.lock();
833 } 833 }
834 SCOPE_EXIT({ 834 SCOPE_EXIT {
835 if (core == sys_core) [[unlikely]] { 835 if (core == sys_core) [[unlikely]] {
836 sys_core_guard.unlock(); 836 sys_core_guard.unlock();
837 } 837 }
838 }); 838 };
839 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) { 839 gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
840 auto& current_area = rasterizer_write_areas[core]; 840 auto& current_area = rasterizer_write_areas[core];
841 PAddr subaddress = address >> YUZU_PAGEBITS; 841 PAddr subaddress = address >> YUZU_PAGEBITS;
@@ -866,11 +866,11 @@ struct Memory::Impl {
866 if (core == sys_core) [[unlikely]] { 866 if (core == sys_core) [[unlikely]] {
867 sys_core_guard.lock(); 867 sys_core_guard.lock();
868 } 868 }
869 SCOPE_EXIT({ 869 SCOPE_EXIT {
870 if (core == sys_core) [[unlikely]] { 870 if (core == sys_core) [[unlikely]] {
871 sys_core_guard.unlock(); 871 sys_core_guard.unlock();
872 } 872 }
873 }); 873 };
874 auto& gpu = system.GPU(); 874 auto& gpu = system.GPU();
875 gpu_device_memory->ApplyOpOnPointer( 875 gpu_device_memory->ApplyOpOnPointer(
876 p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); }); 876 p, scratch_buffers[core], [&](DAddr address) { gpu.InvalidateRegion(address, size); });
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index f7097d01d..caceeec4f 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -224,12 +224,12 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
224 // If we've ever seen a decode failure, return false. 224 // If we've ever seen a decode failure, return false.
225 bool valid = decode_success; 225 bool valid = decode_success;
226 CheatVmOpcode opcode = {}; 226 CheatVmOpcode opcode = {};
227 SCOPE_EXIT({ 227 SCOPE_EXIT {
228 decode_success &= valid; 228 decode_success &= valid;
229 if (valid) { 229 if (valid) {
230 out = opcode; 230 out = opcode;
231 } 231 }
232 }); 232 };
233 233
234 // Helper function for getting instruction dwords. 234 // Helper function for getting instruction dwords.
235 const auto GetNextDword = [&] { 235 const auto GetNextDword = [&] {
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp
index d9d278fa3..5cd26819c 100644
--- a/src/hid_core/frontend/emulated_controller.cpp
+++ b/src/hid_core/frontend/emulated_controller.cpp
@@ -933,8 +933,9 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
933 if (index >= controller.stick_values.size()) { 933 if (index >= controller.stick_values.size()) {
934 return; 934 return;
935 } 935 }
936 auto trigger_guard = 936 auto trigger_guard = SCOPE_GUARD {
937 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); 937 TriggerOnChange(ControllerTriggerType::Stick, !is_configuring);
938 };
938 std::scoped_lock lock{mutex}; 939 std::scoped_lock lock{mutex};
939 const auto stick_value = TransformToStick(callback); 940 const auto stick_value = TransformToStick(callback);
940 941
@@ -989,8 +990,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
989 if (index >= controller.trigger_values.size()) { 990 if (index >= controller.trigger_values.size()) {
990 return; 991 return;
991 } 992 }
992 auto trigger_guard = 993 auto trigger_guard = SCOPE_GUARD {
993 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); 994 TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring);
995 };
994 std::scoped_lock lock{mutex}; 996 std::scoped_lock lock{mutex};
995 const auto trigger_value = TransformToTrigger(callback); 997 const auto trigger_value = TransformToTrigger(callback);
996 998
@@ -1036,7 +1038,9 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
1036 if (index >= controller.motion_values.size()) { 1038 if (index >= controller.motion_values.size()) {
1037 return; 1039 return;
1038 } 1040 }
1039 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); 1041 SCOPE_EXIT {
1042 TriggerOnChange(ControllerTriggerType::Motion, !is_configuring);
1043 };
1040 std::scoped_lock lock{mutex}; 1044 std::scoped_lock lock{mutex};
1041 auto& raw_status = controller.motion_values[index].raw_status; 1045 auto& raw_status = controller.motion_values[index].raw_status;
1042 auto& emulated = controller.motion_values[index].emulated; 1046 auto& emulated = controller.motion_values[index].emulated;
@@ -1070,8 +1074,9 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
1070 if (index >= controller.color_values.size()) { 1074 if (index >= controller.color_values.size()) {
1071 return; 1075 return;
1072 } 1076 }
1073 auto trigger_guard = 1077 auto trigger_guard = SCOPE_GUARD {
1074 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); 1078 TriggerOnChange(ControllerTriggerType::Color, !is_configuring);
1079 };
1075 std::scoped_lock lock{mutex}; 1080 std::scoped_lock lock{mutex};
1076 controller.color_values[index] = TransformToColor(callback); 1081 controller.color_values[index] = TransformToColor(callback);
1077 1082
@@ -1120,7 +1125,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
1120 if (index >= controller.battery_values.size()) { 1125 if (index >= controller.battery_values.size()) {
1121 return; 1126 return;
1122 } 1127 }
1123 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); 1128 SCOPE_EXIT {
1129 TriggerOnChange(ControllerTriggerType::Battery, !is_configuring);
1130 };
1124 std::scoped_lock lock{mutex}; 1131 std::scoped_lock lock{mutex};
1125 controller.battery_values[index] = TransformToBattery(callback); 1132 controller.battery_values[index] = TransformToBattery(callback);
1126 1133
@@ -1183,7 +1190,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
1183} 1190}
1184 1191
1185void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { 1192void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
1186 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); 1193 SCOPE_EXIT {
1194 TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring);
1195 };
1187 std::scoped_lock lock{mutex}; 1196 std::scoped_lock lock{mutex};
1188 controller.camera_values = TransformToCamera(callback); 1197 controller.camera_values = TransformToCamera(callback);
1189 1198
@@ -1198,7 +1207,9 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
1198} 1207}
1199 1208
1200void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { 1209void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
1201 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); 1210 SCOPE_EXIT {
1211 TriggerOnChange(ControllerTriggerType::RingController, !is_configuring);
1212 };
1202 std::scoped_lock lock{mutex}; 1213 std::scoped_lock lock{mutex};
1203 const auto force_value = TransformToStick(callback); 1214 const auto force_value = TransformToStick(callback);
1204 1215
@@ -1212,7 +1223,9 @@ void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& call
1212} 1223}
1213 1224
1214void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { 1225void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
1215 SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); 1226 SCOPE_EXIT {
1227 TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring);
1228 };
1216 std::scoped_lock lock{mutex}; 1229 std::scoped_lock lock{mutex};
1217 controller.nfc_values = TransformToNfc(callback); 1230 controller.nfc_values = TransformToNfc(callback);
1218 1231
@@ -1685,8 +1698,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
1685 return; 1698 return;
1686 } 1699 }
1687 1700
1688 auto trigger_guard = 1701 auto trigger_guard = SCOPE_GUARD {
1689 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); 1702 TriggerOnChange(ControllerTriggerType::Connected, !is_configuring);
1703 };
1690 std::scoped_lock lock{connect_mutex, mutex}; 1704 std::scoped_lock lock{connect_mutex, mutex};
1691 if (is_configuring) { 1705 if (is_configuring) {
1692 tmp_is_connected = true; 1706 tmp_is_connected = true;
@@ -1701,8 +1715,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
1701} 1715}
1702 1716
1703void EmulatedController::Disconnect() { 1717void EmulatedController::Disconnect() {
1704 auto trigger_guard = 1718 auto trigger_guard = SCOPE_GUARD {
1705 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); 1719 TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring);
1720 };
1706 std::scoped_lock lock{connect_mutex, mutex}; 1721 std::scoped_lock lock{connect_mutex, mutex};
1707 if (is_configuring) { 1722 if (is_configuring) {
1708 tmp_is_connected = false; 1723 tmp_is_connected = false;
@@ -1738,8 +1753,9 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
1738} 1753}
1739 1754
1740void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { 1755void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1741 auto trigger_guard = 1756 auto trigger_guard = SCOPE_GUARD {
1742 SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); 1757 TriggerOnChange(ControllerTriggerType::Type, !is_configuring);
1758 };
1743 std::scoped_lock lock{mutex, npad_mutex}; 1759 std::scoped_lock lock{mutex, npad_mutex};
1744 1760
1745 if (is_configuring) { 1761 if (is_configuring) {
diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp
index e859cc538..d40fa66ae 100644
--- a/src/input_common/drivers/android.cpp
+++ b/src/input_common/drivers/android.cpp
@@ -3,6 +3,7 @@
3 3
4#include <set> 4#include <set>
5#include <common/settings_input.h> 5#include <common/settings_input.h>
6#include <common/thread.h>
6#include <jni.h> 7#include <jni.h>
7#include "common/android/android_common.h" 8#include "common/android/android_common.h"
8#include "common/android/id_cache.h" 9#include "common/android/id_cache.h"
@@ -10,7 +11,18 @@
10 11
11namespace InputCommon { 12namespace InputCommon {
12 13
13Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} 14Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
15 vibration_thread = std::jthread([this](std::stop_token token) {
16 Common::SetCurrentThreadName("Android_Vibration");
17 auto env = Common::Android::GetEnvForThread();
18 using namespace std::chrono_literals;
19 while (!token.stop_requested()) {
20 SendVibrations(env, token);
21 }
22 });
23}
24
25Android::~Android() = default;
14 26
15void Android::RegisterController(jobject j_input_device) { 27void Android::RegisterController(jobject j_input_device) {
16 auto env = Common::Android::GetEnvForThread(); 28 auto env = Common::Android::GetEnvForThread();
@@ -57,17 +69,11 @@ void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp,
57Common::Input::DriverResult Android::SetVibration( 69Common::Input::DriverResult Android::SetVibration(
58 [[maybe_unused]] const PadIdentifier& identifier, 70 [[maybe_unused]] const PadIdentifier& identifier,
59 [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { 71 [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
60 auto device = input_devices.find(identifier); 72 vibration_queue.Push(VibrationRequest{
61 if (device != input_devices.end()) { 73 .identifier = identifier,
62 Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) { 74 .vibration = vibration,
63 float average_intensity = 75 });
64 static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0); 76 return Common::Input::DriverResult::Success;
65 env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
66 average_intensity);
67 });
68 return Common::Input::DriverResult::Success;
69 }
70 return Common::Input::DriverResult::NotSupported;
71} 77}
72 78
73bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { 79bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
@@ -347,4 +353,15 @@ PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const
347 }; 353 };
348} 354}
349 355
356void Android::SendVibrations(JNIEnv* env, std::stop_token token) {
357 VibrationRequest request = vibration_queue.PopWait(token);
358 auto device = input_devices.find(request.identifier);
359 if (device != input_devices.end()) {
360 float average_intensity = static_cast<float>(
361 (request.vibration.high_amplitude + request.vibration.low_amplitude) / 2.0);
362 env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
363 average_intensity);
364 }
365}
366
350} // namespace InputCommon 367} // namespace InputCommon
diff --git a/src/input_common/drivers/android.h b/src/input_common/drivers/android.h
index 8a386c1b1..03e2b2c98 100644
--- a/src/input_common/drivers/android.h
+++ b/src/input_common/drivers/android.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include <set> 6#include <set>
7#include <common/threadsafe_queue.h>
7#include <jni.h> 8#include <jni.h>
8#include "input_common/input_engine.h" 9#include "input_common/input_engine.h"
9 10
@@ -16,6 +17,8 @@ class Android final : public InputEngine {
16public: 17public:
17 explicit Android(std::string input_engine_); 18 explicit Android(std::string input_engine_);
18 19
20 ~Android() override;
21
19 /** 22 /**
20 * Registers controller number to accept new inputs. 23 * Registers controller number to accept new inputs.
21 * @param j_input_device YuzuInputDevice object from the Android frontend to register. 24 * @param j_input_device YuzuInputDevice object from the Android frontend to register.
@@ -89,6 +92,9 @@ private:
89 /// Returns the correct identifier corresponding to the player index 92 /// Returns the correct identifier corresponding to the player index
90 PadIdentifier GetIdentifier(const std::string& guid, size_t port) const; 93 PadIdentifier GetIdentifier(const std::string& guid, size_t port) const;
91 94
95 /// Takes all vibrations from the queue and sends the command to the controller
96 void SendVibrations(JNIEnv* env, std::stop_token token);
97
92 static constexpr s32 AXIS_X = 0; 98 static constexpr s32 AXIS_X = 0;
93 static constexpr s32 AXIS_Y = 1; 99 static constexpr s32 AXIS_Y = 1;
94 static constexpr s32 AXIS_Z = 11; 100 static constexpr s32 AXIS_Z = 11;
@@ -133,6 +139,10 @@ private:
133 redmagic_vid, backbone_labs_vid, xbox_vid}; 139 redmagic_vid, backbone_labs_vid, xbox_vid};
134 const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid, 140 const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid,
135 backbone_labs_vid, xbox_vid}; 141 backbone_labs_vid, xbox_vid};
142
143 /// Queue of vibration request to controllers
144 Common::SPSCQueue<VibrationRequest> vibration_queue;
145 std::jthread vibration_thread;
136}; 146};
137 147
138} // namespace InputCommon 148} // namespace InputCommon
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index 08e49a0da..a140ad072 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -69,11 +69,6 @@ public:
69 bool IsVibrationEnabled(const PadIdentifier& identifier) override; 69 bool IsVibrationEnabled(const PadIdentifier& identifier) override;
70 70
71private: 71private:
72 struct VibrationRequest {
73 PadIdentifier identifier;
74 Common::Input::VibrationStatus vibration;
75 };
76
77 void InitJoystick(int joystick_index); 72 void InitJoystick(int joystick_index);
78 void CloseJoystick(SDL_Joystick* sdl_joystick); 73 void CloseJoystick(SDL_Joystick* sdl_joystick);
79 74
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp
index c9f903213..0dd1c958a 100644
--- a/src/input_common/helpers/joycon_driver.cpp
+++ b/src/input_common/helpers/joycon_driver.cpp
@@ -268,7 +268,9 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) {
268} 268}
269 269
270Common::Input::DriverResult JoyconDriver::SetPollingMode() { 270Common::Input::DriverResult JoyconDriver::SetPollingMode() {
271 SCOPE_EXIT({ disable_input_thread = false; }); 271 SCOPE_EXIT {
272 disable_input_thread = false;
273 };
272 disable_input_thread = true; 274 disable_input_thread = true;
273 275
274 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); 276 rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration);
diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h
index c2d0cbb34..3e328509b 100644
--- a/src/input_common/input_engine.h
+++ b/src/input_common/input_engine.h
@@ -46,6 +46,11 @@ enum class EngineInputType {
46 Nfc, 46 Nfc,
47}; 47};
48 48
49struct VibrationRequest {
50 PadIdentifier identifier;
51 Common::Input::VibrationStatus vibration;
52};
53
49namespace std { 54namespace std {
50// Hash used to create lists from PadIdentifier data 55// Hash used to create lists from PadIdentifier data
51template <> 56template <>
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 0031fa5fb..3f9698d6b 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -261,7 +261,9 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
261 case Stage::Geometry: 261 case Stage::Geometry:
262 execution_model = spv::ExecutionModel::Geometry; 262 execution_model = spv::ExecutionModel::Geometry;
263 ctx.AddCapability(spv::Capability::Geometry); 263 ctx.AddCapability(spv::Capability::Geometry);
264 ctx.AddCapability(spv::Capability::GeometryStreams); 264 if (ctx.profile.support_geometry_streams) {
265 ctx.AddCapability(spv::Capability::GeometryStreams);
266 }
265 switch (ctx.runtime_info.input_topology) { 267 switch (ctx.runtime_info.input_topology) {
266 case InputTopology::Points: 268 case InputTopology::Points:
267 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints); 269 ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
index 9f7b6bb4b..f60da758e 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_special.cpp
@@ -129,7 +129,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) { 129 if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
130 ConvertDepthMode(ctx); 130 ConvertDepthMode(ctx);
131 } 131 }
132 if (stream.IsImmediate()) { 132 if (!ctx.profile.support_geometry_streams) {
133 throw NotImplementedException("Geometry streams");
134 } else if (stream.IsImmediate()) {
133 ctx.OpEmitStreamVertex(ctx.Def(stream)); 135 ctx.OpEmitStreamVertex(ctx.Def(stream));
134 } else { 136 } else {
135 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 137 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
140} 142}
141 143
142void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { 144void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
143 if (stream.IsImmediate()) { 145 if (!ctx.profile.support_geometry_streams) {
146 throw NotImplementedException("Geometry streams");
147 } else if (stream.IsImmediate()) {
144 ctx.OpEndStreamPrimitive(ctx.Def(stream)); 148 ctx.OpEndStreamPrimitive(ctx.Def(stream));
145 } else { 149 } else {
146 LOG_WARNING(Shader_SPIRV, "Stream is not immediate"); 150 LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 7578d41cc..90e46bb1b 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -44,6 +44,7 @@ struct Profile {
44 bool support_gl_derivative_control{}; 44 bool support_gl_derivative_control{};
45 bool support_scaled_attributes{}; 45 bool support_scaled_attributes{};
46 bool support_multi_viewport{}; 46 bool support_multi_viewport{};
47 bool support_geometry_streams{};
47 48
48 bool warp_size_potentially_larger_than_guest{}; 49 bool warp_size_potentially_larger_than_guest{};
49 50
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 296c90e85..ed7a5b27e 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -35,7 +35,7 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R
35 const s64 min_spacing_critical = device_local_memory - 512_MiB; 35 const s64 min_spacing_critical = device_local_memory - 512_MiB;
36 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); 36 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
37 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 37 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
38 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 38 const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
39 minimum_memory = static_cast<u64>( 39 minimum_memory = static_cast<u64>(
40 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), 40 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
41 DEFAULT_EXPECTED_MEMORY)); 41 DEFAULT_EXPECTED_MEMORY));
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index a94e1f043..0d47b032c 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -291,7 +291,9 @@ u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
291} 291}
292 292
293void Maxwell3D::ConsumeSinkImpl() { 293void Maxwell3D::ConsumeSinkImpl() {
294 SCOPE_EXIT({ method_sink.clear(); }); 294 SCOPE_EXIT {
295 method_sink.clear();
296 };
295 const auto control = shadow_state.shadow_ram_control; 297 const auto control = shadow_state.shadow_ram_control;
296 if (control == Regs::ShadowRamControl::Track || 298 if (control == Regs::ShadowRamControl::Track ||
297 control == Regs::ShadowRamControl::TrackWithFilter) { 299 control == Regs::ShadowRamControl::TrackWithFilter) {
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index c3eda6893..2135f1f2d 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -197,7 +197,9 @@ private:
197 MicroProfileOnThreadCreate(name.c_str()); 197 MicroProfileOnThreadCreate(name.c_str());
198 198
199 // Cleanup 199 // Cleanup
200 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 200 SCOPE_EXIT {
201 MicroProfileOnThreadExit();
202 };
201 203
202 Common::SetCurrentThreadName(name.c_str()); 204 Common::SetCurrentThreadName(name.c_str());
203 Common::SetCurrentThreadPriority(Common::ThreadPriority::High); 205 Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 58d8110b8..477e11457 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -22,7 +22,9 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
22 Tegra::Control::Scheduler& scheduler, SynchState& state) { 22 Tegra::Control::Scheduler& scheduler, SynchState& state) {
23 std::string name = "GPU"; 23 std::string name = "GPU";
24 MicroProfileOnThreadCreate(name.c_str()); 24 MicroProfileOnThreadCreate(name.c_str());
25 SCOPE_EXIT({ MicroProfileOnThreadExit(); }); 25 SCOPE_EXIT {
26 MicroProfileOnThreadExit();
27 };
26 28
27 Common::SetCurrentThreadName(name.c_str()); 29 Common::SetCurrentThreadName(name.c_str());
28 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical); 30 Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
index 96686da59..1003cd38d 100644
--- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp
+++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
@@ -273,10 +273,10 @@ DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) {
273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); 273 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
274 AVFilterInOut* inputs = avfilter_inout_alloc(); 274 AVFilterInOut* inputs = avfilter_inout_alloc();
275 AVFilterInOut* outputs = avfilter_inout_alloc(); 275 AVFilterInOut* outputs = avfilter_inout_alloc();
276 SCOPE_EXIT({ 276 SCOPE_EXIT {
277 avfilter_inout_free(&inputs); 277 avfilter_inout_free(&inputs);
278 avfilter_inout_free(&outputs); 278 avfilter_inout_free(&outputs);
279 }); 279 };
280 280
281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter 281 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter
282 // so just use 1/1 to make buffer filter happy 282 // so just use 1/1 to make buffer filter happy
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp
index 46e853e04..fb529f88b 100644
--- a/src/video_core/macro/macro_hle.cpp
+++ b/src/video_core/macro/macro_hle.cpp
@@ -92,12 +92,12 @@ public:
92 92
93private: 93private:
94 void Fallback(const std::vector<u32>& parameters) { 94 void Fallback(const std::vector<u32>& parameters) {
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (extended) { 96 if (extended) {
97 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 97 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
98 maxwell3d.replace_table.clear(); 98 maxwell3d.replace_table.clear();
99 } 99 }
100 }); 100 };
101 maxwell3d.RefreshParameters(); 101 maxwell3d.RefreshParameters();
102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); 102 const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
103 103
@@ -281,12 +281,12 @@ public:
281 281
282private: 282private:
283 void Fallback(const std::vector<u32>& parameters) { 283 void Fallback(const std::vector<u32>& parameters) {
284 SCOPE_EXIT({ 284 SCOPE_EXIT {
285 // Clean everything. 285 // Clean everything.
286 maxwell3d.regs.vertex_id_base = 0x0; 286 maxwell3d.regs.vertex_id_base = 0x0;
287 maxwell3d.engine_state = Maxwell3D::EngineHint::None; 287 maxwell3d.engine_state = Maxwell3D::EngineHint::None;
288 maxwell3d.replace_table.clear(); 288 maxwell3d.replace_table.clear();
289 }); 289 };
290 maxwell3d.RefreshParameters(); 290 maxwell3d.RefreshParameters();
291 const u32 start_indirect = parameters[0]; 291 const u32 start_indirect = parameters[0];
292 const u32 end_indirect = parameters[1]; 292 const u32 end_indirect = parameters[1];
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index b42fb110c..16af8e6bd 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -230,7 +230,9 @@ template <typename Func>
230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) { 230void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
231 MICROPROFILE_SCOPE(OpenGL_Drawing); 231 MICROPROFILE_SCOPE(OpenGL_Drawing);
232 232
233 SCOPE_EXIT({ gpu.TickWork(); }); 233 SCOPE_EXIT {
234 gpu.TickWork();
235 };
234 gpu_memory->FlushCaching(); 236 gpu_memory->FlushCaching();
235 237
236 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; 238 GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
@@ -355,7 +357,9 @@ void RasterizerOpenGL::DrawIndirect() {
355void RasterizerOpenGL::DrawTexture() { 357void RasterizerOpenGL::DrawTexture() {
356 MICROPROFILE_SCOPE(OpenGL_Drawing); 358 MICROPROFILE_SCOPE(OpenGL_Drawing);
357 359
358 SCOPE_EXIT({ gpu.TickWork(); }); 360 SCOPE_EXIT {
361 gpu.TickWork();
362 };
359 363
360 texture_cache.SynchronizeGraphicsDescriptors(); 364 texture_cache.SynchronizeGraphicsDescriptors();
361 texture_cache.UpdateRenderTargets(false); 365 texture_cache.UpdateRenderTargets(false);
diff --git a/src/video_core/renderer_vulkan/present/layer.cpp b/src/video_core/renderer_vulkan/present/layer.cpp
index 3847a9a13..4e41afe5b 100644
--- a/src/video_core/renderer_vulkan/present/layer.cpp
+++ b/src/video_core/renderer_vulkan/present/layer.cpp
@@ -82,7 +82,9 @@ void Layer::ConfigureDraw(PresentPushConstants* out_push_constants,
82 // Finish any pending renderpass 82 // Finish any pending renderpass
83 scheduler.RequestOutsideRenderPassOperationContext(); 83 scheduler.RequestOutsideRenderPassOperationContext();
84 scheduler.Wait(resource_ticks[image_index]); 84 scheduler.Wait(resource_ticks[image_index]);
85 SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); }); 85 SCOPE_EXIT {
86 resource_ticks[image_index] = scheduler.CurrentTick();
87 };
86 88
87 if (!use_accelerated) { 89 if (!use_accelerated) {
88 UpdateRawImage(framebuffer, image_index); 90 UpdateRawImage(framebuffer, image_index);
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index d50417116..c553f5b3d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -144,7 +144,9 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
144 return; 144 return;
145 } 145 }
146 146
147 SCOPE_EXIT({ render_window.OnFrameDisplayed(); }); 147 SCOPE_EXIT {
148 render_window.OnFrameDisplayed();
149 };
148 150
149 RenderAppletCaptureLayer(framebuffers); 151 RenderAppletCaptureLayer(framebuffers);
150 152
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 20f7a9702..d34b585d6 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -352,6 +352,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
352 .support_native_ndc = device.IsExtDepthClipControlSupported(), 352 .support_native_ndc = device.IsExtDepthClipControlSupported(),
353 .support_scaled_attributes = !device.MustEmulateScaledFormats(), 353 .support_scaled_attributes = !device.MustEmulateScaledFormats(),
354 .support_multi_viewport = device.SupportsMultiViewport(), 354 .support_multi_viewport = device.SupportsMultiViewport(),
355 .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
355 356
356 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(), 357 .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
357 358
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index aa0a027bb..74f9f099e 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -196,7 +196,9 @@ template <typename Func>
196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) { 196void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
197 MICROPROFILE_SCOPE(Vulkan_Drawing); 197 MICROPROFILE_SCOPE(Vulkan_Drawing);
198 198
199 SCOPE_EXIT({ gpu.TickWork(); }); 199 SCOPE_EXIT {
200 gpu.TickWork();
201 };
200 FlushWork(); 202 FlushWork();
201 gpu_memory->FlushCaching(); 203 gpu_memory->FlushCaching();
202 204
@@ -288,7 +290,9 @@ void RasterizerVulkan::DrawIndirect() {
288void RasterizerVulkan::DrawTexture() { 290void RasterizerVulkan::DrawTexture() {
289 MICROPROFILE_SCOPE(Vulkan_Drawing); 291 MICROPROFILE_SCOPE(Vulkan_Drawing);
290 292
291 SCOPE_EXIT({ gpu.TickWork(); }); 293 SCOPE_EXIT {
294 gpu.TickWork();
295 };
292 FlushWork(); 296 FlushWork();
293 297
294 query_cache.NotifySegment(true); 298 query_cache.NotifySegment(true);
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 5b3c7aa5a..9055b1b92 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -3,6 +3,7 @@
3 3
4#include "common/common_types.h" 4#include "common/common_types.h"
5#include "common/math_util.h" 5#include "common/math_util.h"
6#include "common/settings.h"
6#include "video_core/surface.h" 7#include "video_core/surface.h"
7 8
8namespace VideoCore::Surface { 9namespace VideoCore::Surface {
@@ -400,11 +401,20 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
400 return {DefaultBlockWidth(format), DefaultBlockHeight(format)}; 401 return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
401} 402}
402 403
403u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) { 404u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
404 constexpr u64 RGBA8_PIXEL_SIZE = 4; 405 constexpr u64 RGBA8_PIXEL_SIZE = 4;
405 const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) * 406 const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
406 static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE; 407 static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
407 return (base_size * base_block_size) / BytesPerBlock(format); 408 const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
409
410 switch (Settings::values.astc_recompression.GetValue()) {
411 case Settings::AstcRecompression::Bc1:
412 return uncompressed_size / 8;
413 case Settings::AstcRecompression::Bc3:
414 return uncompressed_size / 4;
415 default:
416 return uncompressed_size;
417 }
408} 418}
409 419
410} // namespace VideoCore::Surface 420} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index a5e8e2f62..ec9cd2fbf 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -517,6 +517,6 @@ size_t PixelComponentSizeBitsInteger(PixelFormat format);
517 517
518std::pair<u32, u32> GetASTCBlockSize(PixelFormat format); 518std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
519 519
520u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format); 520u64 TranscodedAstcSize(u64 base_size, PixelFormat format);
521 521
522} // namespace VideoCore::Surface 522} // namespace VideoCore::Surface
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 01c3561c9..53b4876f2 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -55,7 +55,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
55 const s64 min_spacing_critical = device_local_memory - 512_MiB; 55 const s64 min_spacing_critical = device_local_memory - 512_MiB;
56 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD); 56 const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
57 const s64 min_vacancy_expected = (6 * mem_threshold) / 10; 57 const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
58 const s64 min_vacancy_critical = (3 * mem_threshold) / 10; 58 const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
59 expected_memory = static_cast<u64>( 59 expected_memory = static_cast<u64>(
60 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected), 60 std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
61 DEFAULT_EXPECTED_MEMORY)); 61 DEFAULT_EXPECTED_MEMORY));
@@ -1979,7 +1979,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
1979 if ((IsPixelFormatASTC(image.info.format) && 1979 if ((IsPixelFormatASTC(image.info.format) &&
1980 True(image.flags & ImageFlagBits::AcceleratedUpload)) || 1980 True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
1981 True(image.flags & ImageFlagBits::Converted)) { 1981 True(image.flags & ImageFlagBits::Converted)) {
1982 tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); 1982 tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
1983 } 1983 }
1984 total_used_memory += Common::AlignUp(tentative_size, 1024); 1984 total_used_memory += Common::AlignUp(tentative_size, 1024);
1985 image.lru_index = lru_cache.Insert(image_id, frame_tick); 1985 image.lru_index = lru_cache.Insert(image_id, frame_tick);
@@ -2149,7 +2149,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
2149 if ((IsPixelFormatASTC(image.info.format) && 2149 if ((IsPixelFormatASTC(image.info.format) &&
2150 True(image.flags & ImageFlagBits::AcceleratedUpload)) || 2150 True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
2151 True(image.flags & ImageFlagBits::Converted)) { 2151 True(image.flags & ImageFlagBits::Converted)) {
2152 tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format); 2152 tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
2153 } 2153 }
2154 total_used_memory -= Common::AlignUp(tentative_size, 1024); 2154 total_used_memory -= Common::AlignUp(tentative_size, 1024);
2155 const GPUVAddr gpu_addr = image.gpu_addr; 2155 const GPUVAddr gpu_addr = image.gpu_addr;
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
index 5fa0d9620..f41c3e506 100644
--- a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
+++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp
@@ -116,7 +116,9 @@ void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
116 LOG_ERROR(Render_Vulkan, "Failed to create decoder"); 116 LOG_ERROR(Render_Vulkan, "Failed to create decoder");
117 return; 117 return;
118 } 118 }
119 SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); 119 SCOPE_EXIT {
120 GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder);
121 };
120 122
121 u32 json_size = 0; 123 u32 json_size = 0;
122 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( 124 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index d7216d349..b94924a58 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1297,10 +1297,6 @@ u64 Device::GetDeviceMemoryUsage() const {
1297} 1297}
1298 1298
1299void Device::CollectPhysicalMemoryInfo() { 1299void Device::CollectPhysicalMemoryInfo() {
1300 // Account for resolution scaling in memory limits
1301 const size_t normal_memory = 6_GiB;
1302 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1303
1304 // Calculate limits using memory budget 1300 // Calculate limits using memory budget
1305 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{}; 1301 VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
1306 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT; 1302 budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1331,7 +1327,15 @@ void Device::CollectPhysicalMemoryInfo() {
1331 if (!is_integrated) { 1327 if (!is_integrated) {
1332 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB); 1328 const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
1333 device_access_memory -= reserve_memory; 1329 device_access_memory -= reserve_memory;
1334 device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory); 1330
1331 if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
1332 // Account for resolution scaling in memory limits
1333 const size_t normal_memory = 6_GiB;
1334 const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
1335 device_access_memory =
1336 std::min<u64>(device_access_memory, normal_memory + scaler_memory);
1337 }
1338
1335 return; 1339 return;
1336 } 1340 }
1337 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage); 1341 const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index a2ec26697..e3abe8ddf 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -499,6 +499,11 @@ public:
499 return extensions.transform_feedback; 499 return extensions.transform_feedback;
500 } 500 }
501 501
502 /// Returns true if the device supports VK_EXT_transform_feedback properly.
503 bool AreTransformFeedbackGeometryStreamsSupported() const {
504 return features.transform_feedback.geometryStreams;
505 }
506
502 /// Returns true if the device supports VK_EXT_custom_border_color. 507 /// Returns true if the device supports VK_EXT_custom_border_color.
503 bool IsExtCustomBorderColorSupported() const { 508 bool IsExtCustomBorderColorSupported() const {
504 return extensions.custom_border_color; 509 return extensions.custom_border_color;
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index d138b53c8..0549e8ae4 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -164,6 +164,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n" 164 "the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but " 165 "This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
166 "negatively affecting image quality.")); 166 "negatively affecting image quality."));
167 INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"),
168 tr("Selects whether the emulator should prefer to conserve memory or make maximum usage "
169 "of available video memory for performance. Has no effect on integrated graphics. "
170 "Aggressive mode may severely impact the performance of other applications such as "
171 "recording software."));
167 INSERT( 172 INSERT(
168 Settings, vsync_mode, tr("VSync Mode:"), 173 Settings, vsync_mode, tr("VSync Mode:"),
169 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " 174 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
@@ -315,6 +320,11 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
315 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), 320 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
316 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), 321 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
317 }}); 322 }});
323 translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
324 {
325 PAIR(VramUsageMode, Conservative, tr("Conservative")),
326 PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
327 }});
318 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), 328 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
319 { 329 {
320#ifdef HAS_OPENGL 330#ifdef HAS_OPENGL
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0d16bfd65..c0c0a19b8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -646,10 +646,10 @@ void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParamete
646 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) { 646 std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
647 cabinet_applet = 647 cabinet_applet =
648 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); 648 new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
649 SCOPE_EXIT({ 649 SCOPE_EXIT {
650 cabinet_applet->deleteLater(); 650 cabinet_applet->deleteLater();
651 cabinet_applet = nullptr; 651 cabinet_applet = nullptr;
652 }); 652 };
653 653
654 cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | 654 cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
655 Qt::WindowTitleHint | Qt::WindowSystemMenuHint); 655 Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@@ -673,10 +673,10 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
673 const Core::Frontend::ControllerParameters& parameters) { 673 const Core::Frontend::ControllerParameters& parameters) {
674 controller_applet = 674 controller_applet =
675 new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system); 675 new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system);
676 SCOPE_EXIT({ 676 SCOPE_EXIT {
677 controller_applet->deleteLater(); 677 controller_applet->deleteLater();
678 controller_applet = nullptr; 678 controller_applet = nullptr;
679 }); 679 };
680 680
681 controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | 681 controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
682 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | 682 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -703,10 +703,10 @@ void GMainWindow::ControllerSelectorRequestExit() {
703void GMainWindow::ProfileSelectorSelectProfile( 703void GMainWindow::ProfileSelectorSelectProfile(
704 const Core::Frontend::ProfileSelectParameters& parameters) { 704 const Core::Frontend::ProfileSelectParameters& parameters) {
705 profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); 705 profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters);
706 SCOPE_EXIT({ 706 SCOPE_EXIT {
707 profile_select_applet->deleteLater(); 707 profile_select_applet->deleteLater();
708 profile_select_applet = nullptr; 708 profile_select_applet = nullptr;
709 }); 709 };
710 710
711 profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | 711 profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
712 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | 712 Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() {
1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); 1604 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents); 1605 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
1606 connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware); 1606 connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
1607 connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
1607 connect_menu(ui->action_About, &GMainWindow::OnAbout); 1608 connect_menu(ui->action_About, &GMainWindow::OnAbout);
1608} 1609}
1609 1610
@@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() {
1633 } 1634 }
1634 1635
1635 ui->action_Install_Firmware->setEnabled(!emulation_running); 1636 ui->action_Install_Firmware->setEnabled(!emulation_running);
1637 ui->action_Install_Keys->setEnabled(!emulation_running);
1636 1638
1637 for (QAction* action : applet_actions) { 1639 for (QAction* action : applet_actions) {
1638 action->setEnabled(is_firmware_available && !emulation_running); 1640 action->setEnabled(is_firmware_available && !emulation_running);
@@ -2323,15 +2325,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2323 ASSERT(user_id); 2325 ASSERT(user_id);
2324 2326
2325 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2327 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2326 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2328 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2327 FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0); 2329 program_id, user_id->AsU128(), 0);
2328 2330
2329 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); 2331 path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
2330 } else { 2332 } else {
2331 // Device save data 2333 // Device save data
2332 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2334 const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
2333 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, 2335 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
2334 FileSys::SaveDataType::SaveData, program_id, {}, 0); 2336 program_id, {}, 0);
2335 2337
2336 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path); 2338 path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
2337 } 2339 }
@@ -2672,7 +2674,7 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
2672 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read); 2674 vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
2673 2675
2674 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath( 2676 const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
2675 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage, 2677 {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache,
2676 0 /* program_id */, {}, 0); 2678 0 /* program_id */, {}, 0);
2677 2679
2678 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path); 2680 const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
@@ -2885,17 +2887,19 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2885 LOG_ERROR(Frontend, "CoInitialize failed"); 2887 LOG_ERROR(Frontend, "CoInitialize failed");
2886 return false; 2888 return false;
2887 } 2889 }
2888 SCOPE_EXIT({ CoUninitialize(); }); 2890 SCOPE_EXIT {
2891 CoUninitialize();
2892 };
2889 IShellLinkW* ps1 = nullptr; 2893 IShellLinkW* ps1 = nullptr;
2890 IPersistFile* persist_file = nullptr; 2894 IPersistFile* persist_file = nullptr;
2891 SCOPE_EXIT({ 2895 SCOPE_EXIT {
2892 if (persist_file != nullptr) { 2896 if (persist_file != nullptr) {
2893 persist_file->Release(); 2897 persist_file->Release();
2894 } 2898 }
2895 if (ps1 != nullptr) { 2899 if (ps1 != nullptr) {
2896 ps1->Release(); 2900 ps1->Release();
2897 } 2901 }
2898 }); 2902 };
2899 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW, 2903 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
2900 reinterpret_cast<void**>(&ps1)); 2904 reinterpret_cast<void**>(&ps1));
2901 if (FAILED(hres)) { 2905 if (FAILED(hres)) {
@@ -3006,9 +3010,6 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
3006 3010
3007void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, 3011void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
3008 GameListShortcutTarget target) { 3012 GameListShortcutTarget target) {
3009 std::string game_title;
3010 QString qt_game_title;
3011 std::filesystem::path out_icon_path;
3012 // Get path to yuzu executable 3013 // Get path to yuzu executable
3013 const QStringList args = QApplication::arguments(); 3014 const QStringList args = QApplication::arguments();
3014 std::filesystem::path yuzu_command = args[0].toStdString(); 3015 std::filesystem::path yuzu_command = args[0].toStdString();
@@ -3025,48 +3026,51 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
3025 shortcut_path = 3026 shortcut_path =
3026 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString(); 3027 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
3027 } 3028 }
3028 // Icon path and title 3029
3029 if (std::filesystem::exists(shortcut_path)) { 3030 if (!std::filesystem::exists(shortcut_path)) {
3030 // Get title from game file 3031 GMainWindow::CreateShortcutMessagesGUI(
3031 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), 3032 this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3032 system->GetContentProvider()}; 3033 QString::fromStdString(shortcut_path.generic_string()));
3033 const auto control = pm.GetControlMetadata(); 3034 LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string());
3034 const auto loader = 3035 return;
3035 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read)); 3036 }
3036 game_title = fmt::format("{:016X}", program_id); 3037
3037 if (control.first != nullptr) { 3038 // Get title from game file
3038 game_title = control.first->GetApplicationName(); 3039 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
3039 } else { 3040 system->GetContentProvider()};
3040 loader->ReadTitle(game_title); 3041 const auto control = pm.GetControlMetadata();
3041 } 3042 const auto loader =
3042 // Delete illegal characters from title 3043 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
3043 const std::string illegal_chars = "<>:\"/\\|?*."; 3044 std::string game_title = fmt::format("{:016X}", program_id);
3044 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) { 3045 if (control.first != nullptr) {
3045 if (illegal_chars.find(*it) != std::string::npos) { 3046 game_title = control.first->GetApplicationName();
3046 game_title.erase(it.base() - 1); 3047 } else {
3047 } 3048 loader->ReadTitle(game_title);
3048 } 3049 }
3049 qt_game_title = QString::fromStdString(game_title); 3050 // Delete illegal characters from title
3050 // Get icon from game file 3051 const std::string illegal_chars = "<>:\"/\\|?*.";
3051 std::vector<u8> icon_image_file{}; 3052 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
3052 if (control.second != nullptr) { 3053 if (illegal_chars.find(*it) != std::string::npos) {
3053 icon_image_file = control.second->ReadAllBytes(); 3054 game_title.erase(it.base() - 1);
3054 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3055 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3056 } 3055 }
3057 QImage icon_data = 3056 }
3058 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); 3057 const QString qt_game_title = QString::fromStdString(game_title);
3059 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) { 3058 // Get icon from game file
3060 if (!SaveIconToFile(out_icon_path, icon_data)) { 3059 std::vector<u8> icon_image_file{};
3061 LOG_ERROR(Frontend, "Could not write icon to file"); 3060 if (control.second != nullptr) {
3062 } 3061 icon_image_file = control.second->ReadAllBytes();
3062 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3063 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3064 }
3065 QImage icon_data =
3066 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
3067 std::filesystem::path out_icon_path;
3068 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
3069 if (!SaveIconToFile(out_icon_path, icon_data)) {
3070 LOG_ERROR(Frontend, "Could not write icon to file");
3063 } 3071 }
3064 } else {
3065 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3066 qt_game_title);
3067 LOG_ERROR(Frontend, "Invalid shortcut target");
3068 return;
3069 } 3072 }
3073
3070#if defined(__linux__) 3074#if defined(__linux__)
3071 // Special case for AppImages 3075 // Special case for AppImages
3072 // Warn once if we are making a shortcut to a volatile AppImage 3076 // Warn once if we are making a shortcut to a volatile AppImage
@@ -3520,10 +3524,10 @@ void GMainWindow::OnSaveConfig() {
3520void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { 3524void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
3521 error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{}, 3525 error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{},
3522 tr("OK"), Qt::AlignLeft | Qt::AlignVCenter); 3526 tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
3523 SCOPE_EXIT({ 3527 SCOPE_EXIT {
3524 error_applet->deleteLater(); 3528 error_applet->deleteLater();
3525 error_applet = nullptr; 3529 error_applet = nullptr;
3526 }); 3530 };
3527 error_applet->exec(); 3531 error_applet->exec();
3528 3532
3529 emit ErrorDisplayFinished(); 3533 emit ErrorDisplayFinished();
@@ -4167,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() {
4167 return; 4171 return;
4168 } 4172 }
4169 4173
4170 QString firmware_source_location = 4174 const QString firmware_source_location = QFileDialog::getExistingDirectory(
4171 QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"), 4175 this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
4172 QString::fromStdString(""), QFileDialog::ShowDirsOnly);
4173 if (firmware_source_location.isEmpty()) { 4176 if (firmware_source_location.isEmpty()) {
4174 return; 4177 return;
4175 } 4178 }
@@ -4200,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() {
4200 std::vector<std::filesystem::path> out; 4203 std::vector<std::filesystem::path> out;
4201 const Common::FS::DirEntryCallable callback = 4204 const Common::FS::DirEntryCallable callback =
4202 [&out](const std::filesystem::directory_entry& entry) { 4205 [&out](const std::filesystem::directory_entry& entry) {
4203 if (entry.path().has_extension() && entry.path().extension() == ".nca") 4206 if (entry.path().has_extension() && entry.path().extension() == ".nca") {
4204 out.emplace_back(entry.path()); 4207 out.emplace_back(entry.path());
4208 }
4205 4209
4206 return true; 4210 return true;
4207 }; 4211 };
@@ -4233,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() {
4233 auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered"); 4237 auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
4234 4238
4235 bool success = true; 4239 bool success = true;
4236 bool cancelled = false;
4237 int i = 0; 4240 int i = 0;
4238 for (const auto& firmware_src_path : out) { 4241 for (const auto& firmware_src_path : out) {
4239 i++; 4242 i++;
@@ -4248,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() {
4248 success = false; 4251 success = false;
4249 } 4252 }
4250 4253
4251 if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) { 4254 if (QtProgressCallback(
4252 success = false; 4255 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
4253 cancelled = true; 4256 progress.close();
4254 break; 4257 QMessageBox::warning(
4258 this, tr("Firmware install failed"),
4259 tr("Firmware installation cancelled, firmware may be in bad state, "
4260 "restart yuzu or re-install firmware."));
4261 return;
4255 } 4262 }
4256 } 4263 }
4257 4264
4258 if (!success && !cancelled) { 4265 if (!success) {
4259 progress.close(); 4266 progress.close();
4260 QMessageBox::critical(this, tr("Firmware install failed"), 4267 QMessageBox::critical(this, tr("Firmware install failed"),
4261 tr("One or more firmware files failed to copy into NAND.")); 4268 tr("One or more firmware files failed to copy into NAND."));
4262 return; 4269 return;
4263 } else if (cancelled) {
4264 progress.close();
4265 QMessageBox::warning(this, tr("Firmware install failed"),
4266 tr("Firmware installation cancelled, firmware may be in bad state, "
4267 "restart yuzu or re-install firmware."));
4268 return;
4269 } 4270 }
4270 4271
4271 // Re-scan VFS for the newly placed firmware files. 4272 // Re-scan VFS for the newly placed firmware files.
@@ -4293,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() {
4293 OnCheckFirmwareDecryption(); 4294 OnCheckFirmwareDecryption();
4294} 4295}
4295 4296
4297void GMainWindow::OnInstallDecryptionKeys() {
4298 // Don't do this while emulation is running.
4299 if (emu_thread != nullptr && emu_thread->IsRunning()) {
4300 return;
4301 }
4302
4303 const QString key_source_location = QFileDialog::getOpenFileName(
4304 this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {},
4305 QFileDialog::ReadOnly);
4306 if (key_source_location.isEmpty()) {
4307 return;
4308 }
4309
4310 // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin
4311 LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString());
4312
4313 const std::filesystem::path prod_key_path = key_source_location.toStdString();
4314 const std::filesystem::path key_source_path = prod_key_path.parent_path();
4315 if (!Common::FS::IsDir(key_source_path)) {
4316 return;
4317 }
4318
4319 bool prod_keys_found = false;
4320 std::vector<std::filesystem::path> source_key_files;
4321
4322 if (Common::FS::Exists(prod_key_path)) {
4323 prod_keys_found = true;
4324 source_key_files.emplace_back(prod_key_path);
4325 }
4326
4327 if (Common::FS::Exists(key_source_path / "title.keys")) {
4328 source_key_files.emplace_back(key_source_path / "title.keys");
4329 }
4330
4331 if (Common::FS::Exists(key_source_path / "key_retail.bin")) {
4332 source_key_files.emplace_back(key_source_path / "key_retail.bin");
4333 }
4334
4335 // There should be at least prod.keys.
4336 if (source_key_files.empty() || !prod_keys_found) {
4337 QMessageBox::warning(this, tr("Decryption Keys install failed"),
4338 tr("prod.keys is a required decryption key file."));
4339 return;
4340 }
4341
4342 const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
4343 for (auto key_file : source_key_files) {
4344 std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename();
4345 if (!std::filesystem::copy_file(key_file, destination_key_file,
4346 std::filesystem::copy_options::overwrite_existing)) {
4347 LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(),
4348 destination_key_file.string());
4349 QMessageBox::critical(this, tr("Decryption Keys install failed"),
4350 tr("One or more keys failed to copy."));
4351 return;
4352 }
4353 }
4354
4355 // Reinitialize the key manager, re-read the vfs (for update/dlc files),
4356 // and re-populate the game list in the UI if the user has already added
4357 // game folders.
4358 Core::Crypto::KeyManager::Instance().ReloadKeys();
4359 system->GetFileSystemController().CreateFactories(*vfs);
4360 game_list->PopulateAsync(UISettings::values.game_dirs);
4361
4362 if (ContentManager::AreKeysPresent()) {
4363 QMessageBox::information(this, tr("Decryption Keys install succeeded"),
4364 tr("Decryption Keys were successfully installed"));
4365 } else {
4366 QMessageBox::critical(
4367 this, tr("Decryption Keys install failed"),
4368 tr("Decryption Keys failed to initialize. Check that your dumping tools are "
4369 "up to date and re-dump keys."));
4370 }
4371
4372 OnCheckFirmwareDecryption();
4373}
4374
4296void GMainWindow::OnAbout() { 4375void GMainWindow::OnAbout() {
4297 AboutDialog aboutDialog(this); 4376 AboutDialog aboutDialog(this);
4298 aboutDialog.exec(); 4377 aboutDialog.exec();
@@ -5192,7 +5271,9 @@ int main(int argc, char* argv[]) {
5192 5271
5193 Common::DetachedTasks detached_tasks; 5272 Common::DetachedTasks detached_tasks;
5194 MicroProfileOnThreadCreate("Frontend"); 5273 MicroProfileOnThreadCreate("Frontend");
5195 SCOPE_EXIT({ MicroProfileShutdown(); }); 5274 SCOPE_EXIT {
5275 MicroProfileShutdown();
5276 };
5196 5277
5197 Common::ConfigureNvidiaEnvironmentFlags(); 5278 Common::ConfigureNvidiaEnvironmentFlags();
5198 5279
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1f0e35c67..fce643f3f 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -381,6 +381,7 @@ private slots:
381 void OnOpenYuzuFolder(); 381 void OnOpenYuzuFolder();
382 void OnVerifyInstalledContents(); 382 void OnVerifyInstalledContents();
383 void OnInstallFirmware(); 383 void OnInstallFirmware();
384 void OnInstallDecryptionKeys();
384 void OnAbout(); 385 void OnAbout();
385 void OnToggleFilterBar(); 386 void OnToggleFilterBar();
386 void OnToggleStatusBar(); 387 void OnToggleStatusBar();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 6ff444a22..85dc1f2f6 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -165,8 +165,9 @@
165 <addaction name="separator"/> 165 <addaction name="separator"/>
166 <addaction name="action_Configure_Tas"/> 166 <addaction name="action_Configure_Tas"/>
167 </widget> 167 </widget>
168 <addaction name="action_Verify_installed_contents"/> 168 <addaction name="action_Install_Keys"/>
169 <addaction name="action_Install_Firmware"/> 169 <addaction name="action_Install_Firmware"/>
170 <addaction name="action_Verify_installed_contents"/>
170 <addaction name="separator"/> 171 <addaction name="separator"/>
171 <addaction name="menu_cabinet_applet"/> 172 <addaction name="menu_cabinet_applet"/>
172 <addaction name="action_Load_Album"/> 173 <addaction name="action_Load_Album"/>
@@ -469,6 +470,11 @@
469 <string>Install Firmware</string> 470 <string>Install Firmware</string>
470 </property> 471 </property>
471 </action> 472 </action>
473 <action name="action_Install_Keys">
474 <property name="text">
475 <string>Install Decryption Keys</string>
476 </property>
477 </action>
472 </widget> 478 </widget>
473 <resources> 479 <resources>
474 <include location="yuzu.qrc"/> 480 <include location="yuzu.qrc"/>
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 3b321dad1..8a8cdbc44 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -327,7 +327,9 @@ int main(int argc, char** argv) {
327#endif 327#endif
328 328
329 MicroProfileOnThreadCreate("EmuThread"); 329 MicroProfileOnThreadCreate("EmuThread");
330 SCOPE_EXIT({ MicroProfileShutdown(); }); 330 SCOPE_EXIT {
331 MicroProfileShutdown();
332 };
331 333
332 Common::ConfigureNvidiaEnvironmentFlags(); 334 Common::ConfigureNvidiaEnvironmentFlags();
333 335