summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/verify.yml3
-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
265 files changed, 6739 insertions, 4846 deletions
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 2814d3cdb..13bde68c3 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -81,8 +81,7 @@ jobs:
fetch-depth: 0
- name: Install dependencies
run: |
- # workaround for https://github.com/actions/setup-python/issues/577
- brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12
+ brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd
- name: Build
run: |
mkdir build
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()
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
+ -Wno-missing-field-initializers
)
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(
fun hasMapping(): Boolean {
var hasMapping = false
buttons.forEach {
- if (it != "[empty]") {
+ if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
analogs.forEach {
- if (it != "[empty]") {
+ if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
motions.forEach {
- if (it != "[empty]") {
+ if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true
}
}
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
import org.yuzu.yuzu_emu.utils.NativeConfig
enum class StringSetting(override val key: String) : AbstractStringSetting {
- DRIVER_PATH("driver_path");
+ DRIVER_PATH("driver_path"),
+ DEVICE_NAME("device_name");
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)
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
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
+import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.utils.NativeConfig
/**
@@ -75,6 +76,9 @@ abstract class SettingsItem(
get() = NativeLibrary.isRunning() && !setting.global &&
!NativeConfig.isPerGameConfigLoaded()
+ val clearable: Boolean
+ get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
+
companion object {
const val TYPE_HEADER = 0
const val TYPE_SWITCH = 1
@@ -87,6 +91,7 @@ abstract class SettingsItem(
const val TYPE_INPUT = 8
const val TYPE_INT_SINGLE_CHOICE = 9
const val TYPE_INPUT_PROFILE = 10
+ const val TYPE_STRING_INPUT = 11
const val FASTMEM_COMBINED = "fastmem_combined"
@@ -105,6 +110,7 @@ abstract class SettingsItem(
// List of all general
val settingsItems = HashMap<String, SettingsItem>().apply {
+ put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
put(
SwitchSetting(
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 @@
+// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.features.settings.model.view
+
+import androidx.annotation.StringRes
+import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
+
+class StringInputSetting(
+ setting: AbstractStringSetting,
+ @StringRes titleId: Int = 0,
+ titleString: String = "",
+ @StringRes descriptionId: Int = 0,
+ descriptionString: String = ""
+) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
+ override val type = TYPE_STRING_INPUT
+
+ fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
+
+ fun setSelectedValue(selection: String) =
+ (setting as AbstractStringSetting).setString(selection)
+}
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(
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
+ SettingsItem.TYPE_STRING_INPUT -> {
+ StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
+ }
+
else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
}
@@ -392,6 +396,15 @@ class SettingsAdapter(
popup.show()
}
+ fun onStringInputClick(item: StringInputSetting, position: Int) {
+ SettingsDialogFragment.newInstance(
+ settingsViewModel,
+ item,
+ SettingsItem.TYPE_STRING_INPUT,
+ position
+ ).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
+ }
+
fun onLongClick(item: SettingsItem, position: Int): Boolean {
SettingsDialogFragment.newInstance(
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
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.R
+import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@@ -23,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
+import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage
import org.yuzu.yuzu_emu.utils.collect
@@ -37,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private val settingsViewModel: SettingsViewModel by activityViewModels()
private lateinit var sliderBinding: DialogSliderBinding
+ private lateinit var stringInputBinding: DialogEditTextBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -131,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.create()
}
+ SettingsItem.TYPE_STRING_INPUT -> {
+ stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
+ val item = settingsViewModel.clickedItem as StringInputSetting
+ stringInputBinding.editText.setText(item.getSelectedValue())
+ MaterialAlertDialogBuilder(requireContext())
+ .setTitle(item.title)
+ .setView(stringInputBinding.root)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, defaultCancelListener)
+ .create()
+ }
+
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
MaterialAlertDialogBuilder(requireContext())
@@ -158,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
): View? {
return when (type) {
SettingsItem.TYPE_SLIDER -> sliderBinding.root
+ SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
else -> super.onCreateView(inflater, container, savedInstanceState)
}
}
@@ -200,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
val sliderSetting = settingsViewModel.clickedItem as SliderSetting
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
}
+
+ is StringInputSetting -> {
+ val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
+ stringInputSetting.setSelectedValue(
+ (stringInputBinding.editText.text ?: "").toString()
+ )
+ }
}
closeDialog()
}
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
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
+import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig
@@ -153,6 +154,7 @@ class SettingsFragmentPresenter(
private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
sl.apply {
+ add(StringSetting.DEVICE_NAME.key)
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
add(ShortSetting.RENDERER_SPEED_LIMIT.key)
add(BooleanSetting.USE_DOCKED_MODE.key)
@@ -778,7 +780,7 @@ class SettingsFragmentPresenter(
playerIndex: Int,
paramName: String,
stick: NativeAnalog,
- defaultValue: Int
+ defaultValue: Float
): AbstractIntSetting =
object : AbstractIntSetting {
val params get() = NativeInput.getStickParam(playerIndex, stick)
@@ -786,7 +788,7 @@ class SettingsFragmentPresenter(
override val key = ""
override fun getInt(needsGlobal: Boolean): Int =
- (params.get(paramName, 0.15f) * 100).toInt()
+ (params.get(paramName, defaultValue) * 100).toInt()
override fun setInt(value: Int) {
val tempParams = params
@@ -794,12 +796,12 @@ class SettingsFragmentPresenter(
NativeInput.setStickParam(playerIndex, stick, tempParams)
}
- override val defaultValue = defaultValue
+ override val defaultValue = (defaultValue * 100).toInt()
override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString()
- override fun reset() = setInt(defaultValue)
+ override fun reset() = setInt(this.defaultValue)
}
private fun getExtraStickSettings(
@@ -809,11 +811,11 @@ class SettingsFragmentPresenter(
val stickIsController =
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
val modifierRangeSetting =
- getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50)
+ getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
val stickRangeSetting =
- getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95)
+ getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
val stickDeadzoneSetting =
- getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15)
+ getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
val out = mutableListOf<SettingsItem>().apply {
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
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
-import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -32,9 +31,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime)
- binding.buttonClear.setVisible(
- !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
- )
+ binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
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
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
-import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -48,9 +47,7 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
binding.textSettingValue.setVisible(false)
}
- binding.buttonClear.setVisible(
- !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
- )
+ binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
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
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
-import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
@@ -28,9 +27,7 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
setting.units
)
- binding.buttonClear.setVisible(
- !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
- )
+ binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
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 @@
+// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.features.settings.ui.viewholder
+
+import android.view.View
+import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
+import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
+import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
+import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
+import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
+
+class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
+ SettingViewHolder(binding.root, adapter) {
+ private lateinit var setting: StringInputSetting
+
+ override fun bind(item: SettingsItem) {
+ setting = item as StringInputSetting
+ binding.textSettingName.text = setting.title
+ binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
+ binding.textSettingDescription.text = setting.description
+ binding.textSettingValue.setVisible(true)
+ binding.textSettingValue.text = setting.getSelectedValue()
+
+ binding.buttonClear.setVisible(setting.clearable)
+ binding.buttonClear.setOnClickListener {
+ adapter.onClearClick(setting, bindingAdapterPosition)
+ }
+
+ setStyle(setting.isEditable, binding)
+ }
+
+ override fun onClick(clicked: View) {
+ if (setting.isEditable) {
+ adapter.onStringInputClick(setting, bindingAdapterPosition)
+ }
+ }
+
+ override fun onLongClick(clicked: View): Boolean {
+ if (setting.isEditable) {
+ return adapter.onLongClick(setting, bindingAdapterPosition)
+ }
+ return false
+ }
+}
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
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
-import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
@@ -29,9 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
}
- binding.buttonClear.setVisible(
- !setting.setting.global || NativeConfig.isPerGameConfigLoaded()
- )
+ binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
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 {
}
}
}
- binding.doneControlConfig.setVisible(false)
+ binding.doneControlConfig.setVisible(true)
binding.surfaceInputOverlay.setIsInEditMode(true)
}
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
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
import org.yuzu.yuzu_emu.features.input.model.NativeButton
+import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
}
var shouldUpdateView = false
- val playerIndex =
- if (NativeInput.isHandheldOnly()) {
- NativeInput.ConsoleDevice
- } else {
- NativeInput.Player1Device
- }
+ val playerIndex = when (NativeInput.getStyleIndex(0)) {
+ NpadStyleIndex.Handheld -> 8
+ else -> 0
+ }
for (button in overlayButtons) {
if (!button.updateStatus(event)) {
@@ -664,7 +663,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
val overlayControlData = NativeConfig.getOverlayControlData()
overlayControlData.forEach {
- it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false
+ it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
}
NativeConfig.setOverlayControlData(overlayControlData)
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() {
// Unload user input.
m_system.HIDCore().UnloadInputDevices();
+ // Enable all controllers
+ m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
+
// Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger();
@@ -404,7 +407,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
const size_t program_index,
const bool frontend_initiated) {
MicroProfileOnThreadCreate("EmuThread");
- SCOPE_EXIT({ MicroProfileShutdown(); });
+ SCOPE_EXIT {
+ MicroProfileShutdown();
+ };
LOG_INFO(Frontend, "starting");
@@ -413,7 +418,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
return Core::SystemResultStatus::ErrorLoader;
}
- SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
+ SCOPE_EXIT {
+ EmulationSession::GetInstance().ShutdownEmulation();
+ };
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
frontend_initiated);
@@ -661,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
- {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
+ {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
user_id->AsU128(), 0);
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
FileSys::OpenMode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
- {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
- program_id, user_id->AsU128(), 0);
+ {}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
+ user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path);
}
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,
}
}
+std::vector<s32> GetSupportedStyles(int player_index) {
+ auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
+ const auto npad_style_set = hid_core.GetSupportedStyleTag();
+ std::vector<s32> supported_indexes;
+ if (npad_style_set.fullkey == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
+ }
+
+ if (npad_style_set.joycon_dual == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
+ }
+
+ if (npad_style_set.joycon_left == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
+ }
+
+ if (npad_style_set.joycon_right == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
+ }
+
+ if (player_index == 0 && npad_style_set.handheld == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
+ }
+
+ if (npad_style_set.gamecube == 1) {
+ supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
+ }
+
+ return supported_indexes;
+}
+
void ConnectController(size_t player_index, bool connected) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
+ ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
+ auto supported_styles = GetSupportedStyles(player_index);
+ auto controller_style = controller->GetNpadStyleIndex(true);
+ auto style = std::find(supported_styles.begin(), supported_styles.end(),
+ static_cast<int>(controller_style));
+ if (style == supported_styles.end() && !supported_styles.empty()) {
+ controller->SetNpadStyleIndex(
+ static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
+ }
+ });
+
if (player_index == 0) {
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
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
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
JNIEnv* env, jobject j_obj, jint j_player_index) {
- auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
- const auto npad_style_set = hid_core.GetSupportedStyleTag();
- std::vector<s32> supported_indexes;
- if (npad_style_set.fullkey == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
- }
-
- if (npad_style_set.joycon_dual == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
- }
-
- if (npad_style_set.joycon_left == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
- }
-
- if (npad_style_set.joycon_right == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
- }
-
- if (j_player_index == 0 && npad_style_set.handheld == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
- }
-
- if (npad_style_set.gamecube == 1) {
- supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
- }
-
- jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
- env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
- supported_indexes.data());
+ auto supported_styles = GetSupportedStyles(j_player_index);
+ jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
+ env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
+ supported_styles.data());
return j_supported_indexes;
}
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 @@
<string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings -->
+ <string name="device_name">Device name</string>
<string name="use_docked_mode">Docked Mode</string>
<string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
<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() {
}
}
-u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names,
- [[maybe_unused]] const u32 max_count,
+u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex};
LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
- if (input_devices.size() > 1) {
- names.emplace_back("Uac");
+ if (!input_devices.empty() && !names.empty()) {
+ names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
return 1;
}
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:
* Get a list of audio in device names.
*
* @param names - Output container to write names to.
- * @param max_count - Maximum number of device names to write. Unused
* @param filter - Should the list be filtered? Unused.
*
* @return Number of names written.
*/
- u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count,
- bool filter);
+ u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
/// Core system
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:
break;
}
- tags[released++] = tag;
+ if (released < tags.size()) {
+ tags[released] = tag;
+ }
+
+ released++;
if (released >= tags.size()) {
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() {
}
}
-Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size) {
+Result OpusDecoder::Initialize(const OpusParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size;
shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
R_SUCCEED();
}
-Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params,
+Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
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:
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
~OpusDecoder();
- Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size);
- Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
+ Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
+ Result Initialize(const OpusMultiStreamParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
std::span<const u8> input_data, std::span<u8> output_data, bool reset);
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_)
}
}
-Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
OpusParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
}
-Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size));
}
-Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
R_SUCCEED();
}
-Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params,
- u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
+ u32& out_size) {
OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate,
.channel_count = params.channel_count,
@@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
}
-Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params,
- u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
+ const OpusMultiStreamParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
}
-Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params,
- u64& out_size) {
+Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
+ const OpusMultiStreamParametersEx& params, u32& out_size) {
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
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:
return hardware_opus;
}
- Result GetWorkBufferSize(OpusParameters& params, u64& out_size);
- Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size);
- Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size);
- Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size);
- Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size);
- Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size);
+ Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
+ Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
+ Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
+ Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
+ Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
+ u32& out_size);
+ Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
+ u32& out_size);
private:
Core::System& system;
HardwareOpus hardware_opus;
- std::array<u64, MaxChannels> required_workbuffer_sizes{};
+ std::array<u32, MaxChannels> required_workbuffer_sizes{};
};
} // 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_)
opus_decoder.SetSharedMemory(shared_memory);
}
-u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
+u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) {
return 0;
}
@@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0;
}
- return shared_memory.dsp_return_data[0];
+ return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
-u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
+u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = total_stream_count;
shared_memory.host_send_data[1] = stereo_stream_count;
@@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0;
}
- return shared_memory.dsp_return_data[0];
+ return static_cast<u32>(shared_memory.dsp_return_data[0]);
}
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 total_stream_count,
- u32 stereo_stream_count, void* mappings,
- void* buffer, u64 buffer_size) {
+ u32 stereo_stream_count,
+ const void* mappings, void* buffer,
+ u64 buffer_size) {
std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = (u64)buffer;
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 {
public:
HardwareOpus(Core::System& system);
- u64 GetWorkBufferSize(u32 channel);
- u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
+ u32 GetWorkBufferSize(u32 channel);
+ u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
u64 buffer_size);
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 totaL_stream_count, u32 stereo_stream_count,
- void* mappings, void* buffer, u64 buffer_size);
+ const void* mappings, void* buffer, u64 buffer_size);
Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
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 {
/* 0x00 */ u32 sample_rate;
/* 0x04 */ u32 channel_count;
/* 0x08 */ bool use_large_frame_size;
- /* 0x09 */ INSERT_PADDING_BYTES(7);
+ /* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
}; // size = 0x10
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
@@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
/* 0x08 */ u32 total_stream_count;
/* 0x0C */ u32 stereo_stream_count;
/* 0x10 */ bool use_large_frame_size;
- /* 0x11 */ INSERT_PADDING_BYTES(7);
+ /* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118
static_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
: output_sink{system.AudioCore().GetOutputSink()},
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
-u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
- const size_t max_count) const {
+u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
names = device_names;
}
- const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
+ const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
for (u32 i = 0; i < out_count; i++) {
- out_buffer.push_back(names[i]);
+ out_buffer[i] = names[i];
}
return out_count;
}
-u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
- const size_t max_count) const {
- const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
+u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
+ const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
for (u32 i = 0; i < out_count; i++) {
- out_buffer.push_back(output_device_names[i]);
+ out_buffer[i] = output_device_names[i];
}
return out_count;
}
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:
* Get a list of the available output devices.
*
* @param out_buffer - Output buffer to write the available device names.
- * @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
- u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
+ u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* Get a list of the available output devices.
* Different to above somehow...
*
* @param out_buffer - Output buffer to write the available device names.
- * @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written.
*/
- u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
+ u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
/**
* 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
Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory,
- const u64 transfer_memory_size, const u32 process_handle,
- Kernel::KProcess& process, const u64 applet_resource_user_id,
- const s32 session_id) {
+ const u64 transfer_memory_size, Kernel::KProcess* process_handle,
+ const u64 applet_resource_user_id, const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio,
@@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
}
initialized = true;
- system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
+ system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id);
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:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
- * @param process_handle - Process handle, also used for memory. Unused.
+ * @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
- u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
+ Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**
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 @@
namespace AudioCore::Renderer {
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
- const u32 process_handle_, BehaviorInfo& behaviour_)
+ Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
: input{input_.data() + sizeof(UpdateDataHeader)},
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
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 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
+namespace Kernel {
+class KProcess;
+}
+
namespace AudioCore::Renderer {
class BehaviorInfo;
class VoiceContext;
@@ -39,8 +43,8 @@ class InfoUpdater {
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
public:
- explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle,
- BehaviorInfo& behaviour);
+ explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
+ Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
/**
* Update the voice channel resources.
@@ -197,7 +201,7 @@ private:
/// Expected output size, see CheckConsumedSize
u64 expected_output_size;
/// Unused
- u32 process_handle;
+ Kernel::KProcess* process_handle;
/// Behaviour
BehaviorInfo& behaviour;
};
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 @@
namespace AudioCore::Renderer {
-PoolMapper::PoolMapper(u32 process_handle_, bool force_map_)
+PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {}
-PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_,
- bool force_map_)
+PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
+ u32 pool_count_, bool force_map_)
: process_handle{process_handle_}, pool_infos{pool_infos_.data()},
pool_count{pool_count_}, force_map{force_map_} {}
@@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map;
}
-u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
+Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
switch (pool->GetLocation()) {
case MemoryPoolInfo::Location::CPU:
return process_handle;
case MemoryPoolInfo::Location::DSP:
- return Kernel::Svc::CurrentProcess;
+ // return Kernel::Svc::CurrentProcess;
+ return nullptr;
}
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
- return Kernel::Svc::CurrentProcess;
+ // return Kernel::Svc::CurrentProcess;
+ return nullptr;
}
bool 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
}
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
- [[maybe_unused]] u32 handle{0};
+ [[maybe_unused]] Kernel::KProcess* handle{};
switch (pool.GetLocation()) {
case MemoryPoolInfo::Location::CPU:
handle = process_handle;
break;
case MemoryPoolInfo::Location::DSP:
- handle = Kernel::Svc::CurrentProcess;
+ // handle = Kernel::Svc::CurrentProcess;
break;
}
// 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 @@
#include "common/common_types.h"
#include "core/hle/service/audio/errors.h"
+namespace Kernel {
+class KProcess;
+}
+
namespace AudioCore::Renderer {
class AddressInfo;
@@ -18,9 +22,9 @@ class AddressInfo;
*/
class PoolMapper {
public:
- explicit PoolMapper(u32 process_handle, bool force_map);
- explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count,
- bool force_map);
+ explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
+ explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
+ u32 pool_count, bool force_map);
/**
* Clear the usage state for all given pools.
@@ -98,7 +102,7 @@ public:
* @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU
*/
- u32 GetProcessHandle(const MemoryPoolInfo* pool) const;
+ Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
/**
* Map the given region with the given handle. This is a no-op.
@@ -167,7 +171,7 @@ public:
private:
/// Process handle for this mapper, used when location == CPU
- u32 process_handle;
+ Kernel::KProcess* process_handle{};
/// List of memory pools assigned to this mapper
MemoryPoolInfo* pool_infos{};
/// 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_)
Result System::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
- u32 process_handle_, Kernel::KProcess& process_,
- u64 applet_resource_user_id_, s32 session_id_) {
+ Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
+ s32 session_id_) {
if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision;
}
@@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
behavior.SetUserLibRevision(params.revision);
process_handle = process_handle_;
- process = &process_;
applet_resource_user_id = applet_resource_user_id_;
session_id = session_id_;
@@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device;
execution_mode = params.execution_mode;
- process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size);
+ process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
+ transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back
@@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
(static_cast<f32>(render_time_limit_percent) / 100.0f))};
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
- applet_resource_user_id, process,
+ applet_resource_user_id, process_handle,
reset_command_buffers);
reset_command_buffers = false;
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:
* @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused.
- * @param process_handle - Process handle, also used for memory. Unused.
+ * @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer.
* @return Result code.
*/
Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
- u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id,
+ Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id);
/**
@@ -278,9 +278,7 @@ private:
/// Does what locks do
std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes.
- Kernel::KProcess* process{};
- /// Handle for the process for this system, unused
- u32 process_handle{};
+ Kernel::KProcess* process_handle{};
/// Applet resource id for this system, unused
u64 applet_resource_user_id{};
/// 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() {
return false;
}
- SCOPE_EXIT({ cubeb_destroy(ctx); });
+ SCOPE_EXIT {
+ cubeb_destroy(ctx);
+ };
#ifdef _WIN32
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:
oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
- ASSERT(result == oboe::Result::OK);
+ if (result == oboe::Result::OK) {
+ return temp_stream->getChannelCount() >= 6 ? 6 : 2;
+ }
- return temp_stream->getChannelCount() >= 6 ? 6 : 2;
+ LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
+ direction == oboe::Direction::Output ? "output" : "input");
+ return 2;
}
protected:
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 @@
namespace AudioCore::Sink {
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
queue.enqueue(buffer);
++queued_buffers;
- });
+ };
if (type == StreamType::In) {
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) {
}
char* demangled = nullptr;
- SCOPE_EXIT({ std::free(demangled); });
+ SCOPE_EXIT {
+ std::free(demangled);
+ };
if (is_itanium(mangled)) {
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:
explicit Impl(size_t backing_size_, size_t virtual_size_)
: backing_size{backing_size_}, virtual_size{virtual_size_} {
bool good = false;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (!good) {
Release();
}
- });
+ };
long page_size = sysconf(_SC_PAGESIZE);
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
out_entry->block_size = page_size;
// Regardless of whether the page was mapped, advance on exit.
- SCOPE_EXIT({
+ SCOPE_EXIT {
context->next_page += 1;
context->next_offset += page_size;
- });
+ };
// Validate that we can read the actual entry.
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 @@
#include <atomic>
#include <cstddef>
#include <cstring>
+#include <limits>
#include <new>
#include <span>
#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 @@
#include "common/common_funcs.h"
namespace detail {
-template <typename Func>
-struct ScopeExitHelper {
- explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
- ~ScopeExitHelper() {
+template <class F>
+class ScopeGuard {
+ YUZU_NON_COPYABLE(ScopeGuard);
+
+private:
+ F f;
+ bool active;
+
+public:
+ constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
+ constexpr ~ScopeGuard() {
if (active) {
- func();
+ f();
}
}
-
- void Cancel() {
+ constexpr void Cancel() {
active = false;
}
- Func func;
- bool active{true};
+ constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
+ rhs.Cancel();
+ }
+
+ ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
};
-template <typename Func>
-ScopeExitHelper<Func> ScopeExit(Func&& func) {
- return ScopeExitHelper<Func>(std::forward<Func>(func));
+template <class F>
+constexpr ScopeGuard<F> MakeScopeGuard(F f) {
+ return ScopeGuard<F>(std::move(f));
}
+
+enum class ScopeGuardOnExit {};
+
+template <typename F>
+constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
+ return ScopeGuard<F>(std::forward<F>(f));
+}
+
} // namespace detail
+#define CONCATENATE_IMPL(s1, s2) s1##s2
+#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
+
+#ifdef __COUNTER__
+#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
+#else
+#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
+#endif
+
+/**
+ * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
+ * used when the caller might want to cancel the ScopeExit.
+ */
+#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
+
/**
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
* for doing ad-hoc clean-up tasks in a function with multiple returns.
@@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
* \code
* const int saved_val = g_foo;
* g_foo = 55;
- * SCOPE_EXIT({ g_foo = saved_val; });
+ * SCOPE_EXIT{ g_foo = saved_val; };
*
* if (Bar()) {
* return 0;
@@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
* }
* \endcode
*/
-#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body)
-
-/**
- * This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
- * used when the caller might want to cancel the ScopeExit.
- */
-#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)
+#define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
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 {
AstcRecompression::Bc3,
"astc_recompression",
Category::RendererAdvanced};
+ SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
+ VramUsageMode::Conservative,
+ VramUsageMode::Conservative,
+ VramUsageMode::Aggressive,
+ "vram_usage_mode",
+ Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID
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);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
+ENUM(VramUsageMode, Conservative, Aggressive);
+
ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(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) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
+std::string StringFromBuffer(std::span<const char> data) {
+ return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
+}
+
// Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) {
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 {
[[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
+[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
[[nodiscard]] std::string StripSpaces(const std::string& s);
[[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 @@
# SPDX-License-Identifier: GPL-2.0-or-later
add_library(core STATIC
- arm/arm_interface.h
arm/arm_interface.cpp
+ arm/arm_interface.h
arm/debug.cpp
arm/debug.h
arm/exclusive_monitor.cpp
@@ -37,10 +37,10 @@ add_library(core STATIC
debugger/gdbstub.h
debugger/gdbstub_arch.cpp
debugger/gdbstub_arch.h
- device_memory_manager.h
- device_memory_manager.inc
device_memory.cpp
device_memory.h
+ device_memory_manager.h
+ device_memory_manager.inc
file_sys/bis_factory.cpp
file_sys/bis_factory.h
file_sys/card_image.cpp
@@ -58,9 +58,14 @@ add_library(core STATIC
file_sys/fs_operate_range.h
file_sys/fs_path.h
file_sys/fs_path_utility.h
+ file_sys/fs_save_data_types.h
file_sys/fs_string_util.h
+ file_sys/fsa/fs_i_directory.h
+ file_sys/fsa/fs_i_file.h
+ file_sys/fsa/fs_i_filesystem.h
file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h
+ file_sys/fssrv/fssrv_sf_path.h
file_sys/fssystem/fs_i_storage.h
file_sys/fssystem/fs_types.h
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@@ -390,6 +395,20 @@ add_library(core STATIC
hle/service/acc/errors.h
hle/service/acc/profile_manager.cpp
hle/service/acc/profile_manager.h
+ hle/service/am/am.cpp
+ hle/service/am/am.h
+ hle/service/am/am_results.h
+ hle/service/am/am_types.h
+ hle/service/am/applet.cpp
+ hle/service/am/applet.h
+ hle/service/am/applet_data_broker.cpp
+ hle/service/am/applet_data_broker.h
+ hle/service/am/applet_manager.cpp
+ hle/service/am/applet_manager.h
+ hle/service/am/applet_message_queue.cpp
+ hle/service/am/applet_message_queue.h
+ hle/service/am/display_layer_manager.cpp
+ hle/service/am/display_layer_manager.h
hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp
@@ -411,20 +430,6 @@ add_library(core STATIC
hle/service/am/frontend/applet_web_browser_types.h
hle/service/am/frontend/applets.cpp
hle/service/am/frontend/applets.h
- hle/service/am/am.cpp
- hle/service/am/am.h
- hle/service/am/am_results.h
- hle/service/am/am_types.h
- hle/service/am/applet.cpp
- hle/service/am/applet.h
- hle/service/am/applet_manager.cpp
- hle/service/am/applet_data_broker.cpp
- hle/service/am/applet_data_broker.h
- hle/service/am/applet_manager.h
- hle/service/am/applet_message_queue.cpp
- hle/service/am/applet_message_queue.h
- hle/service/am/display_layer_manager.cpp
- hle/service/am/display_layer_manager.h
hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp
@@ -441,10 +446,10 @@ add_library(core STATIC
hle/service/am/service/application_creator.h
hle/service/am/service/application_functions.cpp
hle/service/am/service/application_functions.h
- hle/service/am/service/application_proxy_service.cpp
- hle/service/am/service/application_proxy_service.h
hle/service/am/service/application_proxy.cpp
hle/service/am/service/application_proxy.h
+ hle/service/am/service/application_proxy_service.cpp
+ hle/service/am/service/application_proxy_service.h
hle/service/am/service/audio_controller.cpp
hle/service/am/service/audio_controller.h
hle/service/am/service/common_state_getter.cpp
@@ -473,10 +478,10 @@ add_library(core STATIC
hle/service/am/service/process_winding_controller.h
hle/service/am/service/self_controller.cpp
hle/service/am/service/self_controller.h
- hle/service/am/service/storage_accessor.cpp
- hle/service/am/service/storage_accessor.h
hle/service/am/service/storage.cpp
hle/service/am/service/storage.h
+ hle/service/am/service/storage_accessor.cpp
+ hle/service/am/service/storage_accessor.h
hle/service/am/service/system_applet_proxy.cpp
hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp
@@ -491,37 +496,35 @@ add_library(core STATIC
hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h
- hle/service/audio/audin_u.cpp
- hle/service/audio/audin_u.h
- hle/service/audio/audio.cpp
- hle/service/audio/audio.h
hle/service/audio/audio_controller.cpp
hle/service/audio/audio_controller.h
- hle/service/audio/audout_u.cpp
- hle/service/audio/audout_u.h
- hle/service/audio/audrec_a.cpp
- hle/service/audio/audrec_a.h
- hle/service/audio/audrec_u.cpp
- hle/service/audio/audrec_u.h
- hle/service/audio/audren_u.cpp
- hle/service/audio/audren_u.h
+ hle/service/audio/audio_device.cpp
+ hle/service/audio/audio_device.h
+ hle/service/audio/audio_in_manager.cpp
+ hle/service/audio/audio_in_manager.h
+ hle/service/audio/audio_in.cpp
+ hle/service/audio/audio_in.h
+ hle/service/audio/audio_out_manager.cpp
+ hle/service/audio/audio_out_manager.h
+ hle/service/audio/audio_out.cpp
+ hle/service/audio/audio_out.h
+ hle/service/audio/audio_renderer_manager.cpp
+ hle/service/audio/audio_renderer_manager.h
+ hle/service/audio/audio_renderer.cpp
+ hle/service/audio/audio_renderer.h
+ hle/service/audio/audio.cpp
+ hle/service/audio/audio.h
hle/service/audio/errors.h
- hle/service/audio/hwopus.cpp
- hle/service/audio/hwopus.h
+ hle/service/audio/final_output_recorder_manager_for_applet.cpp
+ hle/service/audio/final_output_recorder_manager_for_applet.h
+ hle/service/audio/final_output_recorder_manager.cpp
+ hle/service/audio/final_output_recorder_manager.h
+ hle/service/audio/hardware_opus_decoder_manager.cpp
+ hle/service/audio/hardware_opus_decoder_manager.h
+ hle/service/audio/hardware_opus_decoder.cpp
+ hle/service/audio/hardware_opus_decoder.h
hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h
- hle/service/bcat/news/newly_arrived_event_holder.cpp
- hle/service/bcat/news/newly_arrived_event_holder.h
- hle/service/bcat/news/news_data_service.cpp
- hle/service/bcat/news/news_data_service.h
- hle/service/bcat/news/news_database_service.cpp
- hle/service/bcat/news/news_database_service.h
- hle/service/bcat/news/news_service.cpp
- hle/service/bcat/news/news_service.h
- hle/service/bcat/news/overwrite_event_holder.cpp
- hle/service/bcat/news/overwrite_event_holder.h
- hle/service/bcat/news/service_creator.cpp
- hle/service/bcat/news/service_creator.h
hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h
hle/service/bcat/bcat_result.h
@@ -537,6 +540,18 @@ add_library(core STATIC
hle/service/bcat/delivery_cache_progress_service.h
hle/service/bcat/delivery_cache_storage_service.cpp
hle/service/bcat/delivery_cache_storage_service.h
+ hle/service/bcat/news/newly_arrived_event_holder.cpp
+ hle/service/bcat/news/newly_arrived_event_holder.h
+ hle/service/bcat/news/news_data_service.cpp
+ hle/service/bcat/news/news_data_service.h
+ hle/service/bcat/news/news_database_service.cpp
+ hle/service/bcat/news/news_database_service.h
+ hle/service/bcat/news/news_service.cpp
+ hle/service/bcat/news/news_service.h
+ hle/service/bcat/news/overwrite_event_holder.cpp
+ hle/service/bcat/news/overwrite_event_holder.h
+ hle/service/bcat/news/service_creator.cpp
+ hle/service/bcat/news/service_creator.h
hle/service/bcat/service_creator.cpp
hle/service/bcat/service_creator.h
hle/service/bpc/bpc.cpp
@@ -545,6 +560,16 @@ add_library(core STATIC
hle/service/btdrv/btdrv.h
hle/service/btm/btm.cpp
hle/service/btm/btm.h
+ hle/service/btm/btm_debug.cpp
+ hle/service/btm/btm_debug.h
+ hle/service/btm/btm_system.cpp
+ hle/service/btm/btm_system.h
+ hle/service/btm/btm_system_core.cpp
+ hle/service/btm/btm_system_core.h
+ hle/service/btm/btm_user.cpp
+ hle/service/btm/btm_user.h
+ hle/service/btm/btm_user_core.cpp
+ hle/service/btm/btm_user_core.h
hle/service/caps/caps.cpp
hle/service/caps/caps.h
hle/service/caps/caps_a.cpp
@@ -587,6 +612,10 @@ add_library(core STATIC
hle/service/filesystem/fsp/fs_i_file.h
hle/service/filesystem/fsp/fs_i_filesystem.cpp
hle/service/filesystem/fsp/fs_i_filesystem.h
+ hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
+ hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
+ hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
+ hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
hle/service/filesystem/fsp/fs_i_storage.cpp
hle/service/filesystem/fsp/fs_i_storage.h
hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -595,13 +624,13 @@ add_library(core STATIC
hle/service/filesystem/fsp/fsp_pr.h
hle/service/filesystem/fsp/fsp_srv.cpp
hle/service/filesystem/fsp/fsp_srv.h
- hle/service/filesystem/fsp/fsp_util.h
+ hle/service/filesystem/fsp/fsp_types.h
+ hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
+ hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp
hle/service/filesystem/save_data_controller.h
- hle/service/fgm/fgm.cpp
- hle/service/fgm/fgm.h
hle/service/friend/friend.cpp
hle/service/friend/friend.h
hle/service/friend/friend_interface.cpp
@@ -761,10 +790,10 @@ add_library(core STATIC
hle/service/ns/factory_reset_interface.h
hle/service/ns/language.cpp
hle/service/ns/language.h
- hle/service/ns/ns_results.h
- hle/service/ns/ns_types.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
+ hle/service/ns/ns_results.h
+ hle/service/ns/ns_types.h
hle/service/ns/platform_service_manager.cpp
hle/service/ns/platform_service_manager.h
hle/service/ns/query_service.cpp
@@ -835,12 +864,12 @@ add_library(core STATIC
hle/service/nvnflinger/consumer_listener.h
hle/service/nvnflinger/graphic_buffer_producer.cpp
hle/service/nvnflinger/graphic_buffer_producer.h
- hle/service/nvnflinger/hos_binder_driver_server.cpp
- hle/service/nvnflinger/hos_binder_driver_server.h
- hle/service/nvnflinger/hos_binder_driver.cpp
- hle/service/nvnflinger/hos_binder_driver.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
+ hle/service/nvnflinger/hos_binder_driver.cpp
+ hle/service/nvnflinger/hos_binder_driver.h
+ hle/service/nvnflinger/hos_binder_driver_server.cpp
+ hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hwc_layer.h
hle/service/nvnflinger/nvnflinger.cpp
hle/service/nvnflinger/nvnflinger.h
@@ -854,8 +883,20 @@ add_library(core STATIC
hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h
+ hle/service/olsc/daemon_controller.cpp
+ hle/service/olsc/daemon_controller.h
+ hle/service/olsc/native_handle_holder.cpp
+ hle/service/olsc/native_handle_holder.h
+ hle/service/olsc/olsc_service_for_application.cpp
+ hle/service/olsc/olsc_service_for_application.h
+ hle/service/olsc/olsc_service_for_system_service.cpp
+ hle/service/olsc/olsc_service_for_system_service.h
hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h
+ hle/service/olsc/remote_storage_controller.cpp
+ hle/service/olsc/remote_storage_controller.h
+ hle/service/olsc/transfer_task_list_controller.cpp
+ hle/service/olsc/transfer_task_list_controller.h
hle/service/omm/omm.cpp
hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp
@@ -866,25 +907,44 @@ add_library(core STATIC
hle/service/omm/power_state_interface.h
hle/service/os/event.cpp
hle/service/os/event.h
+ hle/service/os/multi_wait.cpp
+ hle/service/os/multi_wait.h
hle/service/os/multi_wait_holder.cpp
hle/service/os/multi_wait_holder.h
hle/service/os/multi_wait_utils.h
- hle/service/os/multi_wait.cpp
- hle/service/os/multi_wait.h
hle/service/os/mutex.cpp
hle/service/os/mutex.h
hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h
+ hle/service/pctl/parental_control_service_factory.cpp
+ hle/service/pctl/parental_control_service_factory.h
+ hle/service/pctl/parental_control_service.cpp
+ hle/service/pctl/parental_control_service.h
hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h
- hle/service/pctl/pctl_module.cpp
- hle/service/pctl/pctl_module.h
+ hle/service/pctl/pctl_results.h
+ hle/service/pctl/pctl_types.h
hle/service/pcv/pcv.cpp
hle/service/pcv/pcv.h
hle/service/pm/pm.cpp
hle/service/pm/pm.h
hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h
+ hle/service/psc/ovln/ovln_types.h
+ hle/service/psc/ovln/receiver_service.cpp
+ hle/service/psc/ovln/receiver_service.h
+ hle/service/psc/ovln/receiver.cpp
+ hle/service/psc/ovln/receiver.h
+ hle/service/psc/ovln/sender_service.cpp
+ hle/service/psc/ovln/sender_service.h
+ hle/service/psc/ovln/sender.cpp
+ hle/service/psc/ovln/sender.h
+ hle/service/psc/pm_control.cpp
+ hle/service/psc/pm_control.h
+ hle/service/psc/pm_module.cpp
+ hle/service/psc/pm_module.h
+ hle/service/psc/pm_service.cpp
+ hle/service/psc/pm_service.h
hle/service/psc/psc.cpp
hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp
@@ -908,15 +968,17 @@ add_library(core STATIC
hle/service/psc/time/common.cpp
hle/service/psc/time/common.h
hle/service/psc/time/errors.h
- hle/service/psc/time/shared_memory.cpp
- hle/service/psc/time/shared_memory.h
- hle/service/psc/time/static.cpp
- hle/service/psc/time/static.h
hle/service/psc/time/manager.h
+ hle/service/psc/time/power_state_request_manager.cpp
+ hle/service/psc/time/power_state_request_manager.h
hle/service/psc/time/power_state_service.cpp
hle/service/psc/time/power_state_service.h
hle/service/psc/time/service_manager.cpp
hle/service/psc/time/service_manager.h
+ hle/service/psc/time/shared_memory.cpp
+ hle/service/psc/time/shared_memory.h
+ hle/service/psc/time/static.cpp
+ hle/service/psc/time/static.h
hle/service/psc/time/steady_clock.cpp
hle/service/psc/time/steady_clock.h
hle/service/psc/time/system_clock.cpp
@@ -925,8 +987,6 @@ add_library(core STATIC
hle/service/psc/time/time_zone.h
hle/service/psc/time/time_zone_service.cpp
hle/service/psc/time/time_zone_service.h
- hle/service/psc/time/power_state_request_manager.cpp
- hle/service/psc/time/power_state_request_manager.h
hle/service/ptm/psm.cpp
hle/service/ptm/psm.h
hle/service/ptm/ptm.cpp
@@ -945,19 +1005,19 @@ add_library(core STATIC
hle/service/service.h
hle/service/services.cpp
hle/service/services.h
+ hle/service/set/factory_settings_server.cpp
+ hle/service/set/factory_settings_server.h
+ hle/service/set/firmware_debug_settings_server.cpp
+ hle/service/set/firmware_debug_settings_server.h
+ hle/service/set/key_code_map.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
- hle/service/set/setting_formats/system_settings.cpp
- hle/service/set/setting_formats/system_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
- hle/service/set/factory_settings_server.cpp
- hle/service/set/factory_settings_server.h
- hle/service/set/firmware_debug_settings_server.cpp
- hle/service/set/firmware_debug_settings_server.h
- hle/service/set/key_code_map.h
+ hle/service/set/setting_formats/system_settings.cpp
+ hle/service/set/setting_formats/system_settings.h
hle/service/set/settings.cpp
hle/service/set/settings.h
hle/service/set/settings_server.cpp
@@ -1000,10 +1060,10 @@ add_library(core STATIC
hle/service/vi/conductor.h
hle/service/vi/container.cpp
hle/service/vi/container.h
- hle/service/vi/display_list.h
hle/service/vi/display.h
- hle/service/vi/layer_list.h
+ hle/service/vi/display_list.h
hle/service/vi/layer.h
+ hle/service/vi/layer_list.h
hle/service/vi/manager_display_service.cpp
hle/service/vi/manager_display_service.h
hle/service/vi/manager_root_service.cpp
@@ -1016,10 +1076,10 @@ add_library(core STATIC
hle/service/vi/system_display_service.h
hle/service/vi/system_root_service.cpp
hle/service/vi/system_root_service.h
- hle/service/vi/vi_results.h
- hle/service/vi/vi_types.h
hle/service/vi/vi.cpp
hle/service/vi/vi.h
+ hle/service/vi/vi_results.h
+ hle/service/vi/vi_types.h
hle/service/vi/vsync_manager.cpp
hle/service/vi/vsync_manager.h
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) {
data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup
- SCOPE_EXIT({
+ SCOPE_EXIT {
data.host_context->Exit();
MicroProfileOnThreadExit();
- });
+ };
// Running
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
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
const auto current_vaddr =
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
- SCOPE_EXIT({
+ SCOPE_EXIT{
page_index += next_pages;
page_offset = 0;
increment(copy_amount);
remaining_size -= copy_amount;
- });
+ };
auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr == 0) {
@@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
auto* memory_device_inter = registered_processes[asid.id];
const auto release_pending = [&] {
if (uncache_bytes > 0) {
- MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
- uncache_bytes, false);
+ if (memory_device_inter != nullptr) {
+ MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
+ uncache_bytes, false);
+ }
uncache_bytes = 0;
}
if (cache_bytes > 0) {
- MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
- cache_bytes, true);
+ if (memory_device_inter != nullptr) {
+ MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
+ cache_bytes, true);
+ }
cache_bytes = 0;
}
};
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 @@
#pragma once
+#include <string_view>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
namespace FileSys {
constexpr 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 {
File = (1 << 1),
All = (Directory | File),
+
+ NotRequireFileSize = (1ULL << 31),
};
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@@ -36,4 +38,29 @@ enum class CreateOption : u8 {
BigFile = (1 << 0),
};
+struct FileSystemAttribute {
+ u8 dir_entry_name_length_max_defined;
+ u8 file_entry_name_length_max_defined;
+ u8 dir_path_name_length_max_defined;
+ u8 file_path_name_length_max_defined;
+ INSERT_PADDING_BYTES_NOINIT(0x5);
+ u8 utf16_dir_entry_name_length_max_defined;
+ u8 utf16_file_entry_name_length_max_defined;
+ u8 utf16_dir_path_name_length_max_defined;
+ u8 utf16_file_path_name_length_max_defined;
+ INSERT_PADDING_BYTES_NOINIT(0x18);
+ s32 dir_entry_name_length_max;
+ s32 file_entry_name_length_max;
+ s32 dir_path_name_length_max;
+ s32 file_path_name_length_max;
+ INSERT_PADDING_WORDS_NOINIT(0x5);
+ s32 utf16_dir_entry_name_length_max;
+ s32 utf16_file_entry_name_length_max;
+ s32 utf16_dir_path_name_length_max;
+ s32 utf16_file_path_name_length_max;
+ INSERT_PADDING_WORDS_NOINIT(0x18);
+ INSERT_PADDING_WORDS_NOINIT(0x1);
+};
+static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
+
} // 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 {
constexpr size_t RequiredAlignment = alignof(u64);
-void* AllocateUnsafe(size_t size) {
+inline void* AllocateUnsafe(size_t size) {
// Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
return ptr;
}
-void DeallocateUnsafe(void* ptr, size_t size) {
+inline void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment});
}
-void* Allocate(size_t size) {
+inline void* Allocate(size_t size) {
return AllocateUnsafe(size);
}
-void Deallocate(void* ptr, size_t size) {
+inline void Deallocate(void* ptr, size_t size) {
// If the pointer is non-null, deallocate it
if (ptr != nullptr) {
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:
// Check that it's possible for us to remove a child
auto* p = m_write_buffer.Get();
- s32 len = std::strlen(p);
+ s32 len = static_cast<s32>(std::strlen(p));
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// 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:
R_SUCCEED();
}
- static Result Normalize(char* dst, size_t* out_len, const char* path, size_t max_out_size,
- bool is_windows_path, bool is_drive_relative_path,
- bool allow_all_characters = false) {
+ static constexpr Result Normalize(char* dst, size_t* out_len, const char* path,
+ size_t max_out_size, bool is_windows_path,
+ bool is_drive_relative_path,
+ bool allow_all_characters = false) {
// Use StringTraits names for remainder of scope
using namespace StringTraits;
@@ -447,7 +448,7 @@ public:
char* replacement_path = nullptr;
size_t replacement_path_size = 0;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (replacement_path != nullptr) {
if (std::is_constant_evaluated()) {
delete[] replacement_path;
@@ -455,7 +456,7 @@ public:
Deallocate(replacement_path, replacement_path_size);
}
}
- });
+ };
// Perform path replacement, if necessary
if (IsParentDirectoryPathReplacementNeeded(cur_path)) {
@@ -1102,8 +1103,8 @@ public:
R_SUCCEED();
}
- static Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
- const PathFlags& flags) {
+ static constexpr Result Normalize(char* dst, size_t dst_size, const char* path, size_t path_len,
+ const PathFlags& flags) {
// Use StringTraits names for remainder of scope
using namespace StringTraits;
@@ -1199,7 +1200,7 @@ public:
const size_t replaced_src_len = path_len - (src - path);
char* replaced_src = nullptr;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (replaced_src != nullptr) {
if (std::is_constant_evaluated()) {
delete[] replaced_src;
@@ -1207,7 +1208,7 @@ public:
Deallocate(replaced_src, replaced_src_len);
}
}
- });
+ };
if (std::is_constant_evaluated()) {
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <fmt/format.h>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace FileSys {
+
+using SaveDataId = u64;
+using SystemSaveDataId = u64;
+using SystemBcatSaveDataId = SystemSaveDataId;
+using ProgramId = u64;
+
+enum class SaveDataSpaceId : u8 {
+ System = 0,
+ User = 1,
+ SdSystem = 2,
+ Temporary = 3,
+ SdUser = 4,
+
+ ProperSystem = 100,
+ SafeMode = 101,
+};
+
+enum class SaveDataType : u8 {
+ System = 0,
+ Account = 1,
+ Bcat = 2,
+ Device = 3,
+ Temporary = 4,
+ Cache = 5,
+ SystemBcat = 6,
+};
+
+enum class SaveDataRank : u8 {
+ Primary = 0,
+ Secondary = 1,
+};
+
+struct SaveDataSize {
+ u64 normal;
+ u64 journal;
+};
+static_assert(sizeof(SaveDataSize) == 0x10, "SaveDataSize has invalid size.");
+
+using UserId = u128;
+static_assert(std::is_trivially_copyable_v<UserId>, "Data type must be trivially copyable.");
+static_assert(sizeof(UserId) == 0x10, "UserId has invalid size.");
+
+constexpr inline SystemSaveDataId InvalidSystemSaveDataId = 0;
+constexpr inline UserId InvalidUserId = {};
+
+enum class SaveDataFlags : u32 {
+ None = (0 << 0),
+ KeepAfterResettingSystemSaveData = (1 << 0),
+ KeepAfterRefurbishment = (1 << 1),
+ KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
+ NeedsSecureDelete = (1 << 3),
+};
+
+enum class SaveDataMetaType : u8 {
+ None = 0,
+ Thumbnail = 1,
+ ExtensionContext = 2,
+};
+
+struct SaveDataMetaInfo {
+ u32 size;
+ SaveDataMetaType type;
+ INSERT_PADDING_BYTES(0xB);
+};
+static_assert(std::is_trivially_copyable_v<SaveDataMetaInfo>,
+ "Data type must be trivially copyable.");
+static_assert(sizeof(SaveDataMetaInfo) == 0x10, "SaveDataMetaInfo has invalid size.");
+
+struct SaveDataCreationInfo {
+ s64 size;
+ s64 journal_size;
+ s64 block_size;
+ u64 owner_id;
+ u32 flags;
+ SaveDataSpaceId space_id;
+ bool pseudo;
+ INSERT_PADDING_BYTES(0x1A);
+};
+static_assert(std::is_trivially_copyable_v<SaveDataCreationInfo>,
+ "Data type must be trivially copyable.");
+static_assert(sizeof(SaveDataCreationInfo) == 0x40, "SaveDataCreationInfo has invalid size.");
+
+struct SaveDataAttribute {
+ ProgramId program_id;
+ UserId user_id;
+ SystemSaveDataId system_save_data_id;
+ SaveDataType type;
+ SaveDataRank rank;
+ u16 index;
+ INSERT_PADDING_BYTES(0x1C);
+
+ static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
+ SystemSaveDataId system_save_data_id, u16 index,
+ SaveDataRank rank) {
+ return {
+ .program_id = program_id,
+ .user_id = user_id,
+ .system_save_data_id = system_save_data_id,
+ .type = type,
+ .rank = rank,
+ .index = index,
+ };
+ }
+
+ static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
+ SystemSaveDataId system_save_data_id, u16 index) {
+ return Make(program_id, type, user_id, system_save_data_id, index, SaveDataRank::Primary);
+ }
+
+ static constexpr SaveDataAttribute Make(ProgramId program_id, SaveDataType type, UserId user_id,
+ SystemSaveDataId system_save_data_id) {
+ return Make(program_id, type, user_id, system_save_data_id, 0, SaveDataRank::Primary);
+ }
+
+ std::string DebugInfo() const {
+ return fmt::format(
+ "[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
+ "rank={}, index={}]",
+ program_id, user_id[1], user_id[0], system_save_data_id, static_cast<u8>(type),
+ static_cast<u8>(rank), index);
+ }
+};
+static_assert(sizeof(SaveDataAttribute) == 0x40);
+static_assert(std::is_trivially_destructible<SaveDataAttribute>::value);
+
+constexpr inline bool operator<(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
+ return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.index, lhs.rank) <
+ std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id, rhs.index, rhs.rank);
+}
+
+constexpr inline bool operator==(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
+ return std::tie(lhs.program_id, lhs.user_id, lhs.system_save_data_id, lhs.type, lhs.rank,
+ lhs.index) == std::tie(rhs.program_id, rhs.user_id, rhs.system_save_data_id,
+ rhs.type, rhs.rank, rhs.index);
+}
+
+constexpr inline bool operator!=(const SaveDataAttribute& lhs, const SaveDataAttribute& rhs) {
+ return !(lhs == rhs);
+}
+
+struct SaveDataExtraData {
+ SaveDataAttribute attr;
+ u64 owner_id;
+ s64 timestamp;
+ u32 flags;
+ INSERT_PADDING_BYTES(4);
+ s64 available_size;
+ s64 journal_size;
+ s64 commit_id;
+ INSERT_PADDING_BYTES(0x190);
+};
+static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has invalid size.");
+static_assert(std::is_trivially_copyable_v<SaveDataExtraData>,
+ "Data type must be trivially copyable.");
+
+struct SaveDataFilter {
+ bool use_program_id;
+ bool use_save_data_type;
+ bool use_user_id;
+ bool use_save_data_id;
+ bool use_index;
+ SaveDataRank rank;
+ SaveDataAttribute attribute;
+};
+static_assert(sizeof(SaveDataFilter) == 0x48, "SaveDataFilter has invalid size.");
+static_assert(std::is_trivially_copyable_v<SaveDataFilter>,
+ "Data type must be trivially copyable.");
+
+struct HashSalt {
+ static constexpr size_t Size = 32;
+
+ std::array<u8, Size> value;
+};
+static_assert(std::is_trivially_copyable_v<HashSalt>, "Data type must be trivially copyable.");
+static_assert(sizeof(HashSalt) == HashSalt::Size);
+
+} // 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) {
}
template <typename T>
+constexpr int Strnlen(const T* str, std::size_t count) {
+ return Strnlen(str, static_cast<int>(count));
+}
+
+template <typename T>
constexpr int Strnlen(const T* str, int count) {
ASSERT(str != nullptr);
ASSERT(count >= 0);
@@ -33,6 +38,11 @@ constexpr int Strnlen(const T* str, int count) {
}
template <typename T>
+constexpr int Strncmp(const T* lhs, const T* rhs, std::size_t count) {
+ return Strncmp(lhs, rhs, static_cast<int>(count));
+}
+
+template <typename T>
constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
ASSERT(lhs != nullptr);
ASSERT(rhs != nullptr);
@@ -52,6 +62,11 @@ constexpr int Strncmp(const T* lhs, const T* rhs, int count) {
}
template <typename T>
+static constexpr int Strlcpy(T* dst, const T* src, std::size_t count) {
+ return Strlcpy<T>(dst, src, static_cast<int>(count));
+}
+
+template <typename T>
static constexpr int Strlcpy(T* dst, const T* src, int count) {
ASSERT(dst != nullptr);
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/file_sys/errors.h"
+#include "core/file_sys/fs_directory.h"
+#include "core/file_sys/fs_file.h"
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/result.h"
+
+namespace FileSys::Fsa {
+
+class IDirectory {
+public:
+ explicit IDirectory(VirtualDir backend_, OpenDirectoryMode mode)
+ : backend(std::move(backend_)) {
+ // TODO(DarkLordZach): Verify that this is the correct behavior.
+ // Build entry index now to save time later.
+ if (True(mode & OpenDirectoryMode::Directory)) {
+ BuildEntryIndex(backend->GetSubdirectories(), DirectoryEntryType::Directory);
+ }
+ if (True(mode & OpenDirectoryMode::File)) {
+ BuildEntryIndex(backend->GetFiles(), DirectoryEntryType::File);
+ }
+ }
+ virtual ~IDirectory() {}
+
+ Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
+ R_UNLESS(out_count != nullptr, ResultNullptrArgument);
+ if (max_entries == 0) {
+ *out_count = 0;
+ R_SUCCEED();
+ }
+ R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
+ R_UNLESS(max_entries > 0, ResultInvalidArgument);
+ R_RETURN(this->DoRead(out_count, out_entries, max_entries));
+ }
+
+ Result GetEntryCount(s64* out) {
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+ R_RETURN(this->DoGetEntryCount(out));
+ }
+
+private:
+ Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
+ const u64 actual_entries =
+ std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
+ const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+ *out_count = actual_entries;
+
+ std::memcpy(out_entries, begin, range_size);
+
+ R_SUCCEED();
+ }
+
+ Result DoGetEntryCount(s64* out) {
+ *out = entries.size() - next_entry_index;
+ R_SUCCEED();
+ }
+
+ // TODO: Remove this when VFS is gone
+ template <typename T>
+ void BuildEntryIndex(const std::vector<T>& new_data, DirectoryEntryType type) {
+ entries.reserve(entries.size() + new_data.size());
+
+ for (const auto& new_entry : new_data) {
+ auto name = new_entry->GetName();
+
+ if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
+ continue;
+ }
+
+ entries.emplace_back(name, static_cast<s8>(type),
+ type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
+ }
+ }
+
+ VirtualDir backend;
+ std::vector<DirectoryEntry> entries;
+ u64 next_entry_index = 0;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/overflow.h"
+#include "core/file_sys/errors.h"
+#include "core/file_sys/fs_file.h"
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/fs_operate_range.h"
+#include "core/file_sys/vfs/vfs.h"
+#include "core/file_sys/vfs/vfs_types.h"
+#include "core/hle/result.h"
+
+namespace FileSys::Fsa {
+
+class IFile {
+public:
+ explicit IFile(VirtualFile backend_) : backend(std::move(backend_)) {}
+ virtual ~IFile() {}
+
+ Result Read(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
+ // Check that we have an output pointer
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+
+ // If we have nothing to read, just succeed
+ if (size == 0) {
+ *out = 0;
+ R_SUCCEED();
+ }
+
+ // Check that the read is valid
+ R_UNLESS(buffer != nullptr, ResultNullptrArgument);
+ R_UNLESS(offset >= 0, ResultOutOfRange);
+ R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
+
+ // Do the read
+ R_RETURN(this->DoRead(out, offset, buffer, size, option));
+ }
+
+ Result Read(size_t* out, s64 offset, void* buffer, size_t size) {
+ R_RETURN(this->Read(out, offset, buffer, size, ReadOption::None));
+ }
+
+ Result GetSize(s64* out) {
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+ R_RETURN(this->DoGetSize(out));
+ }
+
+ Result Flush() {
+ R_RETURN(this->DoFlush());
+ }
+
+ Result Write(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
+ // Handle the zero-size case
+ if (size == 0) {
+ if (option.HasFlushFlag()) {
+ R_TRY(this->Flush());
+ }
+ R_SUCCEED();
+ }
+
+ // Check the write is valid
+ R_UNLESS(buffer != nullptr, ResultNullptrArgument);
+ R_UNLESS(offset >= 0, ResultOutOfRange);
+ R_UNLESS(Common::CanAddWithoutOverflow<s64>(offset, size), ResultOutOfRange);
+
+ R_RETURN(this->DoWrite(offset, buffer, size, option));
+ }
+
+ Result SetSize(s64 size) {
+ R_UNLESS(size >= 0, ResultOutOfRange);
+ R_RETURN(this->DoSetSize(size));
+ }
+
+ Result OperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
+ const void* src, size_t src_size) {
+ R_RETURN(this->DoOperateRange(dst, dst_size, op_id, offset, size, src, src_size));
+ }
+
+ Result OperateRange(OperationId op_id, s64 offset, s64 size) {
+ R_RETURN(this->DoOperateRange(nullptr, 0, op_id, offset, size, nullptr, 0));
+ }
+
+protected:
+ Result DryRead(size_t* out, s64 offset, size_t size, const ReadOption& option,
+ OpenMode open_mode) {
+ // Check that we can read
+ R_UNLESS(static_cast<u32>(open_mode & OpenMode::Read) != 0, ResultReadNotPermitted);
+
+ // Get the file size, and validate our offset
+ s64 file_size = 0;
+ R_TRY(this->DoGetSize(std::addressof(file_size)));
+ R_UNLESS(offset <= file_size, ResultOutOfRange);
+
+ *out = static_cast<size_t>(std::min(file_size - offset, static_cast<s64>(size)));
+ R_SUCCEED();
+ }
+
+ Result DrySetSize(s64 size, OpenMode open_mode) {
+ // Check that we can write
+ R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
+ R_SUCCEED();
+ }
+
+ Result DryWrite(bool* out_append, s64 offset, size_t size, const WriteOption& option,
+ OpenMode open_mode) {
+ // Check that we can write
+ R_UNLESS(static_cast<u32>(open_mode & OpenMode::Write) != 0, ResultWriteNotPermitted);
+
+ // Get the file size
+ s64 file_size = 0;
+ R_TRY(this->DoGetSize(&file_size));
+
+ // Determine if we need to append
+ *out_append = false;
+ if (file_size < offset + static_cast<s64>(size)) {
+ R_UNLESS(static_cast<u32>(open_mode & OpenMode::AllowAppend) != 0,
+ ResultFileExtensionWithoutOpenModeAllowAppend);
+ *out_append = true;
+ }
+
+ R_SUCCEED();
+ }
+
+private:
+ Result DoRead(size_t* out, s64 offset, void* buffer, size_t size, const ReadOption& option) {
+ const auto read_size = backend->Read(static_cast<u8*>(buffer), size, offset);
+ *out = read_size;
+
+ R_SUCCEED();
+ }
+
+ Result DoGetSize(s64* out) {
+ *out = backend->GetSize();
+ R_SUCCEED();
+ }
+
+ Result DoFlush() {
+ // Exists for SDK compatibiltity -- No need to flush file.
+ R_SUCCEED();
+ }
+
+ Result DoWrite(s64 offset, const void* buffer, size_t size, const WriteOption& option) {
+ const std::size_t written = backend->Write(static_cast<const u8*>(buffer), size, offset);
+
+ ASSERT_MSG(written == size,
+ "Could not write all bytes to file (requested={:016X}, actual={:016X}).", size,
+ written);
+
+ R_SUCCEED();
+ }
+
+ Result DoSetSize(s64 size) {
+ backend->Resize(size);
+ R_SUCCEED();
+ }
+
+ Result DoOperateRange(void* dst, size_t dst_size, OperationId op_id, s64 offset, s64 size,
+ const void* src, size_t src_size) {
+ R_THROW(ResultNotImplemented);
+ }
+
+ VirtualFile backend;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/errors.h"
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/fs_path.h"
+#include "core/file_sys/vfs/vfs_types.h"
+#include "core/hle/result.h"
+#include "core/hle/service/filesystem/filesystem.h"
+
+namespace FileSys::Fsa {
+
+class IFile;
+class IDirectory;
+
+enum class QueryId : u32 {
+ SetConcatenationFileAttribute = 0,
+ UpdateMac = 1,
+ IsSignedSystemPartitionOnSdCardValid = 2,
+ QueryUnpreparedFileInformation = 3,
+};
+
+class IFileSystem {
+public:
+ explicit IFileSystem(VirtualDir backend_) : backend{std::move(backend_)} {}
+ virtual ~IFileSystem() {}
+
+ Result CreateFile(const Path& path, s64 size, CreateOption option) {
+ R_UNLESS(size >= 0, ResultOutOfRange);
+ R_RETURN(this->DoCreateFile(path, size, static_cast<int>(option)));
+ }
+
+ Result CreateFile(const Path& path, s64 size) {
+ R_RETURN(this->CreateFile(path, size, CreateOption::None));
+ }
+
+ Result DeleteFile(const Path& path) {
+ R_RETURN(this->DoDeleteFile(path));
+ }
+
+ Result CreateDirectory(const Path& path) {
+ R_RETURN(this->DoCreateDirectory(path));
+ }
+
+ Result DeleteDirectory(const Path& path) {
+ R_RETURN(this->DoDeleteDirectory(path));
+ }
+
+ Result DeleteDirectoryRecursively(const Path& path) {
+ R_RETURN(this->DoDeleteDirectoryRecursively(path));
+ }
+
+ Result RenameFile(const Path& old_path, const Path& new_path) {
+ R_RETURN(this->DoRenameFile(old_path, new_path));
+ }
+
+ Result RenameDirectory(const Path& old_path, const Path& new_path) {
+ R_RETURN(this->DoRenameDirectory(old_path, new_path));
+ }
+
+ Result GetEntryType(DirectoryEntryType* out, const Path& path) {
+ R_RETURN(this->DoGetEntryType(out, path));
+ }
+
+ Result OpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
+ R_UNLESS(out_file != nullptr, ResultNullptrArgument);
+ R_UNLESS(static_cast<u32>(mode & OpenMode::ReadWrite) != 0, ResultInvalidOpenMode);
+ R_UNLESS(static_cast<u32>(mode & ~OpenMode::All) == 0, ResultInvalidOpenMode);
+ R_RETURN(this->DoOpenFile(out_file, path, mode));
+ }
+
+ Result OpenDirectory(VirtualDir* out_dir, const Path& path, OpenDirectoryMode mode) {
+ R_UNLESS(out_dir != nullptr, ResultNullptrArgument);
+ R_UNLESS(static_cast<u64>(mode & OpenDirectoryMode::All) != 0, ResultInvalidOpenMode);
+ R_UNLESS(static_cast<u64>(
+ mode & ~(OpenDirectoryMode::All | OpenDirectoryMode::NotRequireFileSize)) == 0,
+ ResultInvalidOpenMode);
+ R_RETURN(this->DoOpenDirectory(out_dir, path, mode));
+ }
+
+ Result Commit() {
+ R_RETURN(this->DoCommit());
+ }
+
+ Result GetFreeSpaceSize(s64* out, const Path& path) {
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+ R_RETURN(this->DoGetFreeSpaceSize(out, path));
+ }
+
+ Result GetTotalSpaceSize(s64* out, const Path& path) {
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+ R_RETURN(this->DoGetTotalSpaceSize(out, path));
+ }
+
+ Result CleanDirectoryRecursively(const Path& path) {
+ R_RETURN(this->DoCleanDirectoryRecursively(path));
+ }
+
+ Result GetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
+ R_UNLESS(out != nullptr, ResultNullptrArgument);
+ R_RETURN(this->DoGetFileTimeStampRaw(out, path));
+ }
+
+ Result QueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
+ const Path& path) {
+ R_RETURN(this->DoQueryEntry(dst, dst_size, src, src_size, query, path));
+ }
+
+ // These aren't accessible as commands
+ Result CommitProvisionally(s64 counter) {
+ R_RETURN(this->DoCommitProvisionally(counter));
+ }
+
+ Result Rollback() {
+ R_RETURN(this->DoRollback());
+ }
+
+ Result Flush() {
+ R_RETURN(this->DoFlush());
+ }
+
+private:
+ Result DoCreateFile(const Path& path, s64 size, int flags) {
+ R_RETURN(backend.CreateFile(path.GetString(), size));
+ }
+
+ Result DoDeleteFile(const Path& path) {
+ R_RETURN(backend.DeleteFile(path.GetString()));
+ }
+
+ Result DoCreateDirectory(const Path& path) {
+ R_RETURN(backend.CreateDirectory(path.GetString()));
+ }
+
+ Result DoDeleteDirectory(const Path& path) {
+ R_RETURN(backend.DeleteDirectory(path.GetString()));
+ }
+
+ Result DoDeleteDirectoryRecursively(const Path& path) {
+ R_RETURN(backend.DeleteDirectoryRecursively(path.GetString()));
+ }
+
+ Result DoRenameFile(const Path& old_path, const Path& new_path) {
+ R_RETURN(backend.RenameFile(old_path.GetString(), new_path.GetString()));
+ }
+
+ Result DoRenameDirectory(const Path& old_path, const Path& new_path) {
+ R_RETURN(backend.RenameDirectory(old_path.GetString(), new_path.GetString()));
+ }
+
+ Result DoGetEntryType(DirectoryEntryType* out, const Path& path) {
+ R_RETURN(backend.GetEntryType(out, path.GetString()));
+ }
+
+ Result DoOpenFile(VirtualFile* out_file, const Path& path, OpenMode mode) {
+ R_RETURN(backend.OpenFile(out_file, path.GetString(), mode));
+ }
+
+ Result DoOpenDirectory(VirtualDir* out_directory, const Path& path, OpenDirectoryMode mode) {
+ R_RETURN(backend.OpenDirectory(out_directory, path.GetString()));
+ }
+
+ Result DoCommit() {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Result DoGetFreeSpaceSize(s64* out, const Path& path) {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Result DoGetTotalSpaceSize(s64* out, const Path& path) {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Result DoCleanDirectoryRecursively(const Path& path) {
+ R_RETURN(backend.CleanDirectoryRecursively(path.GetString()));
+ }
+
+ Result DoGetFileTimeStampRaw(FileTimeStampRaw* out, const Path& path) {
+ R_RETURN(backend.GetFileTimeStampRaw(out, path.GetString()));
+ }
+
+ Result DoQueryEntry(char* dst, size_t dst_size, const char* src, size_t src_size, QueryId query,
+ const Path& path) {
+ R_THROW(ResultNotImplemented);
+ }
+
+ // These aren't accessible as commands
+ Result DoCommitProvisionally(s64 counter) {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Result DoRollback() {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Result DoFlush() {
+ R_THROW(ResultNotImplemented);
+ }
+
+ Service::FileSystem::VfsDirectoryServiceWrapper backend;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/fs_directory.h"
+
+namespace FileSys::Sf {
+
+struct Path {
+ char str[EntryNameLengthMax + 1];
+
+ static constexpr Path Encode(const char* p) {
+ Path path = {};
+ for (size_t i = 0; i < sizeof(path) - 1; i++) {
+ path.str[i] = p[i];
+ if (p[i] == '\x00') {
+ break;
+ }
+ }
+ return path;
+ }
+
+ static constexpr size_t GetPathLength(const Path& path) {
+ size_t len = 0;
+ for (size_t i = 0; i < sizeof(path) - 1 && path.str[i] != '\x00'; i++) {
+ len++;
+ }
+ return len;
+ }
+};
+static_assert(std::is_trivially_copyable_v<Path>, "Path must be trivially copyable.");
+
+using FspPath = Path;
+
+} // 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 @@
#pragma once
+#include <mutex>
#include <optional>
#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
// Get the base storage size.
m_base_storage_size = base_storages[2]->GetSize();
{
- auto size_guard = SCOPE_GUARD({ m_base_storage_size = 0; });
+ auto size_guard = SCOPE_GUARD {
+ m_base_storage_size = 0;
+ };
R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
<< m_log_size_ratio << m_log_size_ratio,
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) {
Loader::ResultStatus ProgramMetadata::Reload(VirtualFile file) {
const u64 original_program_id = aci_header.title_id;
- SCOPE_EXIT({ aci_header.title_id = original_program_id; });
+ SCOPE_EXIT {
+ aci_header.title_id = original_program_id;
+ };
return this->Load(file);
}
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 {
namespace {
-void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
- if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
- if (meta.zero_1 != 0) {
- LOG_WARNING(Service_FS,
- "Possibly incorrect SaveDataAttribute, type is "
- "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
- meta.zero_1);
- }
- if (meta.zero_2 != 0) {
- LOG_WARNING(Service_FS,
- "Possibly incorrect SaveDataAttribute, type is "
- "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
- meta.zero_2);
- }
- if (meta.zero_3 != 0) {
- LOG_WARNING(Service_FS,
- "Possibly incorrect SaveDataAttribute, type is "
- "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
- meta.zero_3);
- }
- }
-
- if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
- LOG_WARNING(Service_FS,
- "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
- "non-zero ({:016X}).",
- meta.title_id);
- }
-
- if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
- LOG_WARNING(Service_FS,
- "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
- "non-zero ({:016X}{:016X})",
- meta.user_id[1], meta.user_id[0]);
- }
-}
-
bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
- return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
- (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
- (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
- attr.title_id == 0 && attr.save_id == 0);
+ return attr.type == SaveDataType::Cache || attr.type == SaveDataType::Temporary ||
+ (space == SaveDataSpaceId::User && ///< Normal Save Data -- Current Title & User
+ (attr.type == SaveDataType::Account || attr.type == SaveDataType::Device) &&
+ attr.program_id == 0 && attr.system_save_data_id == 0);
}
std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u64 title_id,
@@ -63,7 +26,7 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect nand user saves.
const auto space_id_path = [space_id]() -> std::string_view {
switch (space_id) {
- case SaveDataSpaceId::NandUser:
+ case SaveDataSpaceId::User:
return "/user/save";
default:
return "";
@@ -79,9 +42,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect account/device saves from the future location.
switch (type) {
- case SaveDataType::SaveData:
+ case SaveDataType::Account:
return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
- case SaveDataType::DeviceSaveData:
+ case SaveDataType::Device:
return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
default:
return "";
@@ -90,13 +53,6 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
} // Anonymous namespace
-std::string SaveDataAttribute::DebugInfo() const {
- return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
- "rank={}, index={}]",
- title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
- static_cast<u8>(rank), index);
-}
-
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
VirtualDir save_directory_)
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
@@ -108,18 +64,16 @@ SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
SaveDataFactory::~SaveDataFactory() = default;
VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
- PrintSaveDataAttributeWarnings(meta);
-
- const auto save_directory =
- GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+ const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
+ meta.user_id, meta.system_save_data_id);
return dir->CreateDirectoryRelative(save_directory);
}
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
- const auto save_directory =
- GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+ const auto save_directory = GetFullPath(program_id, dir, space, meta.type, meta.program_id,
+ meta.user_id, meta.system_save_data_id);
auto out = dir->GetDirectoryRelative(save_directory);
@@ -136,11 +90,11 @@ VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) con
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
switch (space) {
- case SaveDataSpaceId::NandSystem:
+ case SaveDataSpaceId::System:
return "/system/";
- case SaveDataSpaceId::NandUser:
+ case SaveDataSpaceId::User:
return "/user/";
- case SaveDataSpaceId::TemporaryStorage:
+ case SaveDataSpaceId::Temporary:
return "/temp/";
default:
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
@@ -153,7 +107,7 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
- if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
+ if (type == SaveDataType::Account || type == SaveDataType::Device) {
if (title_id == 0) {
title_id = program_id;
}
@@ -173,16 +127,16 @@ std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
std::string out = GetSaveDataSpaceIdPath(space);
switch (type) {
- case SaveDataType::SystemSaveData:
+ case SaveDataType::System:
return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
- case SaveDataType::SaveData:
- case SaveDataType::DeviceSaveData:
+ case SaveDataType::Account:
+ case SaveDataType::Device:
return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
- case SaveDataType::TemporaryStorage:
+ case SaveDataType::Temporary:
return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
title_id);
- case SaveDataType::CacheStorage:
+ case SaveDataType::Cache:
return fmt::format("{}save/cache/{:016X}", out, title_id);
default:
ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
@@ -202,7 +156,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path =
- GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+ GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
@@ -221,7 +175,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
const auto path =
- GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
+ GetFullPath(program_id, dir, SaveDataSpaceId::User, type, title_id, user_id, 0);
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
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 @@
#include <string>
#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "core/file_sys/fs_save_data_types.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
@@ -16,73 +17,6 @@ class System;
namespace FileSys {
-enum class SaveDataSpaceId : u8 {
- NandSystem = 0,
- NandUser = 1,
- SdCardSystem = 2,
- TemporaryStorage = 3,
- SdCardUser = 4,
- ProperSystem = 100,
- SafeMode = 101,
-};
-
-enum class SaveDataType : u8 {
- SystemSaveData = 0,
- SaveData = 1,
- BcatDeliveryCacheStorage = 2,
- DeviceSaveData = 3,
- TemporaryStorage = 4,
- CacheStorage = 5,
- SystemBcat = 6,
-};
-
-enum class SaveDataRank : u8 {
- Primary = 0,
- Secondary = 1,
-};
-
-enum class SaveDataFlags : u32 {
- None = (0 << 0),
- KeepAfterResettingSystemSaveData = (1 << 0),
- KeepAfterRefurbishment = (1 << 1),
- KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
- NeedsSecureDelete = (1 << 3),
-};
-
-struct SaveDataAttribute {
- u64 title_id;
- u128 user_id;
- u64 save_id;
- SaveDataType type;
- SaveDataRank rank;
- u16 index;
- INSERT_PADDING_BYTES_NOINIT(4);
- u64 zero_1;
- u64 zero_2;
- u64 zero_3;
-
- std::string DebugInfo() const;
-};
-static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
-
-struct SaveDataExtraData {
- SaveDataAttribute attr;
- u64 owner_id;
- s64 timestamp;
- SaveDataFlags flags;
- INSERT_PADDING_BYTES_NOINIT(4);
- s64 available_size;
- s64 journal_size;
- s64 commit_id;
- std::array<u8, 0x190> unused;
-};
-static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
-
-struct SaveDataSize {
- u64 normal;
- u64 journal;
-};
-
constexpr const char* GetSaveDataSizeFileName() {
return ".yuzu_save_size";
}
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) {
// Create a session request.
KSessionRequest* request = KSessionRequest::Create(m_kernel);
R_UNLESS(request != nullptr, ResultOutOfResource);
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// Initialize the request.
request->Initialize(nullptr, address, size);
@@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
// Create a session request.
KSessionRequest* request = KSessionRequest::Create(m_kernel);
R_UNLESS(request != nullptr, ResultOutOfResource);
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// Initialize the request.
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
// Ensure that we maintain the instruction cache.
bool reprotected_pages = false;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (reprotected_pages && any_code_pages) {
InvalidateInstructionCache(m_kernel, this, dst_address, size);
}
- });
+ };
// Unmap.
{
@@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
// Close the opened pages when we're done with them.
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
// automatically.
- SCOPE_EXIT({ pg.Close(); });
+ SCOPE_EXIT {
+ pg.Close();
+ };
// Clear all the newly allocated pages.
for (const auto& it : pg) {
@@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
// Ensure that the page group is closed when we're done working with it.
- SCOPE_EXIT({ pg.Close(); });
+ SCOPE_EXIT {
+ pg.Close();
+ };
// Clear all pages.
for (const auto& it : pg) {
@@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
// Close the opened pages when we're done with them.
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
// automatically.
- SCOPE_EXIT({ pg.Close(); });
+ SCOPE_EXIT {
+ pg.Close();
+ };
// Clear all the newly allocated pages.
for (const auto& it : pg) {
@@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
// Temporarily unlock ourselves, so that other operations can occur while we flush the
// region.
m_general_lock.Unlock();
- SCOPE_EXIT({ m_general_lock.Lock(); });
+ SCOPE_EXIT {
+ m_general_lock.Lock();
+ };
// Flush the region.
R_ASSERT(FlushDataCache(dst_address, size));
@@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
// Ensure we unmap the io memory when we're done with it.
const KPageProperties unmap_properties =
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
- SCOPE_EXIT({
+ SCOPE_EXIT {
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
unmap_properties, OperationType::Unmap, true));
- });
+ };
// Read the memory.
const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
// Ensure we unmap the io memory when we're done with it.
const KPageProperties unmap_properties =
KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
- SCOPE_EXIT({
+ SCOPE_EXIT {
R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
unmap_properties, OperationType::Unmap, true));
- });
+ };
// Write the memory.
const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
// If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
// free on scope exit.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (start_partial_page != 0) {
m_kernel.MemoryManager().Close(start_partial_page, 1);
}
if (end_partial_page != 0) {
m_kernel.MemoryManager().Close(end_partial_page, 1);
}
- });
+ };
ON_RESULT_FAILURE {
if (cur_mapped_addr != dst_addr) {
@@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
// If we fail in the next bit (or retry), we need to cleanup the pages.
- auto pg_guard = SCOPE_GUARD({
+ auto pg_guard = SCOPE_GUARD {
pg.OpenFirst();
pg.Close();
- });
+ };
// Map the memory.
{
@@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
// Ensure that any pages we track are closed on exit.
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
- SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
+ SCOPE_EXIT {
+ pages_to_close.CloseAndReset();
+ };
// Make a page group representing the region to unmap.
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,
}
// Terminate and close the thread.
- SCOPE_EXIT({ cur_child->Close(); });
+ SCOPE_EXIT {
+ cur_child->Close();
+ };
if (const Result terminate_result = cur_child->Terminate();
ResultTerminationRequested == terminate_result) {
@@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() {
Result KProcess::StartTermination() {
// Finalize the handle table when we're done, if the process isn't immortal.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (!m_is_immortal) {
this->FinalizeHandleTable();
}
- });
+ };
// Terminate child threads other than the current one.
R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
@@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
// Create a new thread for the process.
KThread* main_thread = KThread::Create(m_kernel);
R_UNLESS(main_thread != nullptr, ResultOutOfResource);
- SCOPE_EXIT({ main_thread->Close(); });
+ SCOPE_EXIT {
+ main_thread->Close();
+ };
// Initialize the thread.
R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
@@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
// Ensure we maintain a clean state on exit.
- SCOPE_EXIT({ res_limit->Close(); });
+ SCOPE_EXIT {
+ res_limit->Close();
+ };
// Declare flags and code address.
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
// Process any special data.
if (src_header.GetHasSpecialHeader()) {
// After we process, make sure we track whether the receive list is broken.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (offset > dst_recv_list_idx) {
recv_list_broken = true;
}
- });
+ };
// Process special data.
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
// Process any pointer buffers.
for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
// After we process, make sure we track whether the receive list is broken.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (offset > dst_recv_list_idx) {
recv_list_broken = true;
}
- });
+ };
R_TRY(ProcessReceiveMessagePointerDescriptors(
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
// Process any map alias buffers.
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
// After we process, make sure we track whether the receive list is broken.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (offset > dst_recv_list_idx) {
recv_list_broken = true;
}
- });
+ };
// We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
const KMemoryPermission perm = (i >= src_header.GetSendCount())
@@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
// Process any raw data.
if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
// After we process, make sure we track whether the receive list is broken.
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (offset + raw_count > dst_recv_list_idx) {
recv_list_broken = true;
}
- });
+ };
// Get the offset and size.
const size_t offset_words = offset * sizeof(u32);
@@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
client_thread->Open();
}
- SCOPE_EXIT({ client_thread->Close(); });
+ SCOPE_EXIT {
+ client_thread->Close();
+ };
// Set the request as our current.
m_current_request = request;
@@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
// Reply to the client.
{
// After we reply, close our reference to the request.
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// Get the event to check whether the request is async.
if (KEvent* event = request->GetEvent(); event != nullptr) {
@@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
}
// Close reference to the request once we're done processing it.
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// Extract relevant information from the request.
const uint64_t client_message = request->GetAddress();
@@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() {
}
// Close a reference to the request once it's cleaned up.
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// Extract relevant information from the request.
const uint64_t client_message = request->GetAddress();
@@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() {
ASSERT(thread != nullptr);
// Ensure that we close the request when done.
- SCOPE_EXIT({ request->Close(); });
+ SCOPE_EXIT {
+ request->Close();
+ };
// If we're terminating, close a reference to the thread and event.
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) {
// Allocate a new page.
KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
- auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); });
+ auto page_buf_guard = SCOPE_GUARD {
+ KPageBuffer::Free(kernel, page_buf);
+ };
// Map the address in.
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,
// Construct the page group, guarding to make sure our state is valid on exit.
m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
- auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); });
+ auto pg_guard = SCOPE_GUARD {
+ m_page_group.reset();
+ };
// Lock the memory.
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 {
void Shutdown() {
is_shutting_down.store(true, std::memory_order_relaxed);
- SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); });
+ SCOPE_EXIT {
+ is_shutting_down.store(false, std::memory_order_relaxed);
+ };
CloseServices();
@@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
// Ensure that we don't hold onto any extra references.
- SCOPE_EXIT({ process->Close(); });
+ SCOPE_EXIT {
+ process->Close();
+ };
// Register the new process.
KProcess::Register(*this, process);
@@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
// Ensure that we don't hold onto any extra references.
- SCOPE_EXIT({ process->Close(); });
+ SCOPE_EXIT {
+ process->Close();
+ };
// Register the new process.
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
KCodeMemory* code_mem = KCodeMemory::Create(kernel);
R_UNLESS(code_mem != nullptr, ResultOutOfResource);
- SCOPE_EXIT({ code_mem->Close(); });
+ SCOPE_EXIT {
+ code_mem->Close();
+ };
// Verify that the region is in range.
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_
// Create the device address space.
KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
R_UNLESS(das != nullptr, ResultOutOfResource);
- SCOPE_EXIT({ das->Close(); });
+ SCOPE_EXIT {
+ das->Close();
+ };
// Initialize the device address space.
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) {
event_reservation.Commit();
// Ensure that we clean up the event (and its only references are handle table) on function end.
- SCOPE_EXIT({
+ SCOPE_EXIT {
event->GetReadableEvent().Close();
event->Close();
- });
+ };
// Register the event.
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
}
// Ensure handles are closed when we're done.
- SCOPE_EXIT({
+ SCOPE_EXIT {
for (auto i = 0; i < num_handles; ++i) {
objs[i]->Close();
}
- });
+ };
R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
num_handles, reply_target, timeout_ns));
@@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
event_reservation.Commit();
// At end of scope, kill the standing references to the sub events.
- SCOPE_EXIT({
+ SCOPE_EXIT {
event->GetReadableEvent().Close();
event->Close();
- });
+ };
// Register the event.
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,
port->Initialize(max_sessions, is_light, name);
// Ensure that we clean up the port (and its only references are handle table) on function end.
- SCOPE_EXIT({
+ SCOPE_EXIT {
port->GetServerPort().Close();
port->GetClientPort().Close();
- });
+ };
// Register the port.
KPort::Register(kernel, port);
@@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t
KPort::Register(system.Kernel(), port);
// Ensure that our only reference to the port is in the handle table when we're done.
- SCOPE_EXIT({
+ SCOPE_EXIT {
port->GetClientPort().Close();
port->GetServerPort().Close();
- });
+ };
// Register the handle in the table.
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) {
R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
// Ensure we don't leak a reference to the limit.
- SCOPE_EXIT({ resource_limit->Close(); });
+ SCOPE_EXIT {
+ resource_limit->Close();
+ };
// Initialize the resource limit.
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
// Ensure that we clean up the session (and its only references are handle table) on function
// end.
- SCOPE_EXIT({
+ SCOPE_EXIT {
session->GetClientSession().Close();
session->GetServerSession().Close();
- });
+ };
// Register the session.
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
}
// Ensure handles are closed when we're done.
- SCOPE_EXIT({
+ SCOPE_EXIT {
for (auto i = 0; i < num_handles; ++i) {
objs[i]->Close();
}
- });
+ };
// Convert the timeout from nanoseconds to ticks.
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
// Create the thread.
KThread* thread = KThread::Create(kernel);
R_UNLESS(thread != nullptr, ResultOutOfResource)
- SCOPE_EXIT({ thread->Close(); });
+ SCOPE_EXIT {
+ thread->Close();
+ };
// Initialize the thread.
{
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
R_UNLESS(trmem != nullptr, ResultOutOfResource);
// Ensure the only reference is in the handle table when we're done.
- SCOPE_EXIT({ trmem->Close(); });
+ SCOPE_EXIT {
+ trmem->Close();
+ };
// Ensure that the region is in range.
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) {
Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
std::scoped_lock lk{m_lock};
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (m_data.empty()) {
m_event.Clear();
}
- });
+ };
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
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
Kernel::KProcess::Register(m_system.Kernel(), process);
// On exit, ensure we free the additional reference to the process.
- SCOPE_EXIT({ process->Close(); });
+ SCOPE_EXIT {
+ process->Close();
+ };
// Insert process modules into memory.
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
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
- attribute.title_id = m_applet->program_id;
+ attribute.program_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
- attribute.type = FileSys::SaveDataType::SaveData;
+ attribute.type = FileSys::SaveDataType::Account;
FileSys::VirtualDir save_data{};
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
- &save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
+ &save_data, FileSys::SaveDataSpaceId::User, attribute));
*out_size = 0;
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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "audio_core/in/audio_in_system.h"
-#include "audio_core/renderer/audio_device.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/audio/audin_u.h"
-#include "core/hle/service/ipc_helpers.h"
-
-namespace Service::Audio {
-using namespace AudioCore::AudioIn;
-
-class IAudioIn final : public ServiceFramework<IAudioIn> {
-public:
- explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
- const std::string& device_name, const AudioInParameter& in_params,
- Kernel::KProcess* handle, u64 applet_resource_user_id)
- : ServiceFramework{system_, "IAudioIn"},
- service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
- process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
- {1, &IAudioIn::Start, "Start"},
- {2, &IAudioIn::Stop, "Stop"},
- {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
- {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
- {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
- {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
- {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
- {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
- {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
- {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
- {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
- {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
- {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-
- process->Open();
-
- if (impl->GetSystem()
- .Initialize(device_name, in_params, handle, applet_resource_user_id)
- .IsError()) {
- LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
- }
- }
-
- ~IAudioIn() override {
- impl->Free();
- service_context.CloseEvent(event);
- process->Close();
- }
-
- [[nodiscard]] std::shared_ptr<In> GetImpl() {
- return impl;
- }
-
-private:
- void GetAudioInState(HLERequestContext& ctx) {
- const auto state = static_cast<u32>(impl->GetState());
-
- LOG_DEBUG(Service_Audio, "called. State={}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StartSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StopSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void AppendAudioInBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- u64 tag = rp.PopRaw<u64>();
-
- const auto in_buffer_size{ctx.GetReadBufferSize()};
- if (in_buffer_size < sizeof(AudioInBuffer)) {
- LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
- }
-
- const auto& in_buffer = ctx.ReadBuffer();
- AudioInBuffer buffer{};
- std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
-
- [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
- LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
-
- auto result = impl->AppendBuffer(buffer, tag);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void RegisterBufferEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& buffer_event = impl->GetBufferEvent();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(buffer_event);
- }
-
- void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
- const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- released_buffer.resize_destructive(write_buffer_size);
- released_buffer[0] = 0;
-
- const auto count = impl->GetReleasedBuffers(released_buffer);
-
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
- impl->GetSystem().GetSessionId(), count);
-
- ctx.WriteBuffer(released_buffer);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ContainsAudioInBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const u64 tag{rp.Pop<u64>()};
- const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
-
- LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_queued);
- }
-
- void GetAudioInBufferCount(HLERequestContext& ctx) {
- const auto buffer_count = impl->GetBufferCount();
-
- LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void SetDeviceGain(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto volume{rp.Pop<f32>()};
- LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
-
- impl->SetVolume(volume);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetDeviceGain(HLERequestContext& ctx) {
- auto volume{impl->GetVolume()};
-
- LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- void FlushAudioInBuffers(HLERequestContext& ctx) {
- bool flushed{impl->FlushAudioInBuffers()};
-
- LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flushed);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* event;
- Kernel::KProcess* process;
- std::shared_ptr<AudioCore::AudioIn::In> impl;
- Common::ScratchBuffer<u64> released_buffer;
-};
-
-AudInU::AudInU(Core::System& system_)
- : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
- impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudInU::ListAudioIns, "ListAudioIns"},
- {1, &AudInU::OpenAudioIn, "OpenAudioIn"},
- {2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
- {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
- {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
- {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudInU::~AudInU() = default;
-
-void AudInU::ListAudioIns(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- LOG_DEBUG(Service_Audio, "called");
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
-
- u32 out_count{0};
- if (write_count > 0) {
- out_count = impl->GetDeviceNames(device_names, write_count, false);
- ctx.WriteBuffer(device_names);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(out_count);
-}
-
-void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- LOG_DEBUG(Service_Audio, "called");
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
-
- u32 out_count{0};
- if (write_count > 0) {
- out_count = impl->GetDeviceNames(device_names, write_count, true);
- ctx.WriteBuffer(device_names);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(out_count);
-}
-
-void AudInU::OpenAudioIn(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto in_params{rp.PopRaw<AudioInParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- std::scoped_lock l{impl->mutex};
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_in =
- std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- impl->sessions[new_session_id] = audio_in->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- std::string out_name{out_system.GetName()};
- ctx.WriteBuffer(out_name);
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioInParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioIn>(audio_in);
-}
-
-void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto protocol_specified{rp.PopRaw<u64>()};
- auto in_params{rp.PopRaw<AudioInParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- std::scoped_lock l{impl->mutex};
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_in =
- std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- impl->sessions[new_session_id] = audio_in->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- std::string out_name{out_system.GetName()};
- if (protocol_specified == 0) {
- if (out_system.IsUac()) {
- out_name = "UacIn";
- } else {
- out_name = "DeviceIn";
- }
- }
-
- ctx.WriteBuffer(out_name);
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioInParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioIn>(audio_in);
-}
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_in_manager.h"
-#include "audio_core/in/audio_in.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace AudioCore::AudioOut {
-class Manager;
-class In;
-} // namespace AudioCore::AudioOut
-
-namespace Service::Audio {
-
-class AudInU final : public ServiceFramework<AudInU> {
-public:
- explicit AudInU(Core::System& system_);
- ~AudInU() override;
-
-private:
- void ListAudioIns(HLERequestContext& ctx);
- void ListAudioInsAutoFiltered(HLERequestContext& ctx);
- void OpenInOutImpl(HLERequestContext& ctx);
- void OpenAudioIn(HLERequestContext& ctx);
- void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::AudioIn::Manager> impl;
-};
-
-} // 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 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
-#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/audio/audio_controller.h"
-#include "core/hle/service/audio/audout_u.h"
-#include "core/hle/service/audio/audrec_a.h"
-#include "core/hle/service/audio/audrec_u.h"
-#include "core/hle/service/audio/audren_u.h"
-#include "core/hle/service/audio/hwopus.h"
+#include "core/hle/service/audio/audio_in_manager.h"
+#include "core/hle/service/audio/audio_out_manager.h"
+#include "core/hle/service/audio/audio_renderer_manager.h"
+#include "core/hle/service/audio/final_output_recorder_manager.h"
+#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
+#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
@@ -19,12 +19,16 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
- server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
- server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
- server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));
- server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system));
- server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system));
- server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system));
+ server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
+ server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
+ server_manager->RegisterNamedService(
+ "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
+ server_manager->RegisterNamedService("audrec:u",
+ std::make_shared<IFinalOutputRecorderManager>(system));
+ server_manager->RegisterNamedService("audren:u",
+ std::make_shared<IAudioRendererManager>(system));
+ server_manager->RegisterNamedService("hwopus",
+ std::make_shared<IHardwareOpusDecoderManager>(system));
ServerManager::RunServer(std::move(server_manager));
}
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_)
static const FunctionInfo functions[] = {
{0, nullptr, "GetTargetVolume"},
{1, nullptr, "SetTargetVolume"},
- {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
- {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
+ {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
+ {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
{4, nullptr, "IsTargetMute"},
{5, nullptr, "SetTargetMute"},
{6, nullptr, "IsTargetConnected"},
{7, nullptr, "SetDefaultTarget"},
{8, nullptr, "GetDefaultTarget"},
- {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
- {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
+ {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
+ {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
{11, nullptr, "SetForceMutePolicy"},
- {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
- {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
- {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
+ {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
+ {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
+ {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
{15, nullptr, "SetOutputTarget"},
{16, nullptr, "SetInputTargetForceEnabled"},
- {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
- {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
+ {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
+ {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
{19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
{20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
{21, nullptr, "GetAudioOutputTargetForPlayReport"},
- {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
+ {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
{23, nullptr, "SetSystemOutputMasterVolume"},
{24, nullptr, "GetSystemOutputMasterVolume"},
{25, nullptr, "GetAudioVolumeDataForPlayReport"},
@@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
{27, nullptr, "SetVolumeMappingTableForDev"},
{28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
- {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
- {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
+ {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
+ {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
{32, nullptr, "GetActiveOutputTarget"},
{33, nullptr, "GetTargetDeviceInfo"},
- {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
+ {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
{35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
{37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@@ -138,7 +138,7 @@ Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target,
}
Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) {
- LOG_WARNING(Audio, "(STUBBED) called");
+ LOG_WARNING(Audio, "(STUBBED) called, output_level_mode={}", output_level_mode);
R_SUCCEED();
}
@@ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
R_SUCCEED();
}
+Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+ R_SUCCEED();
+}
+
Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
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:
Set::AudioOutputMode output_mode);
Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
+ Result NotifyHeadphoneVolumeWarningDisplayedEvent();
Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/audio_core.h"
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_device.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::Renderer;
+
+IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
+ u32 device_num)
+ : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
+ impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
+ event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
+ {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
+ {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
+ {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
+ {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
+ {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
+ {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
+ {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
+ {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
+ {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
+ {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
+ {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
+ {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
+ {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
+ };
+ RegisterHandlers(functions);
+
+ event->Signal();
+}
+
+IAudioDevice::~IAudioDevice() {
+ service_context.CloseEvent(event);
+}
+
+Result IAudioDevice::ListAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
+ R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
+}
+
+Result IAudioDevice::SetAudioDeviceOutputVolume(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
+ R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
+}
+
+Result IAudioDevice::GetAudioDeviceOutputVolume(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
+ R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
+}
+
+Result IAudioDevice::GetActiveAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
+ R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
+}
+
+Result IAudioDevice::ListAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
+ Out<s32> out_count) {
+ *out_count = impl->ListAudioDeviceName(out_names);
+
+ std::string out{};
+ for (s32 i = 0; i < *out_count; i++) {
+ std::string a{};
+ u32 j = 0;
+ while (out_names[i].name[j] != '\0') {
+ a += out_names[i].name[j];
+ j++;
+ }
+ out += "\n\t" + a;
+ }
+
+ LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
+ R_SUCCEED();
+}
+
+Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
+ R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
+
+ const std::string device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
+
+ if (device_name == "AudioTvOutput") {
+ impl->SetDeviceVolumes(volume);
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
+ R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
+
+ const std::string device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
+
+ *out_volume = 1.0f;
+ if (device_name == "AudioTvOutput") {
+ *out_volume = impl->GetDeviceVolume(device_name);
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetActiveAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
+ R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
+ out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ event->Signal();
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "(STUBBED) called");
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
+ *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
+ LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
+ R_SUCCEED();
+}
+
+Result IAudioDevice::ListAudioOutputDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
+ *out_count = impl->ListAudioOutputDeviceName(out_names);
+
+ std::string out{};
+ for (s32 i = 0; i < *out_count; i++) {
+ std::string a{};
+ u32 j = 0;
+ while (out_names[i].name[j] != '\0') {
+ a += out_names[i].name[j];
+ j++;
+ }
+ out += "\n\t" + a;
+ }
+
+ LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/renderer/audio_device.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+using AudioCore::Renderer::AudioDevice;
+
+class IAudioDevice final : public ServiceFramework<IAudioDevice> {
+
+public:
+ explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
+ u32 device_num);
+ ~IAudioDevice() override;
+
+private:
+ Result ListAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
+ Out<s32> out_count);
+ Result SetAudioDeviceOutputVolume(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume);
+ Result GetAudioDeviceOutputVolume(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name);
+ Result GetActiveAudioDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name);
+ Result ListAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
+ Out<s32> out_count);
+ Result SetAudioDeviceOutputVolumeAuto(
+ InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume);
+ Result GetAudioDeviceOutputVolumeAuto(
+ Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name);
+ Result GetActiveAudioDeviceNameAuto(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name);
+ Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetActiveChannelCount(Out<u32> out_active_channel_count);
+ Result ListAudioOutputDeviceName(
+ OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
+ Out<s32> out_count);
+
+ KernelHelpers::ServiceContext service_context;
+ std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
+ Kernel::KEvent* event;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/audio_in.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioIn;
+
+IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
+ const std::string& device_name, const AudioInParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id)
+ : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
+ event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
+ manager, event,
+ session_id)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"},
+ {1, D<&IAudioIn::Start>, "Start"},
+ {2, D<&IAudioIn::Stop>, "Stop"},
+ {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"},
+ {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"},
+ {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"},
+ {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"},
+ {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"},
+ {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"},
+ {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"},
+ {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"},
+ {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"},
+ {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"},
+ {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"},
+ {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+
+ process->Open();
+
+ if (impl->GetSystem()
+ .Initialize(device_name, in_params, handle, applet_resource_user_id)
+ .IsError()) {
+ LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
+ }
+}
+
+IAudioIn::~IAudioIn() {
+ impl->Free();
+ service_context.CloseEvent(event);
+ process->Close();
+}
+
+Result IAudioIn::GetAudioInState(Out<u32> out_state) {
+ *out_state = static_cast<u32>(impl->GetState());
+ LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioIn::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StartSystem());
+}
+
+Result IAudioIn::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StopSystem());
+}
+
+Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
+ u64 buffer_client_ptr) {
+ R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
+}
+
+Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
+ u64 buffer_client_ptr) {
+ if (buffer.empty()) {
+ LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
+ R_THROW(Audio::ResultInsufficientBuffer);
+ }
+
+ [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()};
+ LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id,
+ buffer_client_ptr);
+
+ R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr));
+}
+
+Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &impl->GetBufferEvent();
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count) {
+ R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count));
+}
+
+Result IAudioIn::GetReleasedAudioInBuffersAuto(
+ OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
+
+ if (!out_audio_buffer.empty()) {
+ out_audio_buffer[0] = 0;
+ }
+ *out_count = impl->GetReleasedBuffers(out_audio_buffer);
+
+ LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
+ impl->GetSystem().GetSessionId(), *out_count);
+ R_SUCCEED();
+}
+
+Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
+ *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
+
+ LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
+ *out_contains_buffer);
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) {
+ *out_buffer_count = impl->GetBufferCount();
+ LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
+ R_SUCCEED();
+}
+
+Result IAudioIn::SetDeviceGain(f32 device_gain) {
+ impl->SetVolume(device_gain);
+ LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain);
+ R_SUCCEED();
+}
+
+Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) {
+ *out_device_gain = impl->GetVolume();
+ LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain);
+ R_SUCCEED();
+}
+
+Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) {
+ *out_flushed = impl->FlushAudioInBuffers();
+ LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/in/audio_in.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IAudioIn final : public ServiceFramework<IAudioIn> {
+public:
+ explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager,
+ size_t session_id, const std::string& device_name,
+ const AudioCore::AudioIn::AudioInParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id);
+ ~IAudioIn() override;
+
+ std::shared_ptr<AudioCore::AudioIn::In> GetImpl() {
+ return impl;
+ }
+
+ Result GetAudioInState(Out<u32> out_state);
+ Result Start();
+ Result Stop();
+ Result AppendAudioInBuffer(
+ InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
+ u64 buffer_client_ptr);
+ Result AppendAudioInBufferAuto(
+ InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
+ u64 buffer_client_ptr);
+ Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count);
+ Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
+ Out<u32> out_count);
+ Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
+ Result GetAudioInBufferCount(Out<u32> out_buffer_count);
+ Result SetDeviceGain(f32 device_gain);
+ Result GetDeviceGain(Out<f32> out_device_gain);
+ Result FlushAudioInBuffers(Out<bool> out_flushed);
+
+private:
+ Kernel::KProcess* process;
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* event;
+ std::shared_ptr<AudioCore::AudioIn::In> impl;
+ Common::ScratchBuffer<u64> released_buffer;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_in.h"
+#include "core/hle/service/audio/audio_in_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioIn;
+
+IAudioInManager::IAudioInManager(Core::System& system_)
+ : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
+ system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"},
+ {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"},
+ {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"},
+ {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"},
+ {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"},
+ {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioInManager::~IAudioInManager() = default;
+
+Result IAudioInManager::ListAudioIns(
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
+}
+
+Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
+ name, {}, parameter, process_handle, aruid));
+}
+
+Result IAudioInManager::ListAudioInsAuto(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
+}
+
+Result IAudioInManager::OpenAudioInAuto(
+ Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
+ name, {}, parameter, process_handle, aruid));
+}
+
+Result IAudioInManager::ListAudioInsAutoFiltered(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_count = impl->GetDeviceNames(out_audio_ins, true);
+ R_SUCCEED();
+}
+
+Result IAudioInManager::OpenAudioInProtocolSpecified(
+ Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
+ AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ if (!process_handle) {
+ LOG_ERROR(Service_Audio, "Failed to get process handle");
+ R_THROW(ResultUnknown);
+ }
+ if (name.empty() || out_name.empty()) {
+ LOG_ERROR(Service_Audio, "Invalid buffers");
+ R_THROW(ResultUnknown);
+ }
+
+ std::scoped_lock l{impl->mutex};
+
+ size_t new_session_id{};
+
+ R_TRY(impl->LinkToManager());
+ R_TRY(impl->AcquireSessionId(new_session_id));
+
+ LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
+ impl->num_free_sessions);
+
+ const auto device_name = Common::StringFromBuffer(name[0].name);
+ *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
+ parameter, process_handle.Get(), aruid.pid);
+ impl->sessions[new_session_id] = (*out_audio_in)->GetImpl();
+ impl->applet_resource_user_ids[new_session_id] = aruid.pid;
+
+ auto& out_system = impl->sessions[new_session_id]->GetSystem();
+ *out_parameter_internal =
+ AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
+ .channel_count = out_system.GetChannelCount(),
+ .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
+ .state = static_cast<u32>(out_system.GetState())};
+
+ out_name[0] = AudioDeviceName(out_system.GetName());
+
+ if (protocol == Protocol{}) {
+ if (out_system.IsUac()) {
+ out_name[0] = AudioDeviceName("UacIn");
+ } else {
+ out_name[0] = AudioDeviceName("DeviceIn");
+ }
+ }
+
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_in_manager.h"
+#include "audio_core/in/audio_in_system.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
+using Protocol = std::array<u32, 2>;
+
+class IAudioIn;
+
+class IAudioInManager final : public ServiceFramework<IAudioInManager> {
+public:
+ explicit IAudioInManager(Core::System& system_);
+ ~IAudioInManager() override;
+
+private:
+ Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins,
+ Out<u32> out_count);
+ Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+
+ Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins,
+ Out<u32> out_count);
+ Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+
+ Result ListAudioInsAutoFiltered(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count);
+ Result OpenAudioInProtocolSpecified(
+ Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioIn>> out_audio_in,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
+ AudioCore::AudioIn::AudioInParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::AudioIn::Manager> impl;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/out/audio_out.h"
+#include "audio_core/out/audio_out_system.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/service/audio/audio_out.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioOut;
+
+IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
+ const std::string& device_name, const AudioOutParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id)
+ : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
+ event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
+ impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
+
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"},
+ {1, D<&IAudioOut::Start>, "Start"},
+ {2, D<&IAudioOut::Stop>, "Stop"},
+ {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"},
+ {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"},
+ {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"},
+ {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"},
+ {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"},
+ {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"},
+ {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"},
+ {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"},
+ {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"},
+ {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"},
+ {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ process->Open();
+}
+
+IAudioOut::~IAudioOut() {
+ impl->Free();
+ service_context.CloseEvent(event);
+ process->Close();
+}
+
+Result IAudioOut::GetAudioOutState(Out<u32> out_state) {
+ *out_state = static_cast<u32>(impl->GetState());
+ LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioOut::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StartSystem());
+}
+
+Result IAudioOut::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->StopSystem());
+}
+
+Result IAudioOut::AppendAudioOutBuffer(
+ InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
+ R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
+}
+
+Result IAudioOut::AppendAudioOutBufferAuto(
+ InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
+ if (audio_out_buffer.empty()) {
+ LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
+ R_THROW(Audio::ResultInsufficientBuffer);
+ }
+
+ LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
+ impl->GetSystem().GetSessionId(), buffer_client_ptr);
+ R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr));
+}
+
+Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_event = &impl->GetBufferEvent();
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetReleasedAudioOutBuffers(
+ OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) {
+ R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count));
+}
+
+Result IAudioOut::GetReleasedAudioOutBuffersAuto(
+ OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
+
+ if (!out_audio_buffer.empty()) {
+ out_audio_buffer[0] = 0;
+ }
+ *out_count = impl->GetReleasedBuffers(out_audio_buffer);
+
+ LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
+ impl->GetSystem().GetSessionId(), *out_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
+ *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
+
+ LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
+ *out_contains_buffer);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) {
+ *out_buffer_count = impl->GetBufferCount();
+ LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) {
+ *out_played_sample_count = impl->GetPlayedSampleCount();
+ LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count);
+ R_SUCCEED();
+}
+
+Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) {
+ *out_flushed = impl->FlushAudioOutBuffers();
+ LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
+ R_SUCCEED();
+}
+
+Result IAudioOut::SetAudioOutVolume(f32 volume) {
+ LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
+ impl->SetVolume(volume);
+ R_SUCCEED();
+}
+
+Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) {
+ *out_volume = impl->GetVolume();
+ LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_out_manager.h"
+#include "audio_core/out/audio_out_system.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+class IAudioOut : public ServiceFramework<IAudioOut> {
+public:
+ explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
+ size_t session_id, const std::string& device_name,
+ const AudioCore::AudioOut::AudioOutParameter& in_params,
+ Kernel::KProcess* handle, u64 applet_resource_user_id);
+ ~IAudioOut() override;
+
+ std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
+ return impl;
+ }
+
+ Result GetAudioOutState(Out<u32> out_state);
+ Result Start();
+ Result Stop();
+ Result AppendAudioOutBuffer(
+ InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer,
+ u64 buffer_client_ptr);
+ Result AppendAudioOutBufferAuto(
+ InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer,
+ u64 buffer_client_ptr);
+ Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
+ Out<u32> out_count);
+ Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
+ Out<u32> out_count);
+ Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
+ Result GetAudioOutBufferCount(Out<u32> out_buffer_count);
+ Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count);
+ Result FlushAudioOutBuffers(Out<bool> out_flushed);
+ Result SetAudioOutVolume(f32 volume);
+ Result GetAudioOutVolume(Out<f32> out_volume);
+
+private:
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* event;
+ Kernel::KProcess* process;
+ std::shared_ptr<AudioCore::AudioOut::Out> impl;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/hle/service/audio/audio_out.h"
+#include "core/hle/service/audio/audio_out_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/memory.h"
+
+namespace Service::Audio {
+using namespace AudioCore::AudioOut;
+
+IAudioOutManager::IAudioOutManager(Core::System& system_)
+ : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
+ {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"},
+ {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"},
+ {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioOutManager::~IAudioOutManager() = default;
+
+Result IAudioOutManager::ListAudioOuts(
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) {
+ R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
+}
+
+Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid) {
+ R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
+ parameter, process_handle, aruid));
+}
+
+Result IAudioOutManager::ListAudioOutsAuto(
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) {
+ if (!out_audio_outs.empty()) {
+ out_audio_outs[0] = AudioDeviceName("DeviceOut");
+ *out_count = 1;
+ LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
+ } else {
+ *out_count = 0;
+ LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
+ }
+
+ R_SUCCEED();
+}
+
+Result IAudioOutManager::OpenAudioOutAuto(
+ Out<AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ if (!process_handle) {
+ LOG_ERROR(Service_Audio, "Failed to get process handle");
+ R_THROW(ResultUnknown);
+ }
+ if (name.empty() || out_name.empty()) {
+ LOG_ERROR(Service_Audio, "Invalid buffers");
+ R_THROW(ResultUnknown);
+ }
+
+ size_t new_session_id{};
+ R_TRY(impl->LinkToManager());
+ R_TRY(impl->AcquireSessionId(new_session_id));
+
+ const auto device_name = Common::StringFromBuffer(name[0].name);
+ LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
+ impl->num_free_sessions);
+
+ auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
+ parameter, process_handle.Get(), aruid.pid);
+ R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(),
+ aruid.pid));
+
+ *out_audio_out = audio_out;
+ impl->sessions[new_session_id] = audio_out->GetImpl();
+ impl->applet_resource_user_ids[new_session_id] = aruid.pid;
+
+ auto& out_system = impl->sessions[new_session_id]->GetSystem();
+ *out_parameter_internal =
+ AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
+ .channel_count = out_system.GetChannelCount(),
+ .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
+ .state = static_cast<u32>(out_system.GetState())};
+
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_out_manager.h"
+#include "audio_core/out/audio_out.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
+class IAudioOut;
+
+class IAudioOutManager final : public ServiceFramework<IAudioOutManager> {
+public:
+ explicit IAudioOutManager(Core::System& system_);
+ ~IAudioOutManager() override;
+
+private:
+ Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs,
+ Out<u32> out_count);
+ Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
+ AudioCore::AudioOut::AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+ Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs,
+ Out<u32> out_count);
+ Result OpenAudioOutAuto(
+ Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
+ Out<SharedPointer<IAudioOut>> out_audio_out,
+ OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
+ InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
+ AudioCore::AudioOut::AudioOutParameter parameter,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::AudioOut::Manager> impl;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/audio_renderer.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+using namespace AudioCore::Renderer;
+
+IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
+ AudioCore::AudioRendererParameterInternal& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
+ Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
+ s32 session_id)
+ : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
+ rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
+ impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
+ process_handle_} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
+ {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"},
+ {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"},
+ {3, D<&IAudioRenderer::GetState>, "GetState"},
+ {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"},
+ {5, D<&IAudioRenderer::Start>, "Start"},
+ {6, D<&IAudioRenderer::Stop>, "Stop"},
+ {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"},
+ {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"},
+ {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"},
+ {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"},
+ {11, nullptr, "ExecuteAudioRendererRendering"},
+ {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"},
+ {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ process_handle->Open();
+ impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle,
+ applet_resource_user_id, session_id);
+}
+
+IAudioRenderer::~IAudioRenderer() {
+ impl->Finalize();
+ service_context.CloseEvent(rendered_event);
+ process_handle->Close();
+}
+
+Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) {
+ *out_sample_rate = impl->GetSystem().GetSampleRate();
+ LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) {
+ *out_sample_count = impl->GetSystem().GetSampleCount();
+ LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetState(Out<u32> out_state) {
+ *out_state = !impl->GetSystem().IsActive();
+ LOG_DEBUG(Service_Audio, "called, state {}", *out_state);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
+ InBuffer<BufferAttr_HipcMapAlias> input) {
+ R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input));
+}
+
+Result IAudioRenderer::RequestUpdateAuto(
+ OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
+ OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
+ InBuffer<BufferAttr_HipcAutoSelect> input) {
+ LOG_TRACE(Service_Audio, "called");
+
+ const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer);
+ if (result.IsFailure()) {
+ LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
+ }
+
+ R_RETURN(result);
+}
+
+Result IAudioRenderer::Start() {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->Start();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::Stop() {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->Stop();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual,
+ Audio::ResultNotSupported);
+ *out_event = &rendered_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit);
+ ;
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit();
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) {
+ LOG_DEBUG(Service_Audio, "called");
+ impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter);
+ R_SUCCEED();
+}
+
+Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) {
+ LOG_DEBUG(Service_Audio, "called");
+ *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter();
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/renderer/audio_renderer.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::Audio {
+
+class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
+public:
+ explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
+ AudioCore::AudioRendererParameterInternal& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
+ Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
+ s32 session_id);
+ ~IAudioRenderer() override;
+
+private:
+ Result GetSampleRate(Out<u32> out_sample_rate);
+ Result GetSampleCount(Out<u32> out_sample_count);
+ Result GetState(Out<u32> out_state);
+ Result GetMixBufferCount(Out<u32> out_mix_buffer_count);
+ Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
+ InBuffer<BufferAttr_HipcMapAlias> input);
+ Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
+ OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
+ InBuffer<BufferAttr_HipcAutoSelect> input);
+ Result Start();
+ Result Stop();
+ Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result SetRenderingTimeLimit(u32 rendering_time_limit);
+ Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit);
+ Result SetVoiceDropParameter(f32 voice_drop_parameter);
+ Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter);
+
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* rendered_event;
+ AudioCore::Renderer::Manager& manager;
+ std::unique_ptr<AudioCore::Renderer::Renderer> impl;
+ Kernel::KProcess* process_handle;
+ Common::ScratchBuffer<u8> output_buffer;
+ Common::ScratchBuffer<u8> performance_buffer;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "audio_core/audio_render_manager.h"
+#include "audio_core/common/feature_support.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/service/audio/audio_device.h"
+#include "core/hle/service/audio/audio_renderer.h"
+#include "core/hle/service/audio/audio_renderer_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::Renderer;
+
+IAudioRendererManager::IAudioRendererManager(Core::System& system_)
+ : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
+ {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"},
+ {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"},
+ {3, nullptr, "OpenAudioRendererForManualExecution"},
+ {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IAudioRendererManager::~IAudioRendererManager() = default;
+
+Result IAudioRendererManager::OpenAudioRenderer(
+ Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
+ AudioCore::AudioRendererParameterInternal parameter,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
+ InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
+ LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
+ R_THROW(Audio::ResultOutOfSessions);
+ }
+
+ const auto session_id{impl->GetSessionId()};
+ if (session_id == -1) {
+ LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
+ R_THROW(Audio::ResultOutOfSessions);
+ }
+
+ LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
+ impl->GetSessionCount());
+
+ *out_audio_renderer =
+ std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size,
+ process_handle.Get(), aruid.pid, session_id);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size,
+ AudioCore::AudioRendererParameterInternal params) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ R_TRY(impl->GetWorkBufferSize(params, *out_size))
+
+ std::string output_info{};
+ output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
+ output_info +=
+ fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
+ output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
+ static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
+ output_info += fmt::format(
+ "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
+ "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
+ "Context {:04X}",
+ params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
+ params.splitter_destinations, params.voices, params.perf_frames,
+ params.external_context_size);
+
+ LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
+ output_info, *out_size);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetAudioDeviceService(
+ Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid);
+ *out_audio_device = std::make_shared<IAudioDevice>(
+ system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
+ R_SUCCEED();
+}
+
+Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(
+ Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision,
+ ClientAppletResourceUserId aruid) {
+ LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision),
+ aruid.pid);
+ *out_audio_device =
+ std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/audio_render_manager.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IAudioDevice;
+class IAudioRenderer;
+
+class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
+public:
+ explicit IAudioRendererManager(Core::System& system_);
+ ~IAudioRendererManager() override;
+
+private:
+ Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
+ AudioCore::AudioRendererParameterInternal parameter,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
+ InCopyHandle<Kernel::KProcess> process_handle,
+ ClientAppletResourceUserId aruid);
+ Result GetWorkBufferSize(Out<u64> out_size,
+ AudioCore::AudioRendererParameterInternal parameter);
+ Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device,
+ ClientAppletResourceUserId aruid);
+ Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
+ u32 revision, ClientAppletResourceUserId aruid);
+
+ std::unique_ptr<AudioCore::Renderer::Manager> impl;
+ u32 num_audio_devices{0};
+};
+
+} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <array>
-#include <cstring>
-#include <vector>
-
-#include "audio_core/out/audio_out_system.h"
-#include "audio_core/renderer/audio_device.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "common/swap.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/audio/audout_u.h"
-#include "core/hle/service/audio/errors.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/memory.h"
-
-namespace Service::Audio {
-using namespace AudioCore::AudioOut;
-
-class IAudioOut final : public ServiceFramework<IAudioOut> {
-public:
- explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
- size_t session_id, const std::string& device_name,
- const AudioOutParameter& in_params, Kernel::KProcess* handle,
- u64 applet_resource_user_id)
- : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
- event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
- impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
-
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
- {1, &IAudioOut::Start, "Start"},
- {2, &IAudioOut::Stop, "Stop"},
- {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
- {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
- {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"},
- {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
- {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"},
- {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"},
- {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
- {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
- {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
- {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
- {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- process->Open();
- }
-
- ~IAudioOut() override {
- impl->Free();
- service_context.CloseEvent(event);
- process->Close();
- }
-
- [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
- return impl;
- }
-
-private:
- void GetAudioOutState(HLERequestContext& ctx) {
- const auto state = static_cast<u32>(impl->GetState());
-
- LOG_DEBUG(Service_Audio, "called. State={}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StartSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto result = impl->StopSystem();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void AppendAudioOutBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- u64 tag = rp.PopRaw<u64>();
-
- const auto in_buffer_size{ctx.GetReadBufferSize()};
- if (in_buffer_size < sizeof(AudioOutBuffer)) {
- LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
- }
-
- const auto& in_buffer = ctx.ReadBuffer();
- AudioOutBuffer buffer{};
- std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
-
- LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
- impl->GetSystem().GetSessionId(), tag);
-
- auto result = impl->AppendBuffer(buffer, tag);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void RegisterBufferEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& buffer_event = impl->GetBufferEvent();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(buffer_event);
- }
-
- void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
- const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- released_buffer.resize_destructive(write_buffer_size);
- released_buffer[0] = 0;
-
- const auto count = impl->GetReleasedBuffers(released_buffer);
-
- ctx.WriteBuffer(released_buffer);
-
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
- impl->GetSystem().GetSessionId(), count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ContainsAudioOutBuffer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const u64 tag{rp.Pop<u64>()};
- const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
-
- LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_queued);
- }
-
- void GetAudioOutBufferCount(HLERequestContext& ctx) {
- const auto buffer_count = impl->GetBufferCount();
-
- LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
- const auto samples_played = impl->GetPlayedSampleCount();
-
- LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(samples_played);
- }
-
- void FlushAudioOutBuffers(HLERequestContext& ctx) {
- bool flushed{impl->FlushAudioOutBuffers()};
-
- LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flushed);
- }
-
- void SetAudioOutVolume(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto volume = rp.Pop<f32>();
-
- LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
-
- impl->SetVolume(volume);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetAudioOutVolume(HLERequestContext& ctx) {
- const auto volume = impl->GetVolume();
-
- LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* event;
- Kernel::KProcess* process;
- std::shared_ptr<AudioCore::AudioOut::Out> impl;
- Common::ScratchBuffer<u64> released_buffer;
-};
-
-AudOutU::AudOutU(Core::System& system_)
- : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
- impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
- {1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
- {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"},
- {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudOutU::~AudOutU() = default;
-
-void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
- using namespace AudioCore::Renderer;
-
- std::scoped_lock l{impl->mutex};
-
- const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
- std::vector<AudioDevice::AudioDeviceName> device_names{};
- if (write_count > 0) {
- device_names.emplace_back("DeviceOut");
- LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
- } else {
- LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
- }
-
- ctx.WriteBuffer(device_names);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(device_names.size()));
-}
-
-void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto in_params{rp.PopRaw<AudioOutParameter>()};
- auto applet_resource_user_id{rp.PopRaw<u64>()};
- const auto device_name_data{ctx.ReadBuffer()};
- auto device_name = Common::StringFromBuffer(device_name_data);
- auto handle{ctx.GetCopyHandle(0)};
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
- if (process.IsNull()) {
- LOG_ERROR(Service_Audio, "Failed to get process handle");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- auto link{impl->LinkToManager()};
- if (link.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(link);
- return;
- }
-
- size_t new_session_id{};
- auto result{impl->AcquireSessionId(new_session_id)};
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
- impl->num_free_sessions);
-
- auto audio_out =
- std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params,
- process.GetPointerUnsafe(), applet_resource_user_id);
- result = audio_out->GetImpl()->GetSystem().Initialize(
- device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
- if (result.IsError()) {
- LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- impl->sessions[new_session_id] = audio_out->GetImpl();
- impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
-
- auto& out_system = impl->sessions[new_session_id]->GetSystem();
- AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
- .channel_count = out_system.GetChannelCount(),
- .sample_format =
- static_cast<u32>(out_system.GetSampleFormat()),
- .state = static_cast<u32>(out_system.GetState())};
-
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
-
- ctx.WriteBuffer(out_system.GetName());
-
- rb.Push(ResultSuccess);
- rb.PushRaw<AudioOutParameterInternal>(out_params);
- rb.PushIpcInterface<IAudioOut>(audio_out);
-}
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_out_manager.h"
-#include "audio_core/out/audio_out.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace AudioCore::AudioOut {
-class Manager;
-class Out;
-} // namespace AudioCore::AudioOut
-
-namespace Service::Audio {
-
-class IAudioOut;
-
-class AudOutU final : public ServiceFramework<AudOutU> {
-public:
- explicit AudOutU(Core::System& system_);
- ~AudOutU() override;
-
-private:
- void ListAudioOuts(HLERequestContext& ctx);
- void OpenAudioOut(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::AudioOut::Manager> impl;
-};
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <array>
-#include <memory>
-
-#include "audio_core/audio_core.h"
-#include "audio_core/common/audio_renderer_parameter.h"
-#include "audio_core/common/feature_support.h"
-#include "audio_core/renderer/audio_device.h"
-#include "audio_core/renderer/audio_renderer.h"
-#include "audio_core/renderer/voice/voice_info.h"
-#include "common/alignment.h"
-#include "common/bit_util.h"
-#include "common/common_funcs.h"
-#include "common/logging/log.h"
-#include "common/polyfill_ranges.h"
-#include "common/scratch_buffer.h"
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_transfer_memory.h"
-#include "core/hle/service/audio/audren_u.h"
-#include "core/hle/service/audio/errors.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/memory.h"
-
-using namespace AudioCore::Renderer;
-
-namespace Service::Audio {
-
-class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
-public:
- explicit IAudioRenderer(Core::System& system_, Manager& manager_,
- AudioCore::AudioRendererParameterInternal& params,
- Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
- u32 process_handle, Kernel::KProcess& process_,
- u64 applet_resource_user_id, s32 session_id)
- : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
- rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
- impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
- {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
- {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
- {3, &IAudioRenderer::GetState, "GetState"},
- {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
- {5, &IAudioRenderer::Start, "Start"},
- {6, &IAudioRenderer::Stop, "Stop"},
- {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
- {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
- {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
- {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
- {11, nullptr, "ExecuteAudioRendererRendering"},
- {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
- {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- process.Open();
- impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
- applet_resource_user_id, session_id);
- }
-
- ~IAudioRenderer() override {
- impl->Finalize();
- service_context.CloseEvent(rendered_event);
- process.Close();
- }
-
-private:
- void GetSampleRate(HLERequestContext& ctx) {
- const auto sample_rate{impl->GetSystem().GetSampleRate()};
-
- LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(sample_rate);
- }
-
- void GetSampleCount(HLERequestContext& ctx) {
- const auto sample_count{impl->GetSystem().GetSampleCount()};
-
- LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(sample_count);
- }
-
- void GetState(HLERequestContext& ctx) {
- const u32 state{!impl->GetSystem().IsActive()};
-
- LOG_DEBUG(Service_Audio, "called, state {}", state);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state);
- }
-
- void GetMixBufferCount(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(buffer_count);
- }
-
- void RequestUpdate(HLERequestContext& ctx) {
- LOG_TRACE(Service_Audio, "called");
-
- const auto input{ctx.ReadBuffer(0)};
-
- // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
- // checking size 0. Performance size is 0 for most games.
-
- auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
- if (is_buffer_b) {
- const auto buffersB{ctx.BufferDescriptorB()};
- output_buffer.resize_destructive(buffersB[0].Size());
- performance_buffer.resize_destructive(buffersB[1].Size());
- } else {
- const auto buffersC{ctx.BufferDescriptorC()};
- output_buffer.resize_destructive(buffersC[0].Size());
- performance_buffer.resize_destructive(buffersC[1].Size());
- }
-
- auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
-
- if (result.IsSuccess()) {
- if (is_buffer_b) {
- ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
- ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
- } else {
- ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
- ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
- }
- } else {
- LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
- result.GetDescription());
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void Start(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- impl->Start();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void Stop(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- impl->Stop();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void QuerySystemEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultNotSupported);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(rendered_event->GetReadableEvent());
- }
-
- void SetRenderingTimeLimit(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::RequestParser rp{ctx};
- auto limit = rp.PopRaw<u32>();
-
- auto& system_ = impl->GetSystem();
- system_.SetRenderingTimeLimit(limit);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetRenderingTimeLimit(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& system_ = impl->GetSystem();
- auto time = system_.GetRenderingTimeLimit();
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(time);
- }
-
- void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
- }
-
- void SetVoiceDropParameter(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::RequestParser rp{ctx};
- auto voice_drop_param{rp.Pop<f32>()};
-
- auto& system_ = impl->GetSystem();
- system_.SetVoiceDropParameter(voice_drop_param);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetVoiceDropParameter(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- auto& system_ = impl->GetSystem();
- auto voice_drop_param{system_.GetVoiceDropParameter()};
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(voice_drop_param);
- }
-
- KernelHelpers::ServiceContext service_context;
- Kernel::KEvent* rendered_event;
- Manager& manager;
- std::unique_ptr<Renderer> impl;
- Kernel::KProcess& process;
- Common::ScratchBuffer<u8> output_buffer;
- Common::ScratchBuffer<u8> performance_buffer;
-};
-
-class IAudioDevice final : public ServiceFramework<IAudioDevice> {
-
-public:
- explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
- u32 device_num)
- : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
- impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
- event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
- static const FunctionInfo functions[] = {
- {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
- {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
- {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
- {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
- {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
- {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
- {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
- {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
- {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
- {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
- {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
- {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
- {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
- {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
- };
- RegisterHandlers(functions);
-
- event->Signal();
- }
-
- ~IAudioDevice() override {
- service_context.CloseEvent(event);
- }
-
-private:
- void ListAudioDeviceName(HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
-
- std::vector<AudioDevice::AudioDeviceName> out_names{};
-
- const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
-
- std::string out{};
- for (u32 i = 0; i < out_count; i++) {
- std::string a{};
- u32 j = 0;
- while (out_names[i].name[j] != '\0') {
- a += out_names[i].name[j];
- j++;
- }
- out += "\n\t" + a;
- }
-
- LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- ctx.WriteBuffer(out_names);
-
- rb.Push(ResultSuccess);
- rb.Push(out_count);
- }
-
- void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const f32 volume = rp.Pop<f32>();
-
- const auto device_name_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(device_name_buffer);
-
- LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
-
- if (name == "AudioTvOutput") {
- impl->SetDeviceVolumes(volume);
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
- const auto device_name_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(device_name_buffer);
-
- LOG_DEBUG(Service_Audio, "called. Name={}", name);
-
- f32 volume{1.0f};
- if (name == "AudioTvOutput") {
- volume = impl->GetDeviceVolume(name);
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(volume);
- }
-
- void GetActiveAudioDeviceName(HLERequestContext& ctx) {
- const auto write_size = ctx.GetWriteBufferSize();
- std::string out_name{"AudioTvOutput"};
-
- LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
-
- out_name.resize(write_size);
-
- ctx.WriteBuffer(out_name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "(STUBBED) called");
-
- event->Signal();
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void GetActiveChannelCount(HLERequestContext& ctx) {
- const auto& sink{system.AudioCore().GetOutputSink()};
- u32 channel_count{sink.GetSystemChannels()};
-
- LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- rb.Push(ResultSuccess);
- rb.Push<u32>(channel_count);
- }
-
- void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(event->GetReadableEvent());
- }
-
- void ListAudioOutputDeviceName(HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
-
- std::vector<AudioDevice::AudioDeviceName> out_names{};
-
- const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
-
- std::string out{};
- for (u32 i = 0; i < out_count; i++) {
- std::string a{};
- u32 j = 0;
- while (out_names[i].name[j] != '\0') {
- a += out_names[i].name[j];
- j++;
- }
- out += "\n\t" + a;
- }
-
- LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
-
- IPC::ResponseBuilder rb{ctx, 3};
-
- ctx.WriteBuffer(out_names);
-
- rb.Push(ResultSuccess);
- rb.Push(out_count);
- }
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioDevice> impl;
- Kernel::KEvent* event;
-};
-
-AudRenU::AudRenU(Core::System& system_)
- : ServiceFramework{system_, "audren:u"},
- service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
- {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
- {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
- {3, nullptr, "OpenAudioRendererForManualExecution"},
- {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudRenU::~AudRenU() = default;
-
-void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- AudioCore::AudioRendererParameterInternal params;
- rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
- rp.Skip(1, false);
- auto transfer_memory_size = rp.Pop<u64>();
- auto applet_resource_user_id = rp.Pop<u64>();
- auto transfer_memory_handle = ctx.GetCopyHandle(0);
- auto process_handle = ctx.GetCopyHandle(1);
-
- if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
- LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultOutOfSessions);
- return;
- }
-
- auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- const auto session_id{impl->GetSessionId()};
- if (session_id == -1) {
- LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Audio::ResultOutOfSessions);
- return;
- }
-
- LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
- impl->GetSessionCount());
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
- transfer_memory_size, process_handle, *process,
- applet_resource_user_id, session_id);
-}
-
-void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
- AudioCore::AudioRendererParameterInternal params;
-
- IPC::RequestParser rp{ctx};
- rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
-
- u64 size{0};
- auto result = impl->GetWorkBufferSize(params, size);
-
- std::string output_info{};
- output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
- output_info +=
- fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
- output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
- static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
- output_info += fmt::format(
- "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
- "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
- "Context {:04X}",
- params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
- params.splitter_destinations, params.voices, params.perf_frames,
- params.external_context_size);
-
- LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
- output_info, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push<u64>(size);
-}
-
-void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto applet_resource_user_id = rp.Pop<u64>();
-
- LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
- ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
-}
-
-void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
- LOG_ERROR(Service_Audio, "called. Implement me!");
-}
-
-void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
- struct Parameters {
- u32 revision;
- u64 applet_resource_user_id;
- };
-
- IPC::RequestParser rp{ctx};
-
- const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
-
- LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
- AudioCore::GetRevisionNum(revision), applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
- num_audio_devices++);
-}
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/audio_render_manager.h"
-#include "common/scratch_buffer.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-class IAudioRenderer;
-
-class AudRenU final : public ServiceFramework<AudRenU> {
-public:
- explicit AudRenU(Core::System& system_);
- ~AudRenU() override;
-
-private:
- void OpenAudioRenderer(HLERequestContext& ctx);
- void GetWorkBufferSize(HLERequestContext& ctx);
- void GetAudioDeviceService(HLERequestContext& ctx);
- void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
- void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
-
- KernelHelpers::ServiceContext service_context;
- std::unique_ptr<AudioCore::Renderer::Manager> impl;
- u32 num_audio_devices{0};
-};
-
-} // 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 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/audio/audrec_u.h"
+#include "core/hle/service/audio/final_output_recorder_manager.h"
namespace Service::Audio {
@@ -30,13 +30,14 @@ public:
}
};
-AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} {
+IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
+ : ServiceFramework{system_, "audrec:u"} {
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFinalOutputRecorder"},
};
RegisterHandlers(functions);
}
-AudRecU::~AudRecU() = default;
+IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
} // 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;
namespace Service::Audio {
-class AudRecA final : public ServiceFramework<AudRecA> {
+class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
public:
- explicit AudRecA(Core::System& system_);
- ~AudRecA() override;
+ explicit IFinalOutputRecorderManager(Core::System& system_);
+ ~IFinalOutputRecorderManager() override;
};
} // 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 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/audio/audrec_a.h"
+#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
namespace Service::Audio {
-AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
+IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
+ : ServiceFramework{system_, "audrec:a"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestSuspend"},
@@ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"}
RegisterHandlers(functions);
}
-AudRecA::~AudRecA() = default;
+IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
} // 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;
namespace Service::Audio {
-class AudRecU final : public ServiceFramework<AudRecU> {
+class IFinalOutputRecorderManagerForApplet final
+ : public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
public:
- explicit AudRecU(Core::System& system_);
- ~AudRecU() override;
+ explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
+ ~IFinalOutputRecorderManagerForApplet() override;
};
} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/hardware_opus_decoder.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::OpusDecoder;
+
+IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
+ : ServiceFramework{system_, "IHardwareOpusDecoder"},
+ impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"},
+ {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"},
+ {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"},
+ {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"},
+ {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"},
+ {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"},
+ {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"},
+ {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
+ {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"},
+ {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IHardwareOpusDecoder::~IHardwareOpusDecoder() = default;
+
+Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory,
+ u64 transfer_memory_size) {
+ return impl->Initialize(params, transfer_memory, transfer_memory_size);
+}
+
+Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory,
+ u64 transfer_memory_size) {
+ return impl->Initialize(params, transfer_memory, transfer_memory_size);
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data,
+ false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
+ *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->SetContext(decoder_context));
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld(
+ OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size,
+ Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data,
+ out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
+ *out_sample_count);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::SetContextForMultiStream(
+ InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
+ LOG_DEBUG(Service_Audio, "called");
+ R_RETURN(impl->SetContext(decoder_context));
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
+ *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, false));
+ LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
+ *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleaved(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset) {
+ R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
+ out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset) {
+ R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
+ opus_data, out_pcm_data, reset));
+ LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
+ *out_data_size, *out_sample_count, *out_time_taken);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/opus/decoder.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
+public:
+ explicit IHardwareOpusDecoder(Core::System& system_,
+ AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
+ ~IHardwareOpusDecoder() override;
+
+ Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
+ Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
+ Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
+
+private:
+ Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
+ Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
+ Result DecodeInterleavedWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result DecodeInterleavedForMultiStreamWithPerfOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data);
+ Result DecodeInterleavedWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
+ Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
+ Result DecodeInterleaved(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset);
+ Result DecodeInterleavedForMultiStream(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
+ Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
+ InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
+ bool reset);
+
+ std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
+ Common::ScratchBuffer<u8> output_data;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/audio/hardware_opus_decoder.h"
+#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::Audio {
+
+using namespace AudioCore::OpusDecoder;
+
+IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
+ : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
+ {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
+ {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
+ {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
+ {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
+ {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
+ {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
+ {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
+ {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
+ {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+}
+
+IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
+ params.sample_rate, params.channel_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+ OpusParametersEx ex{
+ .sample_rate = params.sample_rate,
+ .channel_count = params.channel_count,
+ .use_large_frame_size = false,
+ };
+ R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
+ R_TRY(impl.GetWorkBufferSize(params, *out_size));
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
+ params.sample_rate, params.channel_count, *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "transfer_memory_size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+
+ OpusMultiStreamParametersEx ex{
+ .sample_rate = params->sample_rate,
+ .channel_count = params->channel_count,
+ .total_stream_count = params->total_stream_count,
+ .stereo_stream_count = params->stereo_stream_count,
+ .use_large_frame_size = false,
+ .mappings{},
+ };
+ std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
+ R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
+ params.sample_rate, params.channel_count, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+ R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
+ OpusParametersEx params) {
+ R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "use_large_frame_size {}"
+ "transfer_memory_size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, params->use_large_frame_size, tmem_size);
+
+ auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
+
+ R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));
+
+ *out_decoder = decoder;
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
+ LOG_DEBUG(Service_Audio,
+ "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
+ "use_large_frame_size {} -- returned size {:#x}",
+ params->sample_rate, params->channel_count, params->total_stream_count,
+ params->stereo_stream_count, params->use_large_frame_size, *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
+ OpusParametersEx params) {
+ R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
+ R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
+ LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "audio_core/opus/decoder_manager.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::Audio {
+
+class IHardwareOpusDecoder;
+
+using AudioCore::OpusDecoder::OpusMultiStreamParameters;
+using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
+using AudioCore::OpusDecoder::OpusParameters;
+using AudioCore::OpusDecoder::OpusParametersEx;
+
+class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
+public:
+ explicit IHardwareOpusDecoderManager(Core::System& system_);
+ ~IHardwareOpusDecoderManager() override;
+
+private:
+ Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ OpusParameters params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
+ Result OpenHardwareOpusDecoderForMultiStream(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeForMultiStream(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
+ Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ OpusParametersEx params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
+ Result OpenHardwareOpusDecoderForMultiStreamEx(
+ Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
+ InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
+ InCopyHandle<Kernel::KTransferMemory> tmem_handle);
+ Result GetWorkBufferSizeForMultiStreamEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
+ Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
+ Result GetWorkBufferSizeForMultiStreamExEx(
+ Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
+
+ Core::System& system;
+ AudioCore::OpusDecoder::OpusDecoderManager impl;
+};
+
+} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <memory>
-#include <vector>
-
-#include "audio_core/opus/decoder.h"
-#include "audio_core/opus/parameters.h"
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "common/scratch_buffer.h"
-#include "core/core.h"
-#include "core/hle/service/audio/hwopus.h"
-#include "core/hle/service/ipc_helpers.h"
-
-namespace Service::Audio {
-using namespace AudioCore::OpusDecoder;
-
-class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
-public:
- explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
- : ServiceFramework{system_, "IHardwareOpusDecoder"},
- impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"},
- {1, &IHardwareOpusDecoder::SetContext, "SetContext"},
- {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"},
- {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"},
- {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
- {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"},
- {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"},
- {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
- {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"},
- {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
- Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size) {
- return impl->Initialize(params, transfer_memory, transfer_memory_size);
- }
-
- Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
- u64 transfer_memory_size) {
- return impl->Initialize(params, transfer_memory, transfer_memory_size);
- }
-
-private:
- void DecodeInterleavedOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- auto result =
- impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- }
-
- void SetContext(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_DEBUG(Service_Audio, "called");
-
- auto input_data{ctx.ReadBuffer(0)};
- auto result = impl->SetContext(input_data);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count,
- input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- }
-
- void SetContextForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_DEBUG(Service_Audio, "called");
-
- auto input_data{ctx.ReadBuffer(0)};
- auto result = impl->SetContext(input_data);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
- sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, false);
-
- LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
- sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleaved(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
- output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto reset{rp.Pop<bool>()};
-
- auto input_data{ctx.ReadBuffer(0)};
- output_data.resize_destructive(ctx.GetWriteBufferSize());
-
- u32 size{};
- u32 sample_count{};
- u64 time_taken{};
- auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
- input_data, output_data, reset);
-
- LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
- reset, size, sample_count, time_taken);
-
- ctx.WriteBuffer(output_data);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(result);
- rb.Push(size);
- rb.Push(sample_count);
- rb.Push(time_taken);
- }
-
- std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
- Common::ScratchBuffer<u8> output_data;
-};
-
-void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto params = rp.PopRaw<OpusParameters>();
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- OpusParametersEx ex{
- .sample_rate = params.sample_rate,
- .channel_count = params.channel_count,
- .use_large_frame_size = false,
- };
- auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParameters>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSize(params, size);
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}",
- params.sample_rate, params.channel_count, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParameters params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
-
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- OpusMultiStreamParametersEx ex{
- .sample_rate = params.sample_rate,
- .channel_count = params.channel_count,
- .total_stream_count = params.total_stream_count,
- .stereo_stream_count = params.stereo_stream_count,
- .use_large_frame_size = false,
- .mappings{},
- };
- std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings));
- auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParameters params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStream(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto params = rp.PopRaw<OpusParametersEx>();
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- auto result =
- decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParametersEx>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- auto transfer_memory_size{rp.Pop<u32>()};
- auto transfer_memory_handle{ctx.GetCopyHandle(0)};
- auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "use_large_frame_size {}"
- "transfer_memory_size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size);
-
- auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
-
- auto result =
- decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result);
- rb.PushIpcInterface(decoder);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size);
-
- LOG_DEBUG(Service_Audio,
- "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
- "use_large_frame_size {} -- returned size 0x{:X}",
- params.sample_rate, params.channel_count, params.total_stream_count,
- params.stereo_stream_count, params.use_large_frame_size, size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- auto params = rp.PopRaw<OpusParametersEx>();
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeExEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto input{ctx.ReadBuffer()};
- OpusMultiStreamParametersEx params;
- std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
-
- u64 size{};
- auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size);
-
- LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(size);
-}
-
-HwOpus::HwOpus(Core::System& system_)
- : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
- static const FunctionInfo functions[] = {
- {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
- {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
- {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"},
- {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"},
- {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
- {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
- {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
- "OpenHardwareOpusDecoderForMultiStreamEx"},
- {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
- {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"},
- {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"},
- };
- RegisterHandlers(functions);
-}
-
-HwOpus::~HwOpus() = default;
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "audio_core/opus/decoder_manager.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class HwOpus final : public ServiceFramework<HwOpus> {
-public:
- explicit HwOpus(Core::System& system_);
- ~HwOpus() override;
-
-private:
- void OpenHardwareOpusDecoder(HLERequestContext& ctx);
- void GetWorkBufferSize(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
- void GetWorkBufferSizeEx(HLERequestContext& ctx);
- void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
- void GetWorkBufferSizeExEx(HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx);
-
- Core::System& system;
- AudioCore::OpusDecoder::OpusDecoderManager impl;
-};
-
-} // 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 @@
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/btdrv/btdrv.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/server_manager.h"
@@ -13,9 +14,9 @@
namespace Service::BtDrv {
-class Bt final : public ServiceFramework<Bt> {
+class IBluetoothUser final : public ServiceFramework<IBluetoothUser> {
public:
- explicit Bt(Core::System& system_)
+ explicit IBluetoothUser(Core::System& system_)
: ServiceFramework{system_, "bt"}, service_context{system_, "bt"} {
// clang-format off
static const FunctionInfo functions[] = {
@@ -28,7 +29,7 @@ public:
{6, nullptr, "SetLeResponse"},
{7, nullptr, "LeSendIndication"},
{8, nullptr, "GetLeEventInfo"},
- {9, &Bt::RegisterBleEvent, "RegisterBleEvent"},
+ {9, C<&IBluetoothUser::RegisterBleEvent>, "RegisterBleEvent"},
};
// clang-format on
RegisterHandlers(functions);
@@ -36,17 +37,16 @@ public:
register_event = service_context.CreateEvent("BT:RegisterEvent");
}
- ~Bt() override {
+ ~IBluetoothUser() override {
service_context.CloseEvent(register_event);
}
private:
- void RegisterBleEvent(HLERequestContext& ctx) {
+ Result RegisterBleEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(register_event->GetReadableEvent());
+ *out_event = &register_event->GetReadableEvent();
+ R_SUCCEED();
}
KernelHelpers::ServiceContext service_context;
@@ -54,9 +54,9 @@ private:
Kernel::KEvent* register_event;
};
-class BtDrv final : public ServiceFramework<BtDrv> {
+class IBluetoothDriver final : public ServiceFramework<IBluetoothDriver> {
public:
- explicit BtDrv(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
+ explicit IBluetoothDriver(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "InitializeBluetoothDriver"},
@@ -93,7 +93,7 @@ public:
{31, nullptr, "EnableMcMode"},
{32, nullptr, "EnableLlrScan"},
{33, nullptr, "DisableLlrScan"},
- {34, nullptr, "EnableRadio"},
+ {34, C<&IBluetoothDriver::EnableRadio>, "EnableRadio"},
{35, nullptr, "SetVisibility"},
{36, nullptr, "EnableTbfcScan"},
{37, nullptr, "RegisterHidReportEvent"},
@@ -195,13 +195,19 @@ public:
RegisterHandlers(functions);
}
+
+private:
+ Result EnableRadio() {
+ LOG_WARNING(Service_BTDRV, "(STUBBED) called");
+ R_SUCCEED();
+ }
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("btdrv", std::make_shared<BtDrv>(system));
- server_manager->RegisterNamedService("bt", std::make_shared<Bt>(system));
+ server_manager->RegisterNamedService("btdrv", std::make_shared<IBluetoothDriver>(system));
+ server_manager->RegisterNamedService("bt", std::make_shared<IBluetoothUser>(system));
ServerManager::RunServer(std::move(server_manager));
}
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 @@
#include <memory>
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_event.h"
#include "core/hle/service/btm/btm.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/btm/btm_debug.h"
+#include "core/hle/service/btm/btm_system.h"
+#include "core/hle/service/btm/btm_user.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::BTM {
-class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
+class IBtm final : public ServiceFramework<IBtm> {
public:
- explicit IBtmUserCore(Core::System& system_)
- : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
- {1, nullptr, "GetBleScanFilterParameter"},
- {2, nullptr, "GetBleScanFilterParameter2"},
- {3, nullptr, "StartBleScanForGeneral"},
- {4, nullptr, "StopBleScanForGeneral"},
- {5, nullptr, "GetBleScanResultsForGeneral"},
- {6, nullptr, "StartBleScanForPaired"},
- {7, nullptr, "StopBleScanForPaired"},
- {8, nullptr, "StartBleScanForSmartDevice"},
- {9, nullptr, "StopBleScanForSmartDevice"},
- {10, nullptr, "GetBleScanResultsForSmartDevice"},
- {17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"},
- {18, nullptr, "BleConnect"},
- {19, nullptr, "BleDisconnect"},
- {20, nullptr, "BleGetConnectionState"},
- {21, nullptr, "AcquireBlePairingEvent"},
- {22, nullptr, "BlePairDevice"},
- {23, nullptr, "BleUnPairDevice"},
- {24, nullptr, "BleUnPairDevice2"},
- {25, nullptr, "BleGetPairedDevices"},
- {26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"},
- {27, nullptr, "GetGattServices"},
- {28, nullptr, "GetGattService"},
- {29, nullptr, "GetGattIncludedServices"},
- {30, nullptr, "GetBelongingGattService"},
- {31, nullptr, "GetGattCharacteristics"},
- {32, nullptr, "GetGattDescriptors"},
- {33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"},
- {34, nullptr, "ConfigureBleMtu"},
- {35, nullptr, "GetBleMtu"},
- {36, nullptr, "RegisterBleGattDataPath"},
- {37, nullptr, "UnregisterBleGattDataPath"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
- connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
- service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
- config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
- }
-
- ~IBtmUserCore() override {
- service_context.CloseEvent(scan_event);
- service_context.CloseEvent(connection_event);
- service_context.CloseEvent(service_discovery_event);
- service_context.CloseEvent(config_event);
- }
-
-private:
- void AcquireBleScanEvent(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3, 1};
- rb.Push(ResultSuccess);
- rb.Push(true);
- rb.PushCopyObjects(scan_event->GetReadableEvent());
- }
-
- void AcquireBleConnectionEvent(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3, 1};
- rb.Push(ResultSuccess);
- rb.Push(true);
- rb.PushCopyObjects(connection_event->GetReadableEvent());
- }
-
- void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3, 1};
- rb.Push(ResultSuccess);
- rb.Push(true);
- rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
- }
-
- void AcquireBleMtuConfigEvent(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3, 1};
- rb.Push(ResultSuccess);
- rb.Push(true);
- rb.PushCopyObjects(config_event->GetReadableEvent());
- }
-
- KernelHelpers::ServiceContext service_context;
-
- Kernel::KEvent* scan_event;
- Kernel::KEvent* connection_event;
- Kernel::KEvent* service_discovery_event;
- Kernel::KEvent* config_event;
-};
-
-class BTM_USR final : public ServiceFramework<BTM_USR> {
-public:
- explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &BTM_USR::GetCore, "GetCore"},
- };
- // clang-format on
- RegisterHandlers(functions);
- }
-
-private:
- void GetCore(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IBtmUserCore>(system);
- }
-};
-
-class BTM final : public ServiceFramework<BTM> {
-public:
- explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} {
+ explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetState"},
@@ -232,144 +109,13 @@ public:
}
};
-class BTM_DBG final : public ServiceFramework<BTM_DBG> {
-public:
- explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "AcquireDiscoveryEvent"},
- {1, nullptr, "StartDiscovery"},
- {2, nullptr, "CancelDiscovery"},
- {3, nullptr, "GetDeviceProperty"},
- {4, nullptr, "CreateBond"},
- {5, nullptr, "CancelBond"},
- {6, nullptr, "SetTsiMode"},
- {7, nullptr, "GeneralTest"},
- {8, nullptr, "HidConnect"},
- {9, nullptr, "GeneralGet"},
- {10, nullptr, "GetGattClientDisconnectionReason"},
- {11, nullptr, "GetBleConnectionParameter"},
- {12, nullptr, "GetBleConnectionParameterRequest"},
- {13, nullptr, "Unknown13"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
-public:
- explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
- {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
- {2, nullptr, "ClearGamepadPairingDatabase"},
- {3, nullptr, "GetPairedGamepadCount"},
- {4, nullptr, "EnableRadio"},
- {5, nullptr, "DisableRadio"},
- {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
- {7, nullptr, "AcquireRadioEvent"},
- {8, nullptr, "AcquireGamepadPairingEvent"},
- {9, nullptr, "IsGamepadPairingStarted"},
- {10, nullptr, "StartAudioDeviceDiscovery"},
- {11, nullptr, "StopAudioDeviceDiscovery"},
- {12, nullptr, "IsDiscoveryingAudioDevice"},
- {13, nullptr, "GetDiscoveredAudioDevice"},
- {14, nullptr, "AcquireAudioDeviceConnectionEvent"},
- {15, nullptr, "ConnectAudioDevice"},
- {16, nullptr, "IsConnectingAudioDevice"},
- {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
- {18, nullptr, "DisconnectAudioDevice"},
- {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
- {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"},
- {21, nullptr, "RemoveAudioDevicePairing"},
- {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
- {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void IsRadioEnabled(HLERequestContext& ctx) {
- LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(true);
- }
-
- void StartGamepadPairing(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void CancelGamepadPairing(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetConnectedAudioDevices(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(0);
- }
-
- void GetPairedAudioDevices(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(0);
- }
-
- void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
-
-class BTM_SYS final : public ServiceFramework<BTM_SYS> {
-public:
- explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &BTM_SYS::GetCore, "GetCore"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void GetCore(HLERequestContext& ctx) {
- LOG_WARNING(Service_BTM, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IBtmSystemCore>(system);
- }
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system));
- server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system));
- server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system));
- server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system));
+ server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system));
+ server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system));
+ server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system));
+ server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system));
ServerManager::RunServer(std::move(server_manager));
}
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 @@
#pragma once
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Core {
class System;
};
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/btm/btm_debug.h"
+
+namespace Service::BTM {
+
+IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "AcquireDiscoveryEvent"},
+ {1, nullptr, "StartDiscovery"},
+ {2, nullptr, "CancelDiscovery"},
+ {3, nullptr, "GetDeviceProperty"},
+ {4, nullptr, "CreateBond"},
+ {5, nullptr, "CancelBond"},
+ {6, nullptr, "SetTsiMode"},
+ {7, nullptr, "GeneralTest"},
+ {8, nullptr, "HidConnect"},
+ {9, nullptr, "GeneralGet"},
+ {10, nullptr, "GetGattClientDisconnectionReason"},
+ {11, nullptr, "GetBleConnectionParameter"},
+ {12, nullptr, "GetBleConnectionParameterRequest"},
+ {13, nullptr, "Unknown13"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IBtmDebug::~IBtmDebug() = default;
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::BTM {
+
+class IBtmDebug final : public ServiceFramework<IBtmDebug> {
+public:
+ explicit IBtmDebug(Core::System& system_);
+ ~IBtmDebug() override;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/hle/service/btm/btm_system.h"
+#include "core/hle/service/btm/btm_system_core.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/service.h"
+
+namespace Service::BTM {
+
+IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, C<&IBtmSystem::GetCore>, "GetCore"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IBtmSystem::~IBtmSystem() = default;
+
+Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) {
+ LOG_WARNING(Service_BTM, "called");
+
+ *out_interface = std::make_shared<IBtmSystemCore>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::BTM {
+class IBtmSystemCore;
+
+class IBtmSystem final : public ServiceFramework<IBtmSystem> {
+public:
+ explicit IBtmSystem(Core::System& system_);
+ ~IBtmSystem() override;
+
+private:
+ Result GetCore(OutInterface<IBtmSystemCore> out_interface);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/hle/service/btm/btm_system_core.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/set/system_settings_server.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service::BTM {
+
+IBtmSystemCore::IBtmSystemCore(Core::System& system_)
+ : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"},
+ {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"},
+ {2, nullptr, "ClearGamepadPairingDatabase"},
+ {3, nullptr, "GetPairedGamepadCount"},
+ {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"},
+ {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"},
+ {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"},
+ {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"},
+ {8, nullptr, "AcquireGamepadPairingEvent"},
+ {9, nullptr, "IsGamepadPairingStarted"},
+ {10, nullptr, "StartAudioDeviceDiscovery"},
+ {11, nullptr, "StopAudioDeviceDiscovery"},
+ {12, nullptr, "IsDiscoveryingAudioDevice"},
+ {13, nullptr, "GetDiscoveredAudioDevice"},
+ {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
+ {15, nullptr, "ConnectAudioDevice"},
+ {16, nullptr, "IsConnectingAudioDevice"},
+ {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"},
+ {18, nullptr, "DisconnectAudioDevice"},
+ {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
+ {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"},
+ {21, nullptr, "RemoveAudioDevicePairing"},
+ {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"},
+ {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"}
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent");
+ audio_device_connection_event =
+ service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent");
+
+ m_set_sys =
+ system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
+}
+
+IBtmSystemCore::~IBtmSystemCore() {
+ service_context.CloseEvent(radio_event);
+ service_context.CloseEvent(audio_device_connection_event);
+}
+
+Result IBtmSystemCore::StartGamepadPairing() {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::CancelGamepadPairing() {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::EnableRadio() {
+ LOG_DEBUG(Service_BTM, "called");
+
+ R_RETURN(m_set_sys->SetBluetoothEnableFlag(true));
+}
+Result IBtmSystemCore::DisableRadio() {
+ LOG_DEBUG(Service_BTM, "called");
+
+ R_RETURN(m_set_sys->SetBluetoothEnableFlag(false));
+}
+
+Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) {
+ LOG_DEBUG(Service_BTM, "called");
+
+ R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled));
+}
+
+Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_is_valid = true;
+ *out_event = &radio_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_event = &audio_device_connection_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::GetConnectedAudioDevices(
+ Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_count = 0;
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::GetPairedAudioDevices(
+ Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_count = 0;
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
+ R_SUCCEED();
+}
+
+Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+}
+
+namespace Service::Set {
+class ISystemSettingsServer;
+}
+
+namespace Service::BTM {
+
+class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
+public:
+ explicit IBtmSystemCore(Core::System& system_);
+ ~IBtmSystemCore() override;
+
+private:
+ Result StartGamepadPairing();
+ Result CancelGamepadPairing();
+ Result EnableRadio();
+ Result DisableRadio();
+ Result IsRadioEnabled(Out<bool> out_is_enabled);
+
+ Result AcquireRadioEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ Result GetConnectedAudioDevices(
+ Out<s32> out_count,
+ OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
+
+ Result GetPairedAudioDevices(
+ Out<s32> out_count,
+ OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
+
+ Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
+ Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
+
+ KernelHelpers::ServiceContext service_context;
+
+ Kernel::KEvent* radio_event;
+ Kernel::KEvent* audio_device_connection_event;
+ std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/hle/service/btm/btm_user.h"
+#include "core/hle/service/btm/btm_user_core.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::BTM {
+
+IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, C<&IBtmUser::GetCore>, "GetCore"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IBtmUser::~IBtmUser() = default;
+
+Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) {
+ LOG_WARNING(Service_BTM, "called");
+
+ *out_interface = std::make_shared<IBtmUserCore>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::BTM {
+class IBtmUserCore;
+
+class IBtmUser final : public ServiceFramework<IBtmUser> {
+public:
+ explicit IBtmUser(Core::System& system_);
+ ~IBtmUser() override;
+
+private:
+ Result GetCore(OutInterface<IBtmUserCore> out_interface);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <memory>
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/btm/btm_user_core.h"
+#include "core/hle/service/cmif_serialization.h"
+
+namespace Service::BTM {
+
+IBtmUserCore::IBtmUserCore(Core::System& system_)
+ : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, C<&IBtmUserCore::AcquireBleScanEvent>, "AcquireBleScanEvent"},
+ {1, nullptr, "GetBleScanFilterParameter"},
+ {2, nullptr, "GetBleScanFilterParameter2"},
+ {3, nullptr, "StartBleScanForGeneral"},
+ {4, nullptr, "StopBleScanForGeneral"},
+ {5, nullptr, "GetBleScanResultsForGeneral"},
+ {6, nullptr, "StartBleScanForPaired"},
+ {7, nullptr, "StopBleScanForPaired"},
+ {8, nullptr, "StartBleScanForSmartDevice"},
+ {9, nullptr, "StopBleScanForSmartDevice"},
+ {10, nullptr, "GetBleScanResultsForSmartDevice"},
+ {17, C<&IBtmUserCore::AcquireBleConnectionEvent>, "AcquireBleConnectionEvent"},
+ {18, nullptr, "BleConnect"},
+ {19, nullptr, "BleDisconnect"},
+ {20, nullptr, "BleGetConnectionState"},
+ {21, nullptr, "AcquireBlePairingEvent"},
+ {22, nullptr, "BlePairDevice"},
+ {23, nullptr, "BleUnPairDevice"},
+ {24, nullptr, "BleUnPairDevice2"},
+ {25, nullptr, "BleGetPairedDevices"},
+ {26, C<&IBtmUserCore::AcquireBleServiceDiscoveryEvent>, "AcquireBleServiceDiscoveryEvent"},
+ {27, nullptr, "GetGattServices"},
+ {28, nullptr, "GetGattService"},
+ {29, nullptr, "GetGattIncludedServices"},
+ {30, nullptr, "GetBelongingGattService"},
+ {31, nullptr, "GetGattCharacteristics"},
+ {32, nullptr, "GetGattDescriptors"},
+ {33, C<&IBtmUserCore::AcquireBleMtuConfigEvent>, "AcquireBleMtuConfigEvent"},
+ {34, nullptr, "ConfigureBleMtu"},
+ {35, nullptr, "GetBleMtu"},
+ {36, nullptr, "RegisterBleGattDataPath"},
+ {37, nullptr, "UnregisterBleGattDataPath"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
+ connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
+ service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
+ config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
+}
+
+IBtmUserCore::~IBtmUserCore() {
+ service_context.CloseEvent(scan_event);
+ service_context.CloseEvent(connection_event);
+ service_context.CloseEvent(service_discovery_event);
+ service_context.CloseEvent(config_event);
+}
+
+Result IBtmUserCore::AcquireBleScanEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_is_valid = true;
+ *out_event = &scan_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IBtmUserCore::AcquireBleConnectionEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_is_valid = true;
+ *out_event = &connection_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IBtmUserCore::AcquireBleServiceDiscoveryEvent(
+ Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_is_valid = true;
+ *out_event = &service_discovery_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+Result IBtmUserCore::AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ *out_is_valid = true;
+ *out_event = &config_event->GetReadableEvent();
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+}
+
+namespace Service::BTM {
+
+class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
+public:
+ explicit IBtmUserCore(Core::System& system_);
+ ~IBtmUserCore() override;
+
+private:
+ Result AcquireBleScanEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ Result AcquireBleConnectionEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ Result AcquireBleServiceDiscoveryEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ Result AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
+ OutCopyHandle<Kernel::KReadableEvent> out_event);
+
+ KernelHelpers::ServiceContext service_context;
+
+ Kernel::KEvent* scan_event;
+ Kernel::KEvent* connection_event;
+ Kernel::KEvent* service_discovery_event;
+ Kernel::KEvent* config_event;
+};
+
+} // 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
auto& buffer = temp[OutBufferIndex];
const size_t size = buffer.size();
- if (ctx.CanWriteBuffer(OutBufferIndex)) {
+ if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
} 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 @@
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/savedata_factory.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
-#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
-template <typename T>
-static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
- const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
- entries.reserve(entries.size() + new_data.size());
-
- for (const auto& new_entry : new_data) {
- auto name = new_entry->GetName();
-
- if (type == FileSys::DirectoryEntryType::File &&
- name == FileSys::GetSaveDataSizeFileName()) {
- continue;
- }
-
- entries.emplace_back(name, static_cast<s8>(type),
- type == FileSys::DirectoryEntryType::Directory ? 0
- : new_entry->GetSize());
- }
-}
-
-IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
+IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
FileSys::OpenDirectoryMode mode)
- : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
+ : ServiceFramework{system_, "IDirectory"},
+ backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
static const FunctionInfo functions[] = {
- {0, &IDirectory::Read, "Read"},
- {1, &IDirectory::GetEntryCount, "GetEntryCount"},
+ {0, D<&IDirectory::Read>, "Read"},
+ {1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
};
RegisterHandlers(functions);
-
- // TODO(DarkLordZach): Verify that this is the correct behavior.
- // Build entry index now to save time later.
- if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
- BuildEntryIndex(entries, backend->GetSubdirectories(),
- FileSys::DirectoryEntryType::Directory);
- }
- if (True(mode & FileSys::OpenDirectoryMode::File)) {
- BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
- }
}
-void IDirectory::Read(HLERequestContext& ctx) {
+Result IDirectory::Read(
+ Out<s64> out_count,
+ const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
LOG_DEBUG(Service_FS, "called.");
- // Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
-
- // Cap at total number of entries.
- const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
-
- // Determine data start and end
- const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
- const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
- const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
-
- next_entry_index += actual_entries;
-
- // Write the data to memory
- ctx.WriteBuffer(begin, range_size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(actual_entries);
+ R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
}
-void IDirectory::GetEntryCount(HLERequestContext& ctx) {
+Result IDirectory::GetEntryCount(Out<s64> out_count) {
LOG_DEBUG(Service_FS, "called");
- u64 count = entries.size() - next_entry_index;
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(count);
+ R_RETURN(backend->GetEntryCount(out_count));
}
} // 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 @@
#pragma once
+#include "core/file_sys/fsa/fs_i_directory.h"
#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/service.h"
@@ -15,16 +17,15 @@ namespace Service::FileSystem {
class IDirectory final : public ServiceFramework<IDirectory> {
public:
- explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
+ explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
FileSys::OpenDirectoryMode mode);
private:
- FileSys::VirtualDir backend;
- std::vector<FileSys::DirectoryEntry> entries;
- u64 next_entry_index = 0;
+ std::unique_ptr<FileSys::Fsa::IDirectory> backend;
- void Read(HLERequestContext& ctx);
- void GetEntryCount(HLERequestContext& ctx);
+ Result Read(Out<s64> out_count,
+ const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
+ Result GetEntryCount(Out<s64> out_count);
};
} // 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 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/errors.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_file.h"
-#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
-IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
- : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
+IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
+ : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
+ // clang-format off
static const FunctionInfo functions[] = {
- {0, &IFile::Read, "Read"},
- {1, &IFile::Write, "Write"},
- {2, &IFile::Flush, "Flush"},
- {3, &IFile::SetSize, "SetSize"},
- {4, &IFile::GetSize, "GetSize"},
+ {0, D<&IFile::Read>, "Read"},
+ {1, D<&IFile::Write>, "Write"},
+ {2, D<&IFile::Flush>, "Flush"},
+ {3, D<&IFile::SetSize>, "SetSize"},
+ {4, D<&IFile::GetSize>, "GetSize"},
{5, nullptr, "OperateRange"},
{6, nullptr, "OperateRangeWithBuffer"},
};
+ // clang-format on
RegisterHandlers(functions);
}
-void IFile::Read(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 option = rp.Pop<u64>();
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
- LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
-
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidSize);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidOffset);
- return;
- }
+Result IFile::Read(
+ FileSys::ReadOption option, Out<s64> out_size, s64 offset,
+ const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
+ s64 size) {
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
+ size);
// Read the data from the Storage backend
- std::vector<u8> output = backend->ReadBytes(length, offset);
-
- // Write the data to memory
- ctx.WriteBuffer(output);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<u64>(output.size()));
+ R_RETURN(
+ backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
}
-void IFile::Write(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 option = rp.Pop<u64>();
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
- LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
-
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidSize);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidOffset);
- return;
- }
-
- const auto data = ctx.ReadBuffer();
+Result IFile::Write(
+ const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
+ FileSys::WriteOption option, s64 offset, s64 size) {
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
+ size);
- ASSERT_MSG(static_cast<s64>(data.size()) <= length,
- "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
- length, data.size());
-
- // Write the data to the Storage backend
- const auto write_size =
- static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
- const std::size_t written = backend->Write(data.data(), write_size, offset);
-
- ASSERT_MSG(static_cast<s64>(written) == length,
- "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
- written);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(backend->Write(offset, buffer.data(), size, option));
}
-void IFile::Flush(HLERequestContext& ctx) {
+Result IFile::Flush() {
LOG_DEBUG(Service_FS, "called");
- // Exists for SDK compatibiltity -- No need to flush file.
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(backend->Flush());
}
-void IFile::SetSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 size = rp.Pop<u64>();
+Result IFile::SetSize(s64 size) {
LOG_DEBUG(Service_FS, "called, size={}", size);
- backend->Resize(size);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(backend->SetSize(size));
}
-void IFile::GetSize(HLERequestContext& ctx) {
- const u64 size = backend->GetSize();
- LOG_DEBUG(Service_FS, "called, size={}", size);
+Result IFile::GetSize(Out<s64> out_size) {
+ LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(size);
+ R_RETURN(backend->GetSize(out_size));
}
} // 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 @@
#pragma once
+#include "core/file_sys/fsa/fs_i_file.h"
+#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/service.h"
@@ -10,16 +12,21 @@ namespace Service::FileSystem {
class IFile final : public ServiceFramework<IFile> {
public:
- explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
+ explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
private:
- FileSys::VirtualFile backend;
+ std::unique_ptr<FileSys::Fsa::IFile> backend;
- void Read(HLERequestContext& ctx);
- void Write(HLERequestContext& ctx);
- void Flush(HLERequestContext& ctx);
- void SetSize(HLERequestContext& ctx);
- void GetSize(HLERequestContext& ctx);
+ Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
+ const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
+ out_buffer,
+ s64 size);
+ Result Write(
+ const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
+ FileSys::WriteOption option, s64 offset, s64 size);
+ Result Flush();
+ Result SetSize(s64 size);
+ Result GetSize(Out<s64> out_size);
};
} // 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 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/string_util.h"
+#include "core/file_sys/fssrv/fssrv_sf_path.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
#include "core/hle/service/filesystem/fsp/fs_i_file.h"
#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
-#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
-IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
- : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
- size_)} {
+IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
+ : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
+ dir_)},
+ size_getter{std::move(size_getter_)} {
static const FunctionInfo functions[] = {
- {0, &IFileSystem::CreateFile, "CreateFile"},
- {1, &IFileSystem::DeleteFile, "DeleteFile"},
- {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
- {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
- {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
- {5, &IFileSystem::RenameFile, "RenameFile"},
+ {0, D<&IFileSystem::CreateFile>, "CreateFile"},
+ {1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
+ {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
+ {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
+ {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
+ {5, D<&IFileSystem::RenameFile>, "RenameFile"},
{6, nullptr, "RenameDirectory"},
- {7, &IFileSystem::GetEntryType, "GetEntryType"},
- {8, &IFileSystem::OpenFile, "OpenFile"},
- {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
- {10, &IFileSystem::Commit, "Commit"},
- {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
- {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
- {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
- {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
+ {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
+ {8, D<&IFileSystem::OpenFile>, "OpenFile"},
+ {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
+ {10, D<&IFileSystem::Commit>, "Commit"},
+ {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
+ {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
+ {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
+ {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
{15, nullptr, "QueryEntry"},
- {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
+ {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
};
RegisterHandlers(functions);
}
-void IFileSystem::CreateFile(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
+Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
+ s32 option, s64 size) {
+ LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- const u64 file_mode = rp.Pop<u64>();
- const u32 file_size = rp.Pop<u32>();
-
- LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
- file_size);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CreateFile(name, file_size));
+ R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
}
-void IFileSystem::DeleteFile(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
+Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. file={}", path->str);
- LOG_DEBUG(Service_FS, "called. file={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteFile(name));
+ R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
}
-void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. directory={}", name);
+Result IFileSystem::CreateDirectory(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. directory={}", path->str);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CreateDirectory(name));
+ R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
}
-void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. directory={}", name);
+Result IFileSystem::DeleteDirectory(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. directory={}", path->str);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteDirectory(name));
+ R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
}
-void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
+Result IFileSystem::DeleteDirectoryRecursively(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. directory={}", path->str);
- LOG_DEBUG(Service_FS, "called. directory={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteDirectoryRecursively(name));
+ R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
}
-void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. Directory: {}", name);
+Result IFileSystem::CleanDirectoryRecursively(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CleanDirectoryRecursively(name));
+ R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
}
-void IFileSystem::RenameFile(HLERequestContext& ctx) {
- const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
- const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
-
- LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
+Result IFileSystem::RenameFile(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
+ LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.RenameFile(src_name, dst_name));
+ R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
}
-void IFileSystem::OpenFile(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
-
- LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
+Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
+ u32 mode) {
+ LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
FileSys::VirtualFile vfs_file{};
- auto result = backend.OpenFile(&vfs_file, name, mode);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- auto file = std::make_shared<IFile>(system, vfs_file);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFile>(std::move(file));
-}
-
-void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
+ R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
+ static_cast<FileSys::OpenMode>(mode)));
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
- const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>();
+ *out_interface = std::make_shared<IFile>(system, vfs_file);
+ R_SUCCEED();
+}
- LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
+Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
+ u32 mode) {
+ LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
FileSys::VirtualDir vfs_dir{};
- auto result = backend.OpenDirectory(&vfs_dir, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IDirectory>(std::move(directory));
-}
+ R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
+ static_cast<FileSys::OpenDirectoryMode>(mode)));
-void IFileSystem::GetEntryType(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
+ *out_interface = std::make_shared<IDirectory>(system, vfs_dir,
+ static_cast<FileSys::OpenDirectoryMode>(mode));
+ R_SUCCEED();
+}
- LOG_DEBUG(Service_FS, "called. file={}", name);
+Result IFileSystem::GetEntryType(
+ Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_DEBUG(Service_FS, "called. file={}", path->str);
FileSys::DirectoryEntryType vfs_entry_type{};
- auto result = backend.GetEntryType(&vfs_entry_type, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(vfs_entry_type));
+ R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
+
+ *out_type = static_cast<u32>(vfs_entry_type);
+ R_SUCCEED();
}
-void IFileSystem::Commit(HLERequestContext& ctx) {
+Result IFileSystem::Commit() {
LOG_WARNING(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
+Result IFileSystem::GetFreeSpaceSize(
+ Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(size.get_free_size());
+ *out_size = size_getter.get_free_size();
+ R_SUCCEED();
}
-void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
+Result IFileSystem::GetTotalSpaceSize(
+ Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(size.get_total_size());
+ *out_size = size_getter.get_total_size();
+ R_SUCCEED();
}
-void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
+Result IFileSystem::GetFileTimeStampRaw(
+ Out<FileSys::FileTimeStampRaw> out_timestamp,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
+ LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
FileSys::FileTimeStampRaw vfs_timestamp{};
- auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 10};
- rb.Push(ResultSuccess);
- rb.PushRaw(vfs_timestamp);
+ R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
+
+ *out_timestamp = vfs_timestamp;
+ R_SUCCEED();
}
-void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
+Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called");
- struct FileSystemAttribute {
- u8 dir_entry_name_length_max_defined;
- u8 file_entry_name_length_max_defined;
- u8 dir_path_name_length_max_defined;
- u8 file_path_name_length_max_defined;
- INSERT_PADDING_BYTES_NOINIT(0x5);
- u8 utf16_dir_entry_name_length_max_defined;
- u8 utf16_file_entry_name_length_max_defined;
- u8 utf16_dir_path_name_length_max_defined;
- u8 utf16_file_path_name_length_max_defined;
- INSERT_PADDING_BYTES_NOINIT(0x18);
- s32 dir_entry_name_length_max;
- s32 file_entry_name_length_max;
- s32 dir_path_name_length_max;
- s32 file_path_name_length_max;
- INSERT_PADDING_WORDS_NOINIT(0x5);
- s32 utf16_dir_entry_name_length_max;
- s32 utf16_file_entry_name_length_max;
- s32 utf16_dir_path_name_length_max;
- s32 utf16_file_path_name_length_max;
- INSERT_PADDING_WORDS_NOINIT(0x18);
- INSERT_PADDING_WORDS_NOINIT(0x1);
- };
- static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
-
- FileSystemAttribute savedata_attribute{};
+ FileSys::FileSystemAttribute savedata_attribute{};
savedata_attribute.dir_entry_name_length_max_defined = true;
savedata_attribute.file_entry_name_length_max_defined = true;
savedata_attribute.dir_entry_name_length_max = 0x40;
savedata_attribute.file_entry_name_length_max = 0x40;
- IPC::ResponseBuilder rb{ctx, 50};
- rb.Push(ResultSuccess);
- rb.PushRaw(savedata_attribute);
+ *out_attribute = savedata_attribute;
+ R_SUCCEED();
}
} // 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 @@
#pragma once
+#include "common/common_funcs.h"
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/fsa/fs_i_filesystem.h"
#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
-#include "core/hle/service/filesystem/fsp/fsp_util.h"
+#include "core/hle/service/filesystem/fsp/fsp_types.h"
#include "core/hle/service/service.h"
+namespace FileSys::Sf {
+struct Path;
+}
+
namespace Service::FileSystem {
+class IFile;
+class IDirectory;
+
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
- explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
-
- void CreateFile(HLERequestContext& ctx);
- void DeleteFile(HLERequestContext& ctx);
- void CreateDirectory(HLERequestContext& ctx);
- void DeleteDirectory(HLERequestContext& ctx);
- void DeleteDirectoryRecursively(HLERequestContext& ctx);
- void CleanDirectoryRecursively(HLERequestContext& ctx);
- void RenameFile(HLERequestContext& ctx);
- void OpenFile(HLERequestContext& ctx);
- void OpenDirectory(HLERequestContext& ctx);
- void GetEntryType(HLERequestContext& ctx);
- void Commit(HLERequestContext& ctx);
- void GetFreeSpaceSize(HLERequestContext& ctx);
- void GetTotalSpaceSize(HLERequestContext& ctx);
- void GetFileTimeStampRaw(HLERequestContext& ctx);
- void GetFileSystemAttribute(HLERequestContext& ctx);
+ explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
+
+ Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
+ s64 size);
+ Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result DeleteDirectoryRecursively(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result CleanDirectoryRecursively(
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
+ Result OpenFile(OutInterface<IFile> out_interface,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
+ Result OpenDirectory(OutInterface<IDirectory> out_interface,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
+ u32 mode);
+ Result GetEntryType(Out<u32> out_type,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result Commit();
+ Result GetFreeSpaceSize(Out<s64> out_size,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result GetTotalSpaceSize(Out<s64> out_size,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
+ const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
+ Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
private:
- VfsDirectoryServiceWrapper backend;
- SizeGetter size;
+ std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
+ SizeGetter size_getter;
};
} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
+
+namespace Service::FileSystem {
+
+IMultiCommitManager::IMultiCommitManager(Core::System& system_)
+ : ServiceFramework{system_, "IMultiCommitManager"} {
+ static const FunctionInfo functions[] = {
+ {1, D<&IMultiCommitManager::Add>, "Add"},
+ {2, D<&IMultiCommitManager::Commit>, "Commit"},
+ };
+ RegisterHandlers(functions);
+}
+
+IMultiCommitManager::~IMultiCommitManager() = default;
+
+Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ R_SUCCEED();
+}
+
+Result IMultiCommitManager::Commit() {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
+public:
+ explicit IMultiCommitManager(Core::System& system_);
+ ~IMultiCommitManager() override;
+
+private:
+ Result Add(std::shared_ptr<IFileSystem> filesystem);
+ Result Commit();
+
+ FileSys::VirtualFile backend;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/hex_util.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
+
+namespace Service::FileSystem {
+
+ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
+ std::shared_ptr<SaveDataController> save_data_controller_,
+ FileSys::SaveDataSpaceId space)
+ : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
+ save_data_controller_} {
+ static const FunctionInfo functions[] = {
+ {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+}
+
+ISaveDataInfoReader::~ISaveDataInfoReader() = default;
+
+static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16) {
+ return 0;
+ }
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+}
+
+Result ISaveDataInfoReader::ReadSaveDataInfo(
+ Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
+ LOG_DEBUG(Service_FS, "called");
+
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = out_entries.size();
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ std::memcpy(out_entries.data(), begin, range_size);
+ *out_count = actual_entries;
+
+ R_SUCCEED();
+}
+
+void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
+ FileSys::VirtualDir save_root{};
+ const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
+
+ if (result != ResultSuccess || save_root == nullptr) {
+ LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
+ return;
+ }
+
+ for (const auto& type : save_root->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ FindNormalSaves(space, type);
+ } else if (space == FileSys::SaveDataSpaceId::Temporary) {
+ FindTemporaryStorageSaves(space, type);
+ }
+ }
+}
+
+void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
+ const FileSys::VirtualDir& type) {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ // Skip non user id subdirectories
+ if (user_id->GetName().size() != 0x20) {
+ continue;
+ }
+
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::System,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+}
+
+void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
+ const FileSys::VirtualDir& type) {
+ for (const auto& user_id : type->GetSubdirectories()) {
+ // Skip non user id subdirectories
+ if (user_id->GetName().size() != 0x20) {
+ continue;
+ }
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::Temporary,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class SaveDataController;
+
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(Core::System& system_,
+ std::shared_ptr<SaveDataController> save_data_controller_,
+ FileSys::SaveDataSpaceId space);
+ ~ISaveDataInfoReader() override;
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ u16_le index;
+ FileSys::SaveDataRank rank;
+ INSERT_PADDING_BYTES(0x25);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ Result ReadSaveDataInfo(Out<u64> out_count,
+ OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
+
+private:
+ void FindAllSaves(FileSys::SaveDataSpaceId space);
+ void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
+ void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
+
+ std::shared_ptr<SaveDataController> save_data_controller;
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
+} // 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 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/errors.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
-#include "core/hle/service/ipc_helpers.h"
namespace Service::FileSystem {
IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
: ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
- {0, &IStorage::Read, "Read"},
+ {0, D<&IStorage::Read>, "Read"},
{1, nullptr, "Write"},
{2, nullptr, "Flush"},
{3, nullptr, "SetSize"},
- {4, &IStorage::GetSize, "GetSize"},
+ {4, D<&IStorage::GetSize>, "GetSize"},
{5, nullptr, "OperateRange"},
};
RegisterHandlers(functions);
}
-void IStorage::Read(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
+Result IStorage::Read(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
+ s64 offset, s64 length) {
LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidSize);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultInvalidOffset);
- return;
- }
+ R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
+ R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
// Read the data from the Storage backend
- std::vector<u8> output = backend->ReadBytes(length, offset);
- // Write the data to memory
- ctx.WriteBuffer(output);
+ backend->Read(out_bytes.data(), length, offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void IStorage::GetSize(HLERequestContext& ctx) {
- const u64 size = backend->GetSize();
- LOG_DEBUG(Service_FS, "called, size={}", size);
+Result IStorage::GetSize(Out<u64> out_size) {
+ *out_size = backend->GetSize();
+
+ LOG_DEBUG(Service_FS, "called, size={}", *out_size);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(size);
+ R_SUCCEED();
}
} // 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 @@
#pragma once
#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/cmif_types.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/service.h"
@@ -16,8 +17,10 @@ public:
private:
FileSys::VirtualFile backend;
- void Read(HLERequestContext& ctx);
- void GetSize(HLERequestContext& ctx);
+ Result Read(
+ OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
+ s64 offset, s64 length);
+ Result GetSize(Out<u64> out_size);
};
} // 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 @@
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
+#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
+#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
#include "core/hle/service/filesystem/fsp/fsp_srv.h"
+#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
#include "core/hle/service/filesystem/romfs_controller.h"
#include "core/hle/service/filesystem/save_data_controller.h"
#include "core/hle/service/hle_ipc.h"
@@ -39,182 +43,6 @@
#include "core/reporter.h"
namespace Service::FileSystem {
-enum class FileSystemProxyType : u8 {
- Code = 0,
- Rom = 1,
- Logo = 2,
- Control = 3,
- Manual = 4,
- Meta = 5,
- Data = 6,
- Package = 7,
- RegisteredUpdate = 8,
-};
-
-class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
-public:
- explicit ISaveDataInfoReader(Core::System& system_,
- std::shared_ptr<SaveDataController> save_data_controller_,
- FileSys::SaveDataSpaceId space)
- : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
- save_data_controller_} {
- static const FunctionInfo functions[] = {
- {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
- };
- RegisterHandlers(functions);
-
- FindAllSaves(space);
- }
-
- void ReadSaveDataInfo(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- // Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
-
- // Cap at total number of entries.
- const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
-
- // Determine data start and end
- const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
- const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
- const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
-
- next_entry_index += actual_entries;
-
- // Write the data to memory
- ctx.WriteBuffer(begin, range_size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(actual_entries);
- }
-
-private:
- static u64 stoull_be(std::string_view str) {
- if (str.size() != 16)
- return 0;
-
- const auto bytes = Common::HexStringToArray<0x8>(str);
- u64 out{};
- std::memcpy(&out, bytes.data(), sizeof(u64));
-
- return Common::swap64(out);
- }
-
- void FindAllSaves(FileSys::SaveDataSpaceId space) {
- FileSys::VirtualDir save_root{};
- const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
-
- if (result != ResultSuccess || save_root == nullptr) {
- LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
- return;
- }
-
- for (const auto& type : save_root->GetSubdirectories()) {
- if (type->GetName() == "save") {
- for (const auto& save_id : type->GetSubdirectories()) {
- for (const auto& user_id : save_id->GetSubdirectories()) {
- // Skip non user id subdirectories
- if (user_id->GetName().size() != 0x20) {
- continue;
- }
-
- const auto save_id_numeric = stoull_be(save_id->GetName());
- auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- if (save_id_numeric != 0) {
- // System Save Data
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::SystemSaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- 0,
- user_id->GetSize(),
- {},
- {},
- });
-
- continue;
- }
-
- for (const auto& title_id : user_id->GetSubdirectories()) {
- const auto device =
- std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
- [](u8 val) { return val == 0; });
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- device ? FileSys::SaveDataType::DeviceSaveData
- : FileSys::SaveDataType::SaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
- // Temporary Storage
- for (const auto& user_id : type->GetSubdirectories()) {
- // Skip non user id subdirectories
- if (user_id->GetName().size() != 0x20) {
- continue;
- }
- for (const auto& title_id : user_id->GetSubdirectories()) {
- if (!title_id->GetFiles().empty() ||
- !title_id->GetSubdirectories().empty()) {
- auto user_id_numeric =
- Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::TemporaryStorage,
- {},
- user_id_numeric,
- stoull_be(type->GetName()),
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- }
- }
- }
-
- struct SaveDataInfo {
- u64_le save_id_unknown;
- FileSys::SaveDataSpaceId space;
- FileSys::SaveDataType type;
- INSERT_PADDING_BYTES(0x6);
- std::array<u8, 0x10> user_id;
- u64_le save_id;
- u64_le title_id;
- u64_le save_image_size;
- u16_le index;
- FileSys::SaveDataRank rank;
- INSERT_PADDING_BYTES(0x25);
- };
- static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
-
- ProcessId process_id = 0;
- std::shared_ptr<SaveDataController> save_data_controller;
- std::vector<SaveDataInfo> info;
- u64 next_entry_index = 0;
-};
FSP_SRV::FSP_SRV(Core::System& system_)
: ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +50,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
- {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
+ {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
{2, nullptr, "OpenDataFileSystemByCurrentProcess"},
- {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
+ {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
{8, nullptr, "OpenFileSystemWithId"},
{9, nullptr, "OpenDataFileSystemByApplicationId"},
{11, nullptr, "OpenBisFileSystem"},
{12, nullptr, "OpenBisStorage"},
{13, nullptr, "InvalidateBisCache"},
{17, nullptr, "OpenHostFileSystem"},
- {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
+ {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
{19, nullptr, "FormatSdCardFileSystem"},
{21, nullptr, "DeleteSaveDataFileSystem"},
- {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
- {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"},
+ {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
+ {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
{24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
{25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
{26, nullptr, "FormatSdCardDryRun"},
@@ -245,30 +73,30 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{31, nullptr, "OpenGameCardFileSystem"},
{32, nullptr, "ExtendSaveDataFileSystem"},
{33, nullptr, "DeleteCacheStorage"},
- {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"},
+ {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
{35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
{36, nullptr, "OpenHostFileSystemWithOption"},
- {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
- {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"},
- {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
+ {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
+ {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
+ {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
{57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
- {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
- {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
+ {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
- {67, nullptr, "FindSaveDataWithFilter"},
+ {67, D<&FSP_SRV::FindSaveDataWithFilter>, "FindSaveDataWithFilter"},
{68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
{69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
+ {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
+ {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
{80, nullptr, "OpenSaveDataMetaFile"},
{81, nullptr, "OpenSaveDataTransferManager"},
{82, nullptr, "OpenSaveDataTransferManagerVersion2"},
- {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
+ {83, D<&FSP_SRV::OpenSaveDataTransferProhibiter>, "OpenSaveDataTransferProhibiter"},
{84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
{85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
{86, nullptr, "OpenSaveDataMover"},
@@ -279,12 +107,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{110, nullptr, "OpenContentStorageFileSystem"},
{120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
{130, nullptr, "OpenCustomStorageFileSystem"},
- {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
+ {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
{201, nullptr, "OpenDataStorageByProgramId"},
- {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
- {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
+ {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
+ {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
{204, nullptr, "OpenDataFileSystemByProgramIndex"},
- {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
+ {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
{206, nullptr, "OpenDataStorageByPath"},
{400, nullptr, "OpenDeviceOperator"},
{500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +152,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{1000, nullptr, "SetBisRootForHost"},
{1001, nullptr, "SetSaveDataSize"},
{1002, nullptr, "SetSaveDataRootPath"},
- {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"},
- {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
- {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
- {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
+ {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
+ {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
+ {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
+ {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
{1007, nullptr, "RegisterUpdatePartition"},
{1008, nullptr, "OpenRegisteredUpdatePartition"},
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1010, nullptr, "SetDataStorageRedirectTarget"},
- {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
+ {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
{1012, nullptr, "GetFsStackUsage"},
{1013, nullptr, "UnsetSaveDataRootPath"},
{1014, nullptr, "OutputMultiProgramTagAccessLog"},
- {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"},
+ {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
{1017, nullptr, "OutputApplicationInfoAccessLog"},
{1018, nullptr, "SetDebugOption"},
{1019, nullptr, "UnsetDebugOption"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
{1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
- {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
+ {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
{1300, nullptr, "OpenBisWiper"},
};
// clang-format on
@@ -355,234 +183,192 @@ FSP_SRV::FSP_SRV(Core::System& system_)
FSP_SRV::~FSP_SRV() = default;
-void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
- current_process_id = ctx.GetPID();
+Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
+ current_process_id = *pid;
LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
- const auto res =
- fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(res);
+ R_RETURN(
+ fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
}
-void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct InputParameters {
- FileSystemProxyType type;
- u64 program_id;
- };
- static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
-
- const auto params = rp.PopRaw<InputParameters>();
- LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
- params.program_id);
+Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
+ FileSystemProxyType type, u64 open_program_id) {
+ LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
+ open_program_id);
// FIXME: many issues with this
- ASSERT(params.type == FileSystemProxyType::Manual);
+ ASSERT(type == FileSystemProxyType::Manual);
const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
- params.program_id, FileSys::ContentRecordType::HtmlDocument);
+ open_program_id, FileSys::ContentRecordType::HtmlDocument);
ASSERT(manual_romfs != nullptr);
const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
ASSERT(extracted_romfs != nullptr);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(system, extracted_romfs,
- SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
+ *out_interface = std::make_shared<IFileSystem>(
+ system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
LOG_DEBUG(Service_FS, "called");
FileSys::VirtualDir sdmc_dir{};
fsc.OpenSDMC(&sdmc_dir);
- auto filesystem = std::make_shared<IFileSystem>(
+ *out_interface = std::make_shared<IFileSystem>(
system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+ R_SUCCEED();
}
-void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
- u128 uid = rp.PopRaw<u128>();
-
+Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
+ FileSys::SaveDataAttribute save_struct, u128 uid) {
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
uid[1], uid[0]);
FileSys::VirtualDir save_data_dir{};
- save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser,
- save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
+ save_struct));
}
-void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
-
+Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
+ FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct) {
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
FileSys::VirtualDir save_data_dir{};
- save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem,
- save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
+ save_struct));
}
-void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
-
- const auto parameters = rp.PopRaw<Parameters>();
-
+Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_INFO(Service_FS, "called.");
FileSys::VirtualDir dir{};
- auto result =
- save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(FileSys::ResultTargetNotFound);
- return;
- }
+ R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
FileSys::StorageId id{};
- switch (parameters.space_id) {
- case FileSys::SaveDataSpaceId::NandUser:
+ switch (space_id) {
+ case FileSys::SaveDataSpaceId::User:
id = FileSys::StorageId::NandUser;
break;
- case FileSys::SaveDataSpaceId::SdCardSystem:
- case FileSys::SaveDataSpaceId::SdCardUser:
+ case FileSys::SaveDataSpaceId::SdSystem:
+ case FileSys::SaveDataSpaceId::SdUser:
id = FileSys::StorageId::SdCard;
break;
- case FileSys::SaveDataSpaceId::NandSystem:
+ case FileSys::SaveDataSpaceId::System:
id = FileSys::StorageId::NandSystem;
break;
- case FileSys::SaveDataSpaceId::TemporaryStorage:
+ case FileSys::SaveDataSpaceId::Temporary:
case FileSys::SaveDataSpaceId::ProperSystem:
case FileSys::SaveDataSpaceId::SafeMode:
ASSERT(false);
}
- auto filesystem =
+ *out_interface =
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+ R_SUCCEED();
}
-void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
+ R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
}
-void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) {
+Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
+ R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
}
-void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
+ OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
LOG_INFO(Service_FS, "called, space={}", space);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(
- std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
+ *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
+ OutInterface<ISaveDataInfoReader> out_interface) {
LOG_WARNING(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
- FileSys::SaveDataSpaceId::TemporaryStorage);
-}
+ *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
+ FileSys::SaveDataSpaceId::Temporary);
-void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called.");
+ R_SUCCEED();
+}
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+Result FSP_SRV::FindSaveDataWithFilter(Out<s64> out_count,
+ OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataFilter filter) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+ R_THROW(FileSys::ResultTargetNotFound);
}
-void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
+Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
+ LOG_WARNING(Service_FS, "(STUBBED) called.");
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
+ R_SUCCEED();
+}
- const auto parameters = rp.PopRaw<Parameters>();
+Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
+ FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
+ InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
// Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
- constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
+ // In an earlier version of the code, this was returned as an out argument, but this is not
+ // correct
+ [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
LOG_WARNING(Service_FS,
- "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
+ "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
"attribute.type={}, attribute.rank={}, attribute.index={}",
- flags, parameters.space_id, parameters.attribute.title_id,
- parameters.attribute.user_id[1], parameters.attribute.user_id[0],
- parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
- parameters.attribute.index);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flags);
+ flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
+ attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
+
+ R_SUCCEED();
}
-void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
+Result FSP_SRV::OpenSaveDataTransferProhibiter(
+ OutInterface<ISaveDataTransferProhibiter> out_prohibiter, u64 id) {
+ LOG_WARNING(Service_FS, "(STUBBED) called, id={:016X}", id);
+ *out_prohibiter = std::make_shared<ISaveDataTransferProhibiter>(system);
+ R_SUCCEED();
+}
+
+Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
LOG_DEBUG(Service_FS, "called");
if (!romfs) {
auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
if (!current_romfs) {
// TODO (bunnei): Find the right error code to use here
- LOG_CRITICAL(Service_FS, "no file system interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ LOG_CRITICAL(Service_FS, "No file system interface available!");
+ R_RETURN(ResultUnknown);
}
romfs = current_romfs;
}
- auto storage = std::make_shared<IStorage>(system, romfs);
+ *out_interface = std::make_shared<IStorage>(system, romfs);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ R_SUCCEED();
}
-void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto unknown = rp.PopRaw<u32>();
- const auto title_id = rp.PopRaw<u64>();
-
+Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
storage_id, unknown, title_id);
@@ -592,19 +378,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
if (archive != nullptr) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
- return;
+ *out_interface = std::make_shared<IStorage>(system, archive);
+ R_SUCCEED();
}
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
- "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
+ "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
storage_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ R_RETURN(ResultUnknown);
}
const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +396,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
auto storage = std::make_shared<IStorage>(
system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ *out_interface = std::move(storage);
+ R_SUCCEED();
}
-void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto title_id = rp.PopRaw<u64>();
-
- LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
+Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u64 title_id) {
+ LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
+ title_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ResultTargetNotFound);
+ R_RETURN(FileSys::ResultTargetNotFound);
}
-void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto program_index = rp.PopRaw<u8>();
-
+Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
+ u8 program_index) {
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +417,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
if (!patched_romfs) {
// TODO: Find the right error code to use here
- LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
+ LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
+ R_RETURN(ResultUnknown);
}
- auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
+ *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
+ R_SUCCEED();
}
-void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
+Result FSP_SRV::DisableAutoSaveDataCreation() {
LOG_DEBUG(Service_FS, "called");
save_data_controller->SetAutoCreate(false);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- access_log_mode = rp.PopEnum<AccessLogMode>();
+Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
+ LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
- LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode);
+ access_log_mode = access_log_mode_;
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) {
+Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(access_log_mode);
-}
+ *out_access_log_mode = access_log_mode;
-void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
- const auto raw = ctx.ReadBufferCopy();
- auto log = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(raw.data()), raw.size());
+ R_SUCCEED();
+}
+Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
LOG_DEBUG(Service_FS, "called");
+ auto log = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
reporter.SaveFSAccessLog(log);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
+Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
+ Out<u32> out_access_log_program_index) {
+ LOG_DEBUG(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(AccessLogVersion::Latest);
- rb.Push(access_log_program_index);
+ *out_access_log_version = AccessLogVersion::Latest;
+ *out_access_log_program_index = access_log_program_index;
+
+ R_SUCCEED();
}
-void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) {
+Result FSP_SRV::FlushAccessLogOnSdCard() {
LOG_DEBUG(Service_FS, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ R_SUCCEED();
}
-void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto index{rp.Pop<s32>()};
-
+Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(ResultSuccess);
- rb.Push(s64{0});
- rb.Push(s64{0});
-}
-
-class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
-public:
- explicit IMultiCommitManager(Core::System& system_)
- : ServiceFramework{system_, "IMultiCommitManager"} {
- static const FunctionInfo functions[] = {
- {1, &IMultiCommitManager::Add, "Add"},
- {2, &IMultiCommitManager::Commit, "Commit"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- FileSys::VirtualFile backend;
-
- void Add(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
+ *out_data_size = 0;
+ *out_journal_size = 0;
- void Commit(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
+ R_SUCCEED();
+}
-void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) {
+Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
LOG_DEBUG(Service_FS, "called");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
+ *out_interface = std::make_shared<IMultiCommitManager>(system);
+
+ R_SUCCEED();
}
} // 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 @@
#pragma once
#include <memory>
+#include "core/file_sys/fs_save_data_types.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/filesystem/fsp/fsp_types.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -20,6 +23,12 @@ namespace Service::FileSystem {
class RomFsController;
class SaveDataController;
+class IFileSystem;
+class ISaveDataInfoReader;
+class ISaveDataTransferProhibiter;
+class IStorage;
+class IMultiCommitManager;
+
enum class AccessLogVersion : u32 {
V7_0_0 = 2,
@@ -38,30 +47,51 @@ public:
~FSP_SRV() override;
private:
- void SetCurrentProcess(HLERequestContext& ctx);
- void OpenFileSystemWithPatch(HLERequestContext& ctx);
- void OpenSdCardFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenSaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
- void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
- void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
- void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageByDataId(HLERequestContext& ctx);
- void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageWithProgramIndex(HLERequestContext& ctx);
- void DisableAutoSaveDataCreation(HLERequestContext& ctx);
- void SetGlobalAccessLogMode(HLERequestContext& ctx);
- void GetGlobalAccessLogMode(HLERequestContext& ctx);
- void OutputAccessLogToSdCard(HLERequestContext& ctx);
- void FlushAccessLogOnSdCard(HLERequestContext& ctx);
- void GetProgramIndexForAccessLog(HLERequestContext& ctx);
- void OpenMultiCommitManager(HLERequestContext& ctx);
- void GetCacheStorageSize(HLERequestContext& ctx);
+ Result SetCurrentProcess(ClientProcessId pid);
+ Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
+ FileSystemProxyType type, u64 open_program_id);
+ Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
+ Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
+ FileSys::SaveDataAttribute save_struct, u128 uid);
+ Result CreateSaveDataFileSystemBySystemSaveDataId(
+ FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct);
+ Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataAttribute attribute);
+ Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
+ FileSys::SaveDataSpaceId space);
+ Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
+ Result FindSaveDataWithFilter(Out<s64> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
+ FileSys::SaveDataSpaceId space_id,
+ FileSys::SaveDataFilter filter);
+ Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
+ Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
+ FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
+ InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
+ OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
+ Result OpenSaveDataTransferProhibiter(OutInterface<ISaveDataTransferProhibiter> out_prohibiter,
+ u64 id);
+ Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
+ Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u32 unknown, u64 title_id);
+ Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
+ FileSys::StorageId storage_id, u64 title_id);
+ Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
+ Result DisableAutoSaveDataCreation();
+ Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
+ Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
+ Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
+ Result FlushAccessLogOnSdCard();
+ Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
+ Out<u32> out_access_log_program_index);
+ Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
+ Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
FileSystemController& fsc;
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 @@
namespace Service::FileSystem {
+enum class FileSystemProxyType : u8 {
+ Code = 0,
+ Rom = 1,
+ Logo = 2,
+ Control = 3,
+ Manual = 4,
+ Meta = 5,
+ Data = 6,
+ Package = 7,
+ RegisteredUpdate = 8,
+};
+
struct SizeGetter {
std::function<u64()> get_free_size;
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
+
+namespace Service::FileSystem {
+
+ISaveDataTransferProhibiter::ISaveDataTransferProhibiter(Core::System& system_)
+ : ServiceFramework{system_, "ISaveDataTransferProhibiter"} {}
+
+ISaveDataTransferProhibiter::~ISaveDataTransferProhibiter() = default;
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class ISaveDataTransferProhibiter : public ServiceFramework<ISaveDataTransferProhibiter> {
+public:
+ explicit ISaveDataTransferProhibiter(Core::System& system_);
+ ~ISaveDataTransferProhibiter() override;
+};
+
+} // 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:
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
{10702, nullptr, "AddPlayHistory"},
{11000, nullptr, "GetProfileImageUrl"},
- {20100, nullptr, "GetFriendCount"},
- {20101, nullptr, "GetNewlyFriendCount"},
+ {20100, &IFriendService::GetFriendCount, "GetFriendCount"},
+ {20101, &IFriendService::GetNewlyFriendCount, "GetNewlyFriendCount"},
{20102, nullptr, "GetFriendDetailedInfo"},
{20103, nullptr, "SyncFriendList"},
{20104, nullptr, "RequestSyncFriendList"},
{20110, nullptr, "LoadFriendSetting"},
- {20200, nullptr, "GetReceivedFriendRequestCount"},
+ {20200, &IFriendService::GetReceivedFriendRequestCount, "GetReceivedFriendRequestCount"},
{20201, nullptr, "GetFriendRequestList"},
{20300, nullptr, "GetFriendCandidateList"},
{20301, nullptr, "GetNintendoNetworkIdInfo"},
@@ -61,14 +61,14 @@ public:
{20501, nullptr, "GetRelationship"},
{20600, nullptr, "GetUserPresenceView"},
{20700, nullptr, "GetPlayHistoryList"},
- {20701, nullptr, "GetPlayHistoryStatistics"},
+ {20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"},
{20800, nullptr, "LoadUserSetting"},
{20801, nullptr, "SyncUserSetting"},
{20900, nullptr, "RequestListSummaryOverlayNotification"},
{21000, nullptr, "GetExternalApplicationCatalog"},
{22000, nullptr, "GetReceivedFriendInvitationList"},
{22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
- {22010, nullptr, "GetReceivedFriendInvitationCountCache"},
+ {22010, &IFriendService::GetReceivedFriendInvitationCountCache, "GetReceivedFriendInvitationCountCache"},
{30100, nullptr, "DropFriendNewlyFlags"},
{30101, nullptr, "DeleteFriend"},
{30110, nullptr, "DropFriendNewlyFlag"},
@@ -144,6 +144,33 @@ private:
rb.PushCopyObjects(completion_event->GetReadableEvent());
}
+ void GetFriendList(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto friend_offset = rp.Pop<u32>();
+ const auto uuid = rp.PopRaw<Common::UUID>();
+ [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
+ const auto pid = rp.Pop<u64>();
+ LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
+ uuid.RawString(), pid);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+
+ rb.Push<u32>(0); // Friend count
+ // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
+ }
+
+ void CheckFriendListAvailability(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto uuid{rp.PopRaw<Common::UUID>()};
+
+ LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(true);
+ }
+
void GetBlockedUserListIds(HLERequestContext& ctx) {
// This is safe to stub, as there should be no adverse consequences from reporting no
// blocked users.
@@ -153,6 +180,17 @@ private:
rb.Push<u32>(0); // Indicates there are no blocked users
}
+ void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto uuid{rp.PopRaw<Common::UUID>()};
+
+ LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(true);
+ }
+
void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_Friend, "(STUBBED) called");
@@ -179,42 +217,43 @@ private:
rb.Push(ResultSuccess);
}
- void GetFriendList(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto friend_offset = rp.Pop<u32>();
- const auto uuid = rp.PopRaw<Common::UUID>();
- [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
- const auto pid = rp.Pop<u64>();
- LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
- uuid.RawString(), pid);
+ void GetFriendCount(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
-
- rb.Push<u32>(0); // Friend count
- // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
+ rb.Push(0);
}
- void CheckFriendListAvailability(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto uuid{rp.PopRaw<Common::UUID>()};
+ void GetNewlyFriendCount(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Friend, "(STUBBED) called");
- LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(0);
+ }
+
+ void GetReceivedFriendRequestCount(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(true);
+ rb.Push(0);
}
- void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto uuid{rp.PopRaw<Common::UUID>()};
+ void GetPlayHistoryStatistics(HLERequestContext& ctx) {
+ LOG_ERROR(Service_Friend, "(STUBBED) called, check in out");
- LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push(true);
+ rb.Push(0);
}
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) {
}
Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
+ };
R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value));
}
Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
Out<bool> out_automatic_correction) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction);
- });
+ };
R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
out_automatic_correction));
@@ -166,21 +168,27 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
}
Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year);
+ };
R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time",
"standard_user_clock_initial_year"));
}
Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
+ };
R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
}
Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
+ };
R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
out_time_point));
@@ -188,15 +196,18 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
+ };
R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
}
Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
Service::PSC::Time::TimeType type) {
- SCOPE_EXIT(
- { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
+ };
R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
}
@@ -205,11 +216,11 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
const Service::PSC::Time::SystemClockContext& user_context,
const Service::PSC::Time::SystemClockContext& network_context) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. type={} out_snapshot={} user_context={} network_context={}", type,
*out_snapshot, user_context, network_context);
- });
+ };
R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(
type, out_snapshot, user_context, network_context));
@@ -218,14 +229,18 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time,
InClockSnapshot a,
InClockSnapshot b) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
+ };
R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
}
Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
InClockSnapshot b) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
+ };
R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
}
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;
Result TimeZoneService::GetDeviceLocationName(
Out<Service::PSC::Time::LocationName> out_location_name) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
+ };
R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
}
@@ -94,7 +96,9 @@ Result TimeZoneService::SetDeviceLocationName(
}
Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
+ };
R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
}
@@ -102,10 +106,10 @@ Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
Result TimeZoneService::LoadLocationNameList(
Out<u32> out_count,
OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
index, *out_count, out_names[0], out_names[1]);
- });
+ };
std::scoped_lock l{m_mutex};
R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
@@ -124,7 +128,9 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
Result TimeZoneService::GetTimeZoneRuleVersion(
Out<Service::PSC::Time::RuleVersion> out_rule_version) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
+ };
R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
}
@@ -132,10 +138,10 @@ Result TimeZoneService::GetTimeZoneRuleVersion(
Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
Out<Service::PSC::Time::LocationName> location_name,
Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name,
*out_time_point);
- });
+ };
R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point));
}
@@ -178,10 +184,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
Result TimeZoneService::ToCalendarTime(
Out<Service::PSC::Time::CalendarTime> out_calendar_time,
Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
*out_calendar_time, *out_additional_info);
- });
+ };
R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
}
@@ -189,10 +195,10 @@ Result TimeZoneService::ToCalendarTime(
Result TimeZoneService::ToCalendarTimeWithMyRule(
Out<Service::PSC::Time::CalendarTime> out_calendar_time,
Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
*out_calendar_time, *out_additional_info);
- });
+ };
R_RETURN(
m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
@@ -202,11 +208,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
OutArray<s64, BufferAttr_HipcPointer> out_times,
const Service::PSC::Time::CalendarTime& calendar_time,
InRule rule) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
calendar_time, *out_count, out_times[0], out_times[1]);
- });
+ };
R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
}
@@ -214,11 +220,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
Result TimeZoneService::ToPosixTimeWithMyRule(
Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
const Service::PSC::Time::CalendarTime& calendar_time) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
calendar_time, *out_count, out_times[0], out_times[1]);
- });
+ };
R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
}
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
{1269, nullptr, "DeleteButtonConfigStorageLeft"},
{1270, nullptr, "DeleteButtonConfigStorageRight"},
{1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"},
- {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
+ {1272, &IHidSystemServer::IsAnyCustomButtonConfigEnabled, "IsAnyCustomButtonConfigEnabled"},
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
{1274, nullptr, "SetDefaultButtonConfig"},
{1275, nullptr, "SetAllDefaultButtonConfig"},
@@ -926,6 +926,16 @@ void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
rb.Push(is_enabled);
}
+void IHidSystemServer::IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx) {
+ const bool is_enabled = false;
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+}
+
std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
resource_manager->Initialize();
return resource_manager;
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 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:
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
void SetForceHandheldStyleVibration(HLERequestContext& ctx);
void IsUsingCustomButtonConfig(HLERequestContext& ctx);
+ void IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx);
std::shared_ptr<ResourceManager> GetResourceManager();
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:
explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "SaveCurrentSetting"},
- {1, nullptr, "LoadCurrentSetting"},
+ {0, &LBL::SaveCurrentSetting, "SaveCurrentSetting"},
+ {1, &LBL::LoadCurrentSetting, "LoadCurrentSetting"},
{2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"},
{3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"},
{4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
@@ -47,7 +47,7 @@ public:
{26, &LBL::EnableVrMode, "EnableVrMode"},
{27, &LBL::DisableVrMode, "DisableVrMode"},
{28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
- {29, nullptr, "IsAutoBrightnessControlSupported"},
+ {29, &LBL::IsAutoBrightnessControlSupported, "IsAutoBrightnessControlSupported"},
};
// clang-format on
@@ -60,6 +60,20 @@ private:
On = 1,
};
+ void SaveCurrentSetting(HLERequestContext& ctx) {
+ LOG_WARNING(Service_LBL, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void LoadCurrentSetting(HLERequestContext& ctx) {
+ LOG_WARNING(Service_LBL, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
void SetCurrentBrightnessSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto brightness = rp.Pop<float>();
@@ -310,6 +324,14 @@ private:
rb.Push(vr_mode_enabled);
}
+ void IsAutoBrightnessControlSupported(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LBL, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u8>(auto_brightness_supported);
+ }
+
bool vr_mode_enabled = false;
float current_brightness = 1.0f;
float ambient_light_value = 0.0f;
@@ -317,7 +339,8 @@ private:
bool dimming = true;
bool backlight_enabled = true;
bool update_instantly = false;
- bool auto_brightness = false; // TODO(ogniK): Move to system settings
+ bool auto_brightness = false;
+ bool auto_brightness_supported = true; // TODO(ogniK): Move to system settings
};
void 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 @@
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/psc/time/steady_clock.h"
#include "core/hle/service/service.h"
+#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/hid_types.h"
#include "hid_core/hid_util.h"
@@ -32,6 +33,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
}
is_initialized = false;
+
+ m_set_sys =
+ system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
}
DeviceManager ::~DeviceManager() {
@@ -774,8 +778,8 @@ Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const
}
Result DeviceManager::IsNfcEnabled() const {
- // TODO: This calls nn::settings::detail::GetNfcEnableFlag
- const bool is_enabled = true;
+ bool is_enabled{};
+ R_TRY(m_set_sys->GetNfcEnableFlag(&is_enabled));
if (!is_enabled) {
return ResultNfcDisabled;
}
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 @@
#include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
+namespace Service::Set {
+class ISystemSettingsServer;
+}
+
namespace Service::NFC {
class NfcDevice;
@@ -98,6 +102,7 @@ private:
Core::System& system;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* availability_change_event;
+ std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};
} // 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:
{1, &NfcInterface::Finalize, "FinalizeOld"},
{2, &NfcInterface::GetState, "GetStateOld"},
{3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
- {100, nullptr, "SetNfcEnabledOld"},
+ {100, &NfcInterface::SetNfcEnabled, "SetNfcEnabledOld"},
{400, &NfcInterface::Initialize, "Initialize"},
{401, &NfcInterface::Finalize, "Finalize"},
{402, &NfcInterface::GetState, "GetState"},
@@ -71,7 +71,7 @@ public:
{410, &NfcInterface::GetTagInfo, "GetTagInfo"},
{411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
{412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
- {500, nullptr, "SetNfcEnabled"},
+ {500, &NfcInterface::SetNfcEnabled, "SetNfcEnabled"},
{510, nullptr, "OutputTestWave"},
{1000, &NfcInterface::ReadMifare, "ReadMifare"},
{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 @@
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_result.h"
+#include "core/hle/service/set/system_settings_server.h"
+#include "core/hle/service/sm/sm.h"
#include "hid_core/hid_types.h"
namespace Service::NFC {
NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
: ServiceFramework{system_, name}, service_context{system_, service_name},
- backend_type{service_backend} {}
+ backend_type{service_backend} {
+ m_set_sys =
+ system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
+}
NfcInterface ::~NfcInterface() = default;
@@ -65,11 +70,11 @@ void NfcInterface::GetState(HLERequestContext& ctx) {
void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
- // TODO: This calls nn::settings::detail::GetNfcEnableFlag
- const bool is_enabled = true;
+ bool is_enabled{};
+ const auto result = m_set_sys->GetNfcEnableFlag(&is_enabled);
IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
+ rb.Push(result);
rb.Push(is_enabled);
}
@@ -212,6 +217,17 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
rb.PushCopyObjects(out_event);
}
+void NfcInterface::SetNfcEnabled(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto is_enabled{rp.Pop<bool>()};
+ LOG_DEBUG(Service_NFC, "called, is_enabled={}", is_enabled);
+
+ const auto result = m_set_sys->SetNfcEnableFlag(is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
void NfcInterface::ReadMifare(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
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 @@
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/service.h"
+namespace Service::Set {
+class ISystemSettingsServer;
+}
+
namespace Service::NFC {
class DeviceManager;
@@ -29,6 +33,7 @@ public:
void AttachActivateEvent(HLERequestContext& ctx);
void AttachDeactivateEvent(HLERequestContext& ctx);
void ReadMifare(HLERequestContext& ctx);
+ void SetNfcEnabled(HLERequestContext& ctx);
void WriteMifare(HLERequestContext& ctx);
void SendCommandByPassThrough(HLERequestContext& ctx);
@@ -44,6 +49,7 @@ protected:
BackendType backend_type;
State state{State::NonInitialized};
std::shared_ptr<DeviceManager> device_manager = nullptr;
+ std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};
} // 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 @@
#include <memory>
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/npns/npns.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::NPNS {
-class NPNS_S final : public ServiceFramework<NPNS_S> {
+class INpnsSystem final : public ServiceFramework<INpnsSystem> {
public:
- explicit NPNS_S(Core::System& system_) : ServiceFramework{system_, "npns:s"} {
+ explicit INpnsSystem(Core::System& system_)
+ : ServiceFramework{system_, "npns:s"}, service_context{system, "npns:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "ListenAll"},
- {2, nullptr, "ListenTo"},
+ {2, C<&INpnsSystem::ListenTo>, "ListenTo"},
{3, nullptr, "Receive"},
{4, nullptr, "ReceiveRaw"},
- {5, nullptr, "GetReceiveEvent"},
+ {5, C<&INpnsSystem::GetReceiveEvent>, "GetReceiveEvent"},
{6, nullptr, "ListenUndelivered"},
{7, nullptr, "GetStateChangeEVent"},
{11, nullptr, "SubscribeTopic"},
@@ -59,12 +63,34 @@ public:
// clang-format on
RegisterHandlers(functions);
+
+ get_receive_event = service_context.CreateEvent("npns:s:GetReceiveEvent");
}
+
+ ~INpnsSystem() override {
+ service_context.CloseEvent(get_receive_event);
+ }
+
+private:
+ Result ListenTo(u32 program_id) {
+ LOG_WARNING(Service_AM, "(STUBBED) called, program_id={}", program_id);
+ R_SUCCEED();
+ }
+
+ Result GetReceiveEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ *out_event = &get_receive_event->GetReadableEvent();
+ R_SUCCEED();
+ }
+
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* get_receive_event;
};
-class NPNS_U final : public ServiceFramework<NPNS_U> {
+class INpnsUser final : public ServiceFramework<INpnsUser> {
public:
- explicit NPNS_U(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
+ explicit INpnsUser(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{1, nullptr, "ListenAll"},
@@ -97,8 +123,8 @@ public:
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("npns:s", std::make_shared<NPNS_S>(system));
- server_manager->RegisterNamedService("npns:u", std::make_shared<NPNS_U>(system));
+ server_manager->RegisterNamedService("npns:s", std::make_shared<INpnsSystem>(system));
+ server_manager->RegisterNamedService("npns:u", std::make_shared<INpnsUser>(system));
ServerManager::RunServer(std::move(server_manager));
}
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(
Result IApplicationManagerInterface::GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
- Common::UUID account_id, u32 flags, u64 application_id) {
+ u32 flags, u64 application_id, Uid account_id) {
LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
- flags, application_id, account_id.FormattedString());
+ flags, application_id, account_id.uuid.FormattedString());
if (!out_rights.empty()) {
ApplicationRightsOnClient rights{};
rights.application_id = application_id;
- rights.uid = account_id;
+ rights.uid = account_id.uuid;
rights.flags = 0;
rights.flags2 = 0;
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:
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result GetApplicationRightsOnClient(
OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
- Common::UUID account_id, u32 flags, u64 application_id);
+ u32 flags, u64 application_id, Uid account_id);
Result CheckSdCardMountStatus();
Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
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 {
};
static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size.");
+struct Uid {
+ alignas(8) Common::UUID uuid;
+};
+static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size.");
+
} // 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_,
IQueryService::~IQueryService() = default;
Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
- Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id,
- u64 application_id) {
+ Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id) {
// TODO(German77): Read statistics of the game
*out_play_statistics = {
.application_id = application_id,
@@ -50,7 +49,7 @@ Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
};
LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}",
- unknown, application_id, account_id.FormattedString());
+ unknown, application_id, account_id.uuid.FormattedString());
R_SUCCEED();
}
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 @@
#include "common/uuid.h"
#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/service.h"
namespace Service::NS {
@@ -29,8 +30,7 @@ public:
private:
Result QueryPlayStatisticsByApplicationIdAndUserAccountId(
- Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id,
- u64 application_id);
+ Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id);
};
} // 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
bool must_unmark_fail = !is_allocation;
const u32 event_id = params.value.raw;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (must_unmark_fail) {
events[event_id].fails = 0;
}
- });
+ };
const u32 fence_id = static_cast<u32>(params.fence.id);
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) {
void NVDRV::Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
- SCOPE_EXIT({
+ SCOPE_EXIT {
rb.Push(ResultSuccess);
rb.PushEnum(NvResult::Success);
- });
+ };
if (is_initialized) {
// 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 @@
#pragma once
-#include <list>
-
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
@@ -26,18 +24,12 @@ struct Layer {
};
struct LayerStack {
- std::list<Layer> layers;
-};
-
-struct Display {
- explicit Display(u64 id_) {
- id = id_;
- }
+ std::vector<std::shared_ptr<Layer>> layers;
- Layer* FindLayer(s32 consumer_id) {
- for (auto& layer : stack.layers) {
- if (layer.consumer_id == consumer_id) {
- return &layer;
+ std::shared_ptr<Layer> FindLayer(s32 consumer_id) {
+ for (auto& layer : layers) {
+ if (layer->consumer_id == consumer_id) {
+ return layer;
}
}
@@ -45,7 +37,13 @@ struct Display {
}
bool HasLayers() {
- return !stack.layers.empty();
+ return !layers.empty();
+ }
+};
+
+struct Display {
+ explicit Display(u64 id_) {
+ id = id_;
}
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,
// Acquire all necessary framebuffers.
for (auto& layer : display.stack.layers) {
- auto consumer_id = layer.consumer_id;
+ auto consumer_id = layer->consumer_id;
// Try to fetch the framebuffer (either new or stale).
- const auto result = this->CacheFramebufferLocked(layer, consumer_id);
+ const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
// If we failed, skip this layer.
if (result == CacheStatus::NoBufferAvailable) {
@@ -75,7 +75,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
const auto& igbp_buffer = *item.graphic_buffer;
// TODO: get proper Z-index from layer
- if (layer.visible) {
+ if (layer->visible) {
composition_stack.emplace_back(HwcLayer{
.buffer_handle = igbp_buffer.BufferId(),
.offset = igbp_buffer.Offset(),
@@ -84,7 +84,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
.height = igbp_buffer.Height(),
.stride = igbp_buffer.Stride(),
.z_index = 0,
- .blending = layer.blending,
+ .blending = layer->blending,
.transform = static_cast<android::BufferTransformFlags>(item.transform),
.crop_rect = item.crop,
.acquire_fence = item.fence,
@@ -134,7 +134,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
continue;
}
- if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
+ if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
@@ -153,7 +153,7 @@ void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_i
}
// Try to release the buffer item.
- auto* const layer = display.FindLayer(consumer_id);
+ const auto layer = display.stack.FindLayer(consumer_id);
if (layer && it->second.is_acquired) {
layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
}
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) {
bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
u64 display_id) {
auto* const display = this->FindDisplay(display_id);
- if (!display || !display->HasLayers()) {
+ if (!display || !display->stack.HasLayers()) {
return false;
}
@@ -46,19 +46,34 @@ bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_spe
return true;
}
-void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
- auto* const display = this->FindDisplay(display_id);
+void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) {
auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
m_server.TryGetBinder(consumer_binder_id));
-
- if (!display || !binder) {
+ if (!binder) {
return;
}
auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
buffer_item_consumer->Connect(false);
- display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id);
+ m_layers.layers.emplace_back(
+ std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id));
+}
+
+void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) {
+ std::erase_if(m_layers.layers,
+ [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
+}
+
+void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
+ auto* const display = this->FindDisplay(display_id);
+ auto layer = this->FindLayer(consumer_binder_id);
+
+ if (!display || !layer) {
+ return;
+ }
+
+ display->stack.layers.emplace_back(std::move(layer));
}
void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
@@ -69,18 +84,18 @@ void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_bi
m_composer.RemoveLayerLocked(*display, consumer_binder_id);
std::erase_if(display->stack.layers,
- [&](auto& layer) { return layer.consumer_id == consumer_binder_id; });
+ [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
}
void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
- if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
+ if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->visible = visible;
return;
}
}
void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
- if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
+ if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
layer->blending = blending;
return;
}
@@ -96,9 +111,9 @@ Display* SurfaceFlinger::FindDisplay(u64 display_id) {
return nullptr;
}
-Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
- for (auto& display : m_displays) {
- if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) {
+std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
+ for (auto& layer : m_layers.layers) {
+ if (layer->consumer_id == consumer_binder_id) {
return layer;
}
}
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:
void RemoveDisplay(u64 display_id);
bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
+ void CreateLayer(s32 consumer_binder_id);
+ void DestroyLayer(s32 consumer_binder_id);
+
void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
@@ -44,7 +47,7 @@ public:
private:
Display* FindDisplay(u64 display_id);
- Layer* FindLayer(s32 consumer_binder_id);
+ std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
public:
// TODO: these don't belong here
@@ -57,6 +60,7 @@ private:
KernelHelpers::ServiceContext m_context;
std::vector<Display> m_displays;
+ LayerStack m_layers;
std::shared_ptr<Nvidia::Module> nvdrv;
s32 disp_fd;
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/daemon_controller.h"
+
+namespace Service::OLSC {
+
+IDaemonController::IDaemonController(Core::System& system_)
+ : ServiceFramework{system_, "IDaemonController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IDaemonController::GetAutoTransferEnabledForAccountAndApplication>, "GetAutoTransferEnabledForAccountAndApplication"},
+ {1, nullptr, "SetAutoTransferEnabledForAccountAndApplication"},
+ {2, nullptr, "GetGlobalUploadEnabledForAccount"},
+ {3, nullptr, "SetGlobalUploadEnabledForAccount"},
+ {4, nullptr, "TouchAccount"},
+ {5, nullptr, "GetGlobalDownloadEnabledForAccount"},
+ {6, nullptr, "SetGlobalDownloadEnabledForAccount"},
+ {10, nullptr, "GetForbiddenSaveDataIndication"},
+ {11, nullptr, "GetStopperObject"},
+ {12, nullptr, "GetState"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IDaemonController::~IDaemonController() = default;
+
+Result IDaemonController::GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
+ Common::UUID user_id,
+ u64 application_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called, user_id={} application_id={:016X}",
+ user_id.FormattedString(), application_id);
+ *out_is_enabled = false;
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/uuid.h"
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IDaemonController final : public ServiceFramework<IDaemonController> {
+public:
+ explicit IDaemonController(Core::System& system_);
+ ~IDaemonController() override;
+
+private:
+ Result GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
+ Common::UUID user_id, u64 application_id);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/native_handle_holder.h"
+
+namespace Service::OLSC {
+
+INativeHandleHolder::INativeHandleHolder(Core::System& system_)
+ : ServiceFramework{system_, "INativeHandleHolder"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&INativeHandleHolder::GetNativeHandle>, "GetNativeHandle"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+INativeHandleHolder::~INativeHandleHolder() = default;
+
+Result INativeHandleHolder::GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_event = nullptr;
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KReadableEvent;
+}
+
+namespace Service::OLSC {
+
+class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
+public:
+ explicit INativeHandleHolder(Core::System& system_);
+ ~INativeHandleHolder() override;
+
+private:
+ Result GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
+};
+
+} // 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 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/olsc/olsc.h"
+#include "core/hle/service/olsc/olsc_service_for_application.h"
+#include "core/hle/service/olsc/olsc_service_for_system_service.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::OLSC {
-class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
-public:
- explicit IOlscServiceForApplication(Core::System& system_)
- : ServiceFramework{system_, "olsc:u"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IOlscServiceForApplication::Initialize, "Initialize"},
- {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
- {13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
- {14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
- {15, nullptr, "SetCustomData"},
- {16, nullptr, "DeleteSaveDataBackupSetting"},
- {18, nullptr, "GetSaveDataBackupInfoCache"},
- {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
- {22, nullptr, "DeleteSaveDataBackupAsync"},
- {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
- {26, nullptr, "DownloadSaveDataBackupAsync"},
- {27, nullptr, "UploadSaveDataBackupAsync"},
- {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
- {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
- {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
- {9015, nullptr, "SetCustomDataForDebug"},
- {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
- {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
- {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
- {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
- {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
- {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void Initialize(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- initialized = true;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetSaveDataBackupSetting(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- // backup_setting is set to 0 since real value is unknown
- constexpr u64 backup_setting = 0;
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(backup_setting);
- }
-
- void SetSaveDataBackupSettingEnabled(HLERequestContext& ctx) {
- LOG_WARNING(Service_OLSC, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- bool initialized{};
-};
-
-class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
-public:
- explicit INativeHandleHolder(Core::System& system_)
- : ServiceFramework{system_, "INativeHandleHolder"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetNativeHandle"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
-public:
- explicit ITransferTaskListController(Core::System& system_)
- : ServiceFramework{system_, "ITransferTaskListController"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
- {6, nullptr, "Unknown6"},
- {7, nullptr, "Unknown7"},
- {8, nullptr, "GetRemoteStorageController"},
- {9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
- {12, nullptr, "Unknown12"},
- {13, nullptr, "Unknown13"},
- {14, nullptr, "Unknown14"},
- {15, nullptr, "Unknown15"},
- {16, nullptr, "Unknown16"},
- {17, nullptr, "Unknown17"},
- {18, nullptr, "Unknown18"},
- {19, nullptr, "Unknown19"},
- {20, nullptr, "Unknown20"},
- {21, nullptr, "Unknown21"},
- {22, nullptr, "Unknown22"},
- {23, nullptr, "Unknown23"},
- {24, nullptr, "Unknown24"},
- {25, nullptr, "Unknown25"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void GetNativeHandleHolder(HLERequestContext& ctx) {
- LOG_INFO(Service_OLSC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<INativeHandleHolder>(system);
- }
-};
-
-class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
-public:
- explicit IOlscServiceForSystemService(Core::System& system_)
- : ServiceFramework{system_, "olsc:s"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
- {1, nullptr, "OpenRemoteStorageController"},
- {2, nullptr, "OpenDaemonController"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
- {12, nullptr, "Unknown12"},
- {13, nullptr, "Unknown13"},
- {100, nullptr, "ListLastTransferTaskErrorInfo"},
- {101, nullptr, "GetLastErrorInfoCount"},
- {102, nullptr, "RemoveLastErrorInfoOld"},
- {103, nullptr, "GetLastErrorInfo"},
- {104, nullptr, "GetLastErrorEventHolder"},
- {105, nullptr, "GetLastTransferTaskErrorInfo"},
- {200, nullptr, "GetDataTransferPolicyInfo"},
- {201, nullptr, "RemoveDataTransferPolicyInfo"},
- {202, nullptr, "UpdateDataTransferPolicyOld"},
- {203, nullptr, "UpdateDataTransferPolicy"},
- {204, nullptr, "CleanupDataTransferPolicyInfo"},
- {205, nullptr, "RequestDataTransferPolicy"},
- {300, nullptr, "GetAutoTransferSeriesInfo"},
- {301, nullptr, "UpdateAutoTransferSeriesInfo"},
- {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
- {900, nullptr, "CleanupTransferTask"},
- {902, nullptr, "CleanupSeriesInfoType0"},
- {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
- {904, nullptr, "CleanupApplicationAutoTransferSetting"},
- {905, nullptr, "CleanupErrorHistory"},
- {906, nullptr, "SetLastError"},
- {907, nullptr, "AddSaveDataArchiveInfoType0"},
- {908, nullptr, "RemoveSeriesInfoType0"},
- {909, nullptr, "GetSeriesInfoType0"},
- {910, nullptr, "RemoveLastErrorInfo"},
- {911, nullptr, "CleanupSeriesInfoType1"},
- {912, nullptr, "RemoveSeriesInfoType1"},
- {913, nullptr, "GetSeriesInfoType1"},
- {1000, nullptr, "UpdateIssueOld"},
- {1010, nullptr, "Unknown1010"},
- {1011, nullptr, "ListIssueInfoOld"},
- {1012, nullptr, "GetIssueOld"},
- {1013, nullptr, "GetIssue2Old"},
- {1014, nullptr, "GetIssue3Old"},
- {1020, nullptr, "RepairIssueOld"},
- {1021, nullptr, "RepairIssueWithUserIdOld"},
- {1022, nullptr, "RepairIssue2Old"},
- {1023, nullptr, "RepairIssue3Old"},
- {1024, nullptr, "Unknown1024"},
- {1100, nullptr, "UpdateIssue"},
- {1110, nullptr, "Unknown1110"},
- {1111, nullptr, "ListIssueInfo"},
- {1112, nullptr, "GetIssue"},
- {1113, nullptr, "GetIssue2"},
- {1114, nullptr, "GetIssue3"},
- {1120, nullptr, "RepairIssue"},
- {1121, nullptr, "RepairIssueWithUserId"},
- {1122, nullptr, "RepairIssue2"},
- {1123, nullptr, "RepairIssue3"},
- {1124, nullptr, "Unknown1124"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void OpenTransferTaskListController(HLERequestContext& ctx) {
- LOG_INFO(Service_OLSC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ITransferTaskListController>(system);
- }
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- server_manager->RegisterNamedService("olsc:u",
- std::make_shared<IOlscServiceForApplication>(system));
- server_manager->RegisterNamedService("olsc:s",
- std::make_shared<IOlscServiceForSystemService>(system));
+ const auto OlscFactoryForApplication = [&] {
+ return std::make_shared<IOlscServiceForApplication>(system);
+ };
+
+ const auto OlscFactoryForSystemService = [&] {
+ return std::make_shared<IOlscServiceForSystemService>(system);
+ };
+
+ server_manager->RegisterNamedService("olsc:u", OlscFactoryForApplication);
+ server_manager->RegisterNamedService("olsc:s", OlscFactoryForSystemService);
ServerManager::RunServer(std::move(server_manager));
}
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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/olsc_service_for_application.h"
+
+namespace Service::OLSC {
+
+IOlscServiceForApplication::IOlscServiceForApplication(Core::System& system_)
+ : ServiceFramework{system_, "olsc:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IOlscServiceForApplication::Initialize>, "Initialize"},
+ {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
+ {13, D<&IOlscServiceForApplication::GetSaveDataBackupSetting>, "GetSaveDataBackupSetting"},
+ {14, D<&IOlscServiceForApplication::SetSaveDataBackupSettingEnabled>, "SetSaveDataBackupSettingEnabled"},
+ {15, nullptr, "SetCustomData"},
+ {16, nullptr, "DeleteSaveDataBackupSetting"},
+ {18, nullptr, "GetSaveDataBackupInfoCache"},
+ {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
+ {22, nullptr, "DeleteSaveDataBackupAsync"},
+ {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
+ {26, nullptr, "DownloadSaveDataBackupAsync"},
+ {27, nullptr, "UploadSaveDataBackupAsync"},
+ {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
+ {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
+ {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
+ {9015, nullptr, "SetCustomDataForDebug"},
+ {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
+ {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
+ {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
+ {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
+ {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
+ {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IOlscServiceForApplication::~IOlscServiceForApplication() = default;
+
+Result IOlscServiceForApplication::Initialize(ClientProcessId process_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ initialized = true;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForApplication::GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ // backup_setting is set to 0 since real value is unknown
+ *out_save_data_backup_setting = 0;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForApplication::SetSaveDataBackupSettingEnabled(bool enabled,
+ NS::Uid account_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called, enabled={}, account_id={}", enabled,
+ account_id.uuid.FormattedString());
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/ns/ns_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
+public:
+ explicit IOlscServiceForApplication(Core::System& system_);
+ ~IOlscServiceForApplication() override;
+
+private:
+ Result Initialize(ClientProcessId process_id);
+ Result GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting);
+ Result SetSaveDataBackupSettingEnabled(bool enabled, NS::Uid account_id);
+
+ bool initialized{};
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/daemon_controller.h"
+#include "core/hle/service/olsc/olsc_service_for_system_service.h"
+#include "core/hle/service/olsc/remote_storage_controller.h"
+#include "core/hle/service/olsc/transfer_task_list_controller.h"
+
+namespace Service::OLSC {
+
+IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_)
+ : ServiceFramework{system_, "olsc:s"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
+ {1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
+ {2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
+ {12, nullptr, "Unknown12"},
+ {13, nullptr, "Unknown13"},
+ {100, nullptr, "ListLastTransferTaskErrorInfo"},
+ {101, nullptr, "GetLastErrorInfoCount"},
+ {102, nullptr, "RemoveLastErrorInfoOld"},
+ {103, nullptr, "GetLastErrorInfo"},
+ {104, nullptr, "GetLastErrorEventHolder"},
+ {105, nullptr, "GetLastTransferTaskErrorInfo"},
+ {200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
+ {201, nullptr, "RemoveDataTransferPolicyInfo"},
+ {202, nullptr, "UpdateDataTransferPolicyOld"},
+ {203, nullptr, "UpdateDataTransferPolicy"},
+ {204, nullptr, "CleanupDataTransferPolicyInfo"},
+ {205, nullptr, "RequestDataTransferPolicy"},
+ {300, nullptr, "GetAutoTransferSeriesInfo"},
+ {301, nullptr, "UpdateAutoTransferSeriesInfo"},
+ {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
+ {900, nullptr, "CleanupTransferTask"},
+ {902, nullptr, "CleanupSeriesInfoType0"},
+ {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
+ {904, nullptr, "CleanupApplicationAutoTransferSetting"},
+ {905, nullptr, "CleanupErrorHistory"},
+ {906, nullptr, "SetLastError"},
+ {907, nullptr, "AddSaveDataArchiveInfoType0"},
+ {908, nullptr, "RemoveSeriesInfoType0"},
+ {909, nullptr, "GetSeriesInfoType0"},
+ {910, nullptr, "RemoveLastErrorInfo"},
+ {911, nullptr, "CleanupSeriesInfoType1"},
+ {912, nullptr, "RemoveSeriesInfoType1"},
+ {913, nullptr, "GetSeriesInfoType1"},
+ {1000, nullptr, "UpdateIssueOld"},
+ {1010, nullptr, "Unknown1010"},
+ {1011, nullptr, "ListIssueInfoOld"},
+ {1012, nullptr, "GetIssueOld"},
+ {1013, nullptr, "GetIssue2Old"},
+ {1014, nullptr, "GetIssue3Old"},
+ {1020, nullptr, "RepairIssueOld"},
+ {1021, nullptr, "RepairIssueWithUserIdOld"},
+ {1022, nullptr, "RepairIssue2Old"},
+ {1023, nullptr, "RepairIssue3Old"},
+ {1024, nullptr, "Unknown1024"},
+ {1100, nullptr, "UpdateIssue"},
+ {1110, nullptr, "Unknown1110"},
+ {1111, nullptr, "ListIssueInfo"},
+ {1112, nullptr, "GetIssue"},
+ {1113, nullptr, "GetIssue2"},
+ {1114, nullptr, "GetIssue3"},
+ {1120, nullptr, "RepairIssue"},
+ {1121, nullptr, "RepairIssueWithUserId"},
+ {1122, nullptr, "RepairIssue2"},
+ {1123, nullptr, "RepairIssue3"},
+ {1124, nullptr, "Unknown1124"},
+ {10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
+
+Result IOlscServiceForSystemService::OpenTransferTaskListController(
+ Out<SharedPointer<ITransferTaskListController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<ITransferTaskListController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::OpenRemoteStorageController(
+ Out<SharedPointer<IRemoteStorageController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<IRemoteStorageController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::OpenDaemonController(
+ Out<SharedPointer<IDaemonController>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::make_shared<IDaemonController>(system);
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(Out<u16> out_policy_info,
+ u64 application_id) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_policy_info = 0;
+ R_SUCCEED();
+}
+
+Result IOlscServiceForSystemService::CloneService(
+ Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
+ LOG_INFO(Service_OLSC, "called");
+ *out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IDaemonController;
+class IRemoteStorageController;
+class ITransferTaskListController;
+
+class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
+public:
+ explicit IOlscServiceForSystemService(Core::System& system_);
+ ~IOlscServiceForSystemService() override;
+
+private:
+ Result OpenTransferTaskListController(
+ Out<SharedPointer<ITransferTaskListController>> out_interface);
+ Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
+ Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
+ Result GetDataTransferPolicyInfo(Out<u16> out_policy_info, u64 application_id);
+ Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/remote_storage_controller.h"
+
+namespace Service::OLSC {
+
+IRemoteStorageController::IRemoteStorageController(Core::System& system_)
+ : ServiceFramework{system_, "IRemoteStorageController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "GetSaveDataArchiveInfoBySaveDataId"},
+ {1, nullptr, "GetSaveDataArchiveInfoByApplicationId"},
+ {3, nullptr, "GetSaveDataArchiveCount"},
+ {6, nullptr, "CleanupSaveDataArchives"},
+ {7, nullptr, "CreateSaveDataArchiveCacheUpdationTask"},
+ {8, nullptr, "CreateSaveDataArchiveCacheUpdationForSpecifiedApplicationTask"},
+ {9, nullptr, "Delete"},
+ {10, nullptr, "GetSeriesInfo"},
+ {11, nullptr, "CreateDeleteDataTask"},
+ {12, nullptr, "DeleteSeriesInfo"},
+ {13, nullptr, "CreateRegisterNotificationTokenTask"},
+ {14, nullptr, "UpdateSeriesInfo"},
+ {15, nullptr, "RegisterUploadSaveDataTransferTaskForAutonomyRegistration"},
+ {16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
+ {17, nullptr, "ListDataInfo"},
+ {18, nullptr, "GetDataInfo"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
+ {21, nullptr, "ListSecondarySaves"},
+ {22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
+ {23, nullptr, "TouchSecondarySave"},
+ {24, nullptr, "GetSecondarySaveDataInfo"},
+ {25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
+ {900, nullptr, "Unknown900"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IRemoteStorageController::~IRemoteStorageController() = default;
+
+Result IRemoteStorageController::GetSecondarySave(Out<bool> out_has_secondary_save,
+ Out<std::array<u64, 3>> out_unknown,
+ u64 application_id) {
+ LOG_ERROR(Service_OLSC, "(STUBBED) called, application_id={:016X}", application_id);
+ *out_has_secondary_save = false;
+ *out_unknown = {};
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class IRemoteStorageController final : public ServiceFramework<IRemoteStorageController> {
+public:
+ explicit IRemoteStorageController(Core::System& system_);
+ ~IRemoteStorageController() override;
+
+private:
+ Result GetSecondarySave(Out<bool> out_has_secondary_save, Out<std::array<u64, 3>> out_unknown,
+ u64 application_id);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/olsc/native_handle_holder.h"
+#include "core/hle/service/olsc/transfer_task_list_controller.h"
+
+namespace Service::OLSC {
+
+ITransferTaskListController::ITransferTaskListController(Core::System& system_)
+ : ServiceFramework{system_, "ITransferTaskListController"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "GetRemoteStorageController"},
+ {9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
+ {10, nullptr, "Unknown10"},
+ {11, nullptr, "Unknown11"},
+ {12, nullptr, "Unknown12"},
+ {13, nullptr, "Unknown13"},
+ {14, nullptr, "Unknown14"},
+ {15, nullptr, "Unknown15"},
+ {16, nullptr, "Unknown16"},
+ {17, nullptr, "Unknown17"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "Unknown20"},
+ {21, nullptr, "Unknown21"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
+ {24, nullptr, "Unknown24"},
+ {25, nullptr, "Unknown25"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ITransferTaskListController::~ITransferTaskListController() = default;
+
+Result ITransferTaskListController::GetNativeHandleHolder(
+ Out<SharedPointer<INativeHandleHolder>> out_holder) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+ *out_holder = std::make_shared<INativeHandleHolder>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::OLSC {
+
+class INativeHandleHolder;
+
+class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
+public:
+ explicit ITransferTaskListController(Core::System& system_);
+ ~ITransferTaskListController() override;
+
+private:
+ Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/pctl/parental_control_service.h"
+#include "core/hle/service/pctl/pctl_results.h"
+
+namespace Service::PCTL {
+
+IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
+ : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
+ service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
+ unlinked_event{service_context}, request_suspension_event{service_context} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {1, D<&IParentalControlService::Initialize>, "Initialize"},
+ {1001, D<&IParentalControlService::CheckFreeCommunicationPermission>, "CheckFreeCommunicationPermission"},
+ {1002, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
+ {1003, D<&IParentalControlService::ConfirmResumeApplicationPermission>, "ConfirmResumeApplicationPermission"},
+ {1004, D<&IParentalControlService::ConfirmSnsPostPermission>, "ConfirmSnsPostPermission"},
+ {1005, nullptr, "ConfirmSystemSettingsPermission"},
+ {1006, D<&IParentalControlService::IsRestrictionTemporaryUnlocked>, "IsRestrictionTemporaryUnlocked"},
+ {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
+ {1008, nullptr, "EnterRestrictedSystemSettings"},
+ {1009, nullptr, "LeaveRestrictedSystemSettings"},
+ {1010, D<&IParentalControlService::IsRestrictedSystemSettingsEntered>, "IsRestrictedSystemSettingsEntered"},
+ {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
+ {1012, nullptr, "GetRestrictedFeatures"},
+ {1013, D<&IParentalControlService::ConfirmStereoVisionPermission>, "ConfirmStereoVisionPermission"},
+ {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
+ {1015, nullptr, "ConfirmPlayableApplicationVideo"},
+ {1016, nullptr, "ConfirmShowNewsPermission"},
+ {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
+ {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
+ {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
+ {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
+ {1033, nullptr, "SetSafetyLevel"},
+ {1034, nullptr, "GetSafetyLevelSettings"},
+ {1035, D<&IParentalControlService::GetCurrentSettings>, "GetCurrentSettings"},
+ {1036, nullptr, "SetCustomSafetyLevelSettings"},
+ {1037, nullptr, "GetDefaultRatingOrganization"},
+ {1038, nullptr, "SetDefaultRatingOrganization"},
+ {1039, D<&IParentalControlService::GetFreeCommunicationApplicationListCount>, "GetFreeCommunicationApplicationListCount"},
+ {1042, nullptr, "AddToFreeCommunicationApplicationList"},
+ {1043, nullptr, "DeleteSettings"},
+ {1044, nullptr, "GetFreeCommunicationApplicationList"},
+ {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
+ {1046, nullptr, "DisableFeaturesForReset"},
+ {1047, nullptr, "NotifyApplicationDownloadStarted"},
+ {1048, nullptr, "NotifyNetworkProfileCreated"},
+ {1049, nullptr, "ResetFreeCommunicationApplicationList"},
+ {1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
+ {1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
+ {1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
+ {1064, D<&IParentalControlService::ResetConfirmedStereoVisionPermission>, "ResetConfirmedStereoVisionPermission"},
+ {1065, D<&IParentalControlService::IsStereoVisionPermitted>, "IsStereoVisionPermitted"},
+ {1201, nullptr, "UnlockRestrictionTemporarily"},
+ {1202, nullptr, "UnlockSystemSettingsRestriction"},
+ {1203, nullptr, "SetPinCode"},
+ {1204, nullptr, "GenerateInquiryCode"},
+ {1205, nullptr, "CheckMasterKey"},
+ {1206, D<&IParentalControlService::GetPinCodeLength>, "GetPinCodeLength"},
+ {1207, nullptr, "GetPinCodeChangedEvent"},
+ {1208, nullptr, "GetPinCode"},
+ {1403, D<&IParentalControlService::IsPairingActive>, "IsPairingActive"},
+ {1406, nullptr, "GetSettingsLastUpdated"},
+ {1411, nullptr, "GetPairingAccountInfo"},
+ {1421, nullptr, "GetAccountNickname"},
+ {1424, nullptr, "GetAccountState"},
+ {1425, nullptr, "RequestPostEvents"},
+ {1426, nullptr, "GetPostEventInterval"},
+ {1427, nullptr, "SetPostEventInterval"},
+ {1432, D<&IParentalControlService::GetSynchronizationEvent>, "GetSynchronizationEvent"},
+ {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
+ {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
+ {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
+ {1454, nullptr, "GetPlayTimerRemainingTime"},
+ {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
+ {1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
+ {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
+ {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
+ {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
+ {1472, nullptr, "CancelNetworkRequest"},
+ {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
+ {1474, nullptr, "ClearUnlinkedEvent"},
+ {1601, nullptr, "DisableAllFeatures"},
+ {1602, nullptr, "PostEnableAllFeatures"},
+ {1603, nullptr, "IsAllFeaturesDisabled"},
+ {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
+ {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
+ {1903, nullptr, "GetExemptApplicationListCountForDebug"},
+ {1904, nullptr, "GetExemptApplicationListForDebug"},
+ {1905, nullptr, "UpdateExemptApplicationListForDebug"},
+ {1906, nullptr, "AddToExemptApplicationListForDebug"},
+ {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
+ {1908, nullptr, "ClearExemptApplicationListForDebug"},
+ {1941, nullptr, "DeletePairing"},
+ {1951, nullptr, "SetPlayTimerSettingsForDebug"},
+ {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
+ {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
+ {2001, nullptr, "RequestPairingAsync"},
+ {2002, nullptr, "FinishRequestPairing"},
+ {2003, nullptr, "AuthorizePairingAsync"},
+ {2004, nullptr, "FinishAuthorizePairing"},
+ {2005, nullptr, "RetrievePairingInfoAsync"},
+ {2006, nullptr, "FinishRetrievePairingInfo"},
+ {2007, nullptr, "UnlinkPairingAsync"},
+ {2008, nullptr, "FinishUnlinkPairing"},
+ {2009, nullptr, "GetAccountMiiImageAsync"},
+ {2010, nullptr, "FinishGetAccountMiiImage"},
+ {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
+ {2012, nullptr, "FinishGetAccountMiiImageContentType"},
+ {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
+ {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
+ {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
+ {2016, nullptr, "RequestUpdateExemptionListAsync"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+}
+
+IParentalControlService::~IParentalControlService() = default;
+
+bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if ((states.application_info.parental_control_flag & 1) == 0) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_free_communication_default_on) {
+ return true;
+ }
+ // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
+ // but as we don't have multiproceses support yet, we can just assume our application is
+ // valid for the time being
+ return true;
+}
+
+bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
+ if (states.temporary_unlocked) {
+ return true;
+ }
+ if (pin_code[0] == '\0') {
+ return true;
+ }
+ if (!settings.is_stero_vision_restricted) {
+ return false;
+ }
+ return true;
+}
+
+void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
+ if (settings.disabled) {
+ return;
+ }
+
+ if (pin_code[0] == '\0') {
+ return;
+ }
+ settings.is_stero_vision_restricted = is_restricted;
+}
+
+Result IParentalControlService::Initialize() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & (Capability::Application | Capability::System))) {
+ LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ // TODO(ogniK): Recovery flag initialization for pctl:r
+
+ const auto program_id = system.GetApplicationProcessProgramID();
+ if (program_id != 0) {
+ const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ if (control.first) {
+ states.tid_from_event = 0;
+ states.launch_time_valid = false;
+ states.is_suspended = false;
+ states.free_communication = false;
+ states.stereo_vision = false;
+ states.application_info = ApplicationInfo{
+ .application_id = program_id,
+ .age_rating = control.first->GetRatingAge(),
+ .parental_control_flag = control.first->GetParentalControlFlag(),
+ .capability = capability,
+ };
+
+ if (False(capability & (Capability::System | Capability::Recovery))) {
+ // TODO(ogniK): Signal application launch event
+ }
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result IParentalControlService::CheckFreeCommunicationPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ R_THROW(PCTL::ResultNoFreeCommunication);
+ } else {
+ states.free_communication = true;
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::ConfirmLaunchApplicationPermission(
+ InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
+ application_id);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmResumeApplicationPermission(
+ InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
+ application_id);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmSnsPostPermission() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_THROW(PCTL::ResultNoFreeCommunication);
+}
+
+Result IParentalControlService::IsRestrictionTemporaryUnlocked(
+ Out<bool> out_is_temporary_unlocked) {
+ *out_is_temporary_unlocked = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
+ *out_is_temporary_unlocked);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsRestrictedSystemSettingsEntered(
+ Out<bool> out_is_restricted_system_settings_entered) {
+ *out_is_restricted_system_settings_entered = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
+ *out_is_restricted_system_settings_entered);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmStereoVisionPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+ states.stereo_vision = true;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::EndFreeCommunication() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsFreeCommunicationAvailable() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+
+ if (!CheckFreeCommunicationPermissionImpl()) {
+ R_THROW(PCTL::ResultNoFreeCommunication);
+ } else {
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::IsRestrictionEnabled(Out<bool> out_restriction_enabled) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & (Capability::Status | Capability::Recovery))) {
+ LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
+ *out_restriction_enabled = false;
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ *out_restriction_enabled = pin_code[0] != '\0';
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetSafetyLevel(Out<u32> out_safety_level) {
+ *out_safety_level = 0;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", *out_safety_level);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetCurrentSettings(Out<RestrictionSettings> out_settings) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_settings = restriction_settings;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetFreeCommunicationApplicationListCount(Out<s32> out_count) {
+ *out_count = 4;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", *out_count);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ConfirmStereoVisionRestrictionConfigurable() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ if (pin_code[0] == '\0') {
+ R_THROW(PCTL::ResultNoRestrictionEnabled);
+ }
+
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsStereoVisionPermitted(Out<bool> out_is_permitted) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (!ConfirmStereoVisionPermissionImpl()) {
+ *out_is_permitted = false;
+ R_THROW(PCTL::ResultStereoVisionRestricted);
+ } else {
+ *out_is_permitted = true;
+ R_SUCCEED();
+ }
+}
+
+Result IParentalControlService::GetPinCodeLength(Out<s32> out_length) {
+ *out_length = 0;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, length={}", *out_length);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPairingActive(Out<bool> out_is_pairing_active) {
+ *out_is_pairing_active = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", *out_is_pairing_active);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetSynchronizationEvent(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = synchronization_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::StartPlayTimer() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::StopPlayTimer() {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled) {
+ *out_is_play_timer_enabled = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, enabled={}", *out_is_play_timer_enabled);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
+ *out_is_restricted_by_play_timer = false;
+ LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetPlayTimerSettings(
+ Out<PlayTimerSettings> out_play_timer_settings) {
+ LOG_WARNING(Service_PCTL, "(STUBBED) called");
+ *out_play_timer_settings = {};
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
+ OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = request_suspension_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
+ *out_play_timer_alarm_disabled = false;
+ LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
+ *out_play_timer_alarm_disabled);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
+ LOG_INFO(Service_PCTL, "called");
+ *out_event = unlinked_event.GetHandle();
+ R_SUCCEED();
+}
+
+Result IParentalControlService::GetStereoVisionRestriction(
+ Out<bool> out_stereo_vision_restriction) {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ *out_stereo_vision_restriction = false;
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ *out_stereo_vision_restriction = settings.is_stero_vision_restricted;
+ R_SUCCEED();
+}
+
+Result IParentalControlService::SetStereoVisionRestriction(bool stereo_vision_restriction) {
+ LOG_DEBUG(Service_PCTL, "called, can_use={}", stereo_vision_restriction);
+
+ if (False(capability & Capability::StereoVision)) {
+ LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
+ R_THROW(PCTL::ResultNoCapability);
+ }
+
+ SetStereoVisionRestrictionImpl(stereo_vision_restriction);
+ R_SUCCEED();
+}
+
+Result IParentalControlService::ResetConfirmedStereoVisionPermission() {
+ LOG_DEBUG(Service_PCTL, "called");
+
+ states.stereo_vision = false;
+
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/os/event.h"
+#include "core/hle/service/pctl/pctl_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PCTL {
+
+class IParentalControlService final : public ServiceFramework<IParentalControlService> {
+public:
+ explicit IParentalControlService(Core::System& system_, Capability capability_);
+ ~IParentalControlService() override;
+
+private:
+ bool CheckFreeCommunicationPermissionImpl() const;
+ bool ConfirmStereoVisionPermissionImpl() const;
+ void SetStereoVisionRestrictionImpl(bool is_restricted);
+
+ Result Initialize();
+ Result CheckFreeCommunicationPermission();
+ Result ConfirmLaunchApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
+ u64 nacp_flag, u64 application_id);
+ Result ConfirmResumeApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
+ u64 nacp_flag, u64 application_id);
+ Result ConfirmSnsPostPermission();
+ Result IsRestrictionTemporaryUnlocked(Out<bool> out_is_temporary_unlocked);
+ Result IsRestrictedSystemSettingsEntered(Out<bool> out_is_restricted_system_settings_entered);
+ Result ConfirmStereoVisionPermission();
+ Result EndFreeCommunication();
+ Result IsFreeCommunicationAvailable();
+ Result IsRestrictionEnabled(Out<bool> out_restriction_enabled);
+ Result GetSafetyLevel(Out<u32> out_safety_level);
+ Result GetCurrentSettings(Out<RestrictionSettings> out_settings);
+ Result GetFreeCommunicationApplicationListCount(Out<s32> out_count);
+ Result ConfirmStereoVisionRestrictionConfigurable();
+ Result IsStereoVisionPermitted(Out<bool> out_is_permitted);
+ Result GetPinCodeLength(Out<s32> out_length);
+ Result IsPairingActive(Out<bool> out_is_pairing_active);
+ Result GetSynchronizationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result StartPlayTimer();
+ Result StopPlayTimer();
+ Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
+ Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
+ Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
+ Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
+ Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
+ Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
+ Result SetStereoVisionRestriction(bool stereo_vision_restriction);
+ Result ResetConfirmedStereoVisionPermission();
+
+ struct States {
+ u64 current_tid{};
+ ApplicationInfo application_info{};
+ u64 tid_from_event{};
+ bool launch_time_valid{};
+ bool is_suspended{};
+ bool temporary_unlocked{};
+ bool free_communication{};
+ bool stereo_vision{};
+ };
+
+ struct ParentalControlSettings {
+ bool is_stero_vision_restricted{};
+ bool is_free_communication_default_on{};
+ bool disabled{};
+ };
+
+ States states{};
+ ParentalControlSettings settings{};
+ RestrictionSettings restriction_settings{};
+ std::array<char, 8> pin_code{};
+ Capability capability{};
+
+ KernelHelpers::ServiceContext service_context;
+ Event synchronization_event;
+ Event unlinked_event;
+ Event request_suspension_event;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/pctl/parental_control_service.h"
+#include "core/hle/service/pctl/parental_control_service_factory.h"
+
+namespace Service::PCTL {
+
+IParentalControlServiceFactory::IParentalControlServiceFactory(Core::System& system_,
+ const char* name_,
+ Capability capability_)
+ : ServiceFramework{system_, name_}, capability{capability_} {
+ static const FunctionInfo functions[] = {
+ {0, D<&IParentalControlServiceFactory::CreateService>, "CreateService"},
+ {1, D<&IParentalControlServiceFactory::CreateServiceWithoutInitialize>,
+ "CreateServiceWithoutInitialize"},
+ };
+ RegisterHandlers(functions);
+}
+
+IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
+
+Result IParentalControlServiceFactory::CreateService(
+ Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
+ LOG_DEBUG(Service_PCTL, "called");
+ // TODO(ogniK): Get application id from process
+ *out_service = std::make_shared<IParentalControlService>(system, capability);
+ R_SUCCEED();
+}
+
+Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
+ Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
+ LOG_DEBUG(Service_PCTL, "called");
+ // TODO(ogniK): Get application id from process
+ *out_service = std::make_shared<IParentalControlService>(system, capability);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/pctl/pctl_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PCTL {
+
+class IParentalControlService;
+
+class IParentalControlServiceFactory : public ServiceFramework<IParentalControlServiceFactory> {
+public:
+ explicit IParentalControlServiceFactory(Core::System& system_, const char* name_,
+ Capability capability_);
+ ~IParentalControlServiceFactory() override;
+
+ Result CreateService(Out<SharedPointer<IParentalControlService>> out_service,
+ ClientProcessId process_id);
+ Result CreateServiceWithoutInitialize(Out<SharedPointer<IParentalControlService>> out_service,
+ ClientProcessId process_id);
+
+private:
+ Capability capability{};
+};
+
+void LoopProcess(Core::System& system);
+
+} // 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 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/service/pctl/parental_control_service_factory.h"
#include "core/hle/service/pctl/pctl.h"
+#include "core/hle/service/server_manager.h"
namespace Service::PCTL {
-PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability_)
- : Interface{system_, std::move(module_), name, capability_} {
- static const FunctionInfo functions[] = {
- {0, &PCTL::CreateService, "CreateService"},
- {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
- };
- RegisterHandlers(functions);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("pctl",
+ std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl",
+ Capability::Application | Capability::SnsPost |
+ Capability::Status | Capability::StereoVision));
+ // TODO(ogniK): Implement remaining capabilities
+ server_manager->RegisterNamedService("pctl:a", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:a", Capability::None));
+ server_manager->RegisterNamedService("pctl:r", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:r", Capability::None));
+ server_manager->RegisterNamedService("pctl:s", std::make_shared<IParentalControlServiceFactory>(
+ system, "pctl:s", Capability::None));
+ ServerManager::RunServer(std::move(server_manager));
}
-PCTL::~PCTL() = default;
} // 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 @@
#pragma once
-#include "core/hle/service/pctl/pctl_module.h"
-
namespace Core {
class System;
}
namespace Service::PCTL {
-class PCTL final : public Module::Interface {
-public:
- explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
- Capability capability_);
- ~PCTL() override;
-};
+void LoopProcess(Core::System& system);
} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/file_sys/control_metadata.h"
-#include "core/file_sys/patch_manager.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/pctl/pctl.h"
-#include "core/hle/service/pctl/pctl_module.h"
-#include "core/hle/service/server_manager.h"
-
-namespace Service::PCTL {
-
-namespace Error {
-
-constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
-constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
-constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
-constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
-
-} // namespace Error
-
-class IParentalControlService final : public ServiceFramework<IParentalControlService> {
-public:
- explicit IParentalControlService(Core::System& system_, Capability capability_)
- : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
- service_context{system_, "IParentalControlService"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {1, &IParentalControlService::Initialize, "Initialize"},
- {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
- {1002, nullptr, "ConfirmLaunchApplicationPermission"},
- {1003, nullptr, "ConfirmResumeApplicationPermission"},
- {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
- {1005, nullptr, "ConfirmSystemSettingsPermission"},
- {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
- {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
- {1008, nullptr, "EnterRestrictedSystemSettings"},
- {1009, nullptr, "LeaveRestrictedSystemSettings"},
- {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
- {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
- {1012, nullptr, "GetRestrictedFeatures"},
- {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
- {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
- {1015, nullptr, "ConfirmPlayableApplicationVideo"},
- {1016, nullptr, "ConfirmShowNewsPermission"},
- {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
- {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
- {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
- {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
- {1033, nullptr, "SetSafetyLevel"},
- {1034, nullptr, "GetSafetyLevelSettings"},
- {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
- {1036, nullptr, "SetCustomSafetyLevelSettings"},
- {1037, nullptr, "GetDefaultRatingOrganization"},
- {1038, nullptr, "SetDefaultRatingOrganization"},
- {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
- {1042, nullptr, "AddToFreeCommunicationApplicationList"},
- {1043, nullptr, "DeleteSettings"},
- {1044, nullptr, "GetFreeCommunicationApplicationList"},
- {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
- {1046, nullptr, "DisableFeaturesForReset"},
- {1047, nullptr, "NotifyApplicationDownloadStarted"},
- {1048, nullptr, "NotifyNetworkProfileCreated"},
- {1049, nullptr, "ResetFreeCommunicationApplicationList"},
- {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
- {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
- {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
- {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
- {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
- {1201, nullptr, "UnlockRestrictionTemporarily"},
- {1202, nullptr, "UnlockSystemSettingsRestriction"},
- {1203, nullptr, "SetPinCode"},
- {1204, nullptr, "GenerateInquiryCode"},
- {1205, nullptr, "CheckMasterKey"},
- {1206, nullptr, "GetPinCodeLength"},
- {1207, nullptr, "GetPinCodeChangedEvent"},
- {1208, nullptr, "GetPinCode"},
- {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
- {1406, nullptr, "GetSettingsLastUpdated"},
- {1411, nullptr, "GetPairingAccountInfo"},
- {1421, nullptr, "GetAccountNickname"},
- {1424, nullptr, "GetAccountState"},
- {1425, nullptr, "RequestPostEvents"},
- {1426, nullptr, "GetPostEventInterval"},
- {1427, nullptr, "SetPostEventInterval"},
- {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
- {1451, nullptr, "StartPlayTimer"},
- {1452, nullptr, "StopPlayTimer"},
- {1453, nullptr, "IsPlayTimerEnabled"},
- {1454, nullptr, "GetPlayTimerRemainingTime"},
- {1455, nullptr, "IsRestrictedByPlayTimer"},
- {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
- {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
- {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
- {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
- {1472, nullptr, "CancelNetworkRequest"},
- {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
- {1474, nullptr, "ClearUnlinkedEvent"},
- {1601, nullptr, "DisableAllFeatures"},
- {1602, nullptr, "PostEnableAllFeatures"},
- {1603, nullptr, "IsAllFeaturesDisabled"},
- {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
- {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
- {1903, nullptr, "GetExemptApplicationListCountForDebug"},
- {1904, nullptr, "GetExemptApplicationListForDebug"},
- {1905, nullptr, "UpdateExemptApplicationListForDebug"},
- {1906, nullptr, "AddToExemptApplicationListForDebug"},
- {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
- {1908, nullptr, "ClearExemptApplicationListForDebug"},
- {1941, nullptr, "DeletePairing"},
- {1951, nullptr, "SetPlayTimerSettingsForDebug"},
- {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
- {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
- {2001, nullptr, "RequestPairingAsync"},
- {2002, nullptr, "FinishRequestPairing"},
- {2003, nullptr, "AuthorizePairingAsync"},
- {2004, nullptr, "FinishAuthorizePairing"},
- {2005, nullptr, "RetrievePairingInfoAsync"},
- {2006, nullptr, "FinishRetrievePairingInfo"},
- {2007, nullptr, "UnlinkPairingAsync"},
- {2008, nullptr, "FinishUnlinkPairing"},
- {2009, nullptr, "GetAccountMiiImageAsync"},
- {2010, nullptr, "FinishGetAccountMiiImage"},
- {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
- {2012, nullptr, "FinishGetAccountMiiImageContentType"},
- {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
- {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
- {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
- {2016, nullptr, "RequestUpdateExemptionListAsync"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- synchronization_event =
- service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
- unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
- request_suspension_event =
- service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
- }
-
- ~IParentalControlService() {
- service_context.CloseEvent(synchronization_event);
- service_context.CloseEvent(unlinked_event);
- service_context.CloseEvent(request_suspension_event);
- };
-
-private:
- bool CheckFreeCommunicationPermissionImpl() const {
- if (states.temporary_unlocked) {
- return true;
- }
- if ((states.application_info.parental_control_flag & 1) == 0) {
- return true;
- }
- if (pin_code[0] == '\0') {
- return true;
- }
- if (!settings.is_free_communication_default_on) {
- return true;
- }
- // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
- // but as we don't have multiproceses support yet, we can just assume our application is
- // valid for the time being
- return true;
- }
-
- bool ConfirmStereoVisionPermissionImpl() const {
- if (states.temporary_unlocked) {
- return true;
- }
- if (pin_code[0] == '\0') {
- return true;
- }
- if (!settings.is_stero_vision_restricted) {
- return false;
- }
- return true;
- }
-
- void SetStereoVisionRestrictionImpl(bool is_restricted) {
- if (settings.disabled) {
- return;
- }
-
- if (pin_code[0] == '\0') {
- return;
- }
- settings.is_stero_vision_restricted = is_restricted;
- }
-
- void Initialize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
- IPC::ResponseBuilder rb{ctx, 2};
-
- if (False(capability & (Capability::Application | Capability::System))) {
- LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
- return;
- }
-
- // TODO(ogniK): Recovery flag initialization for pctl:r
-
- const auto tid = system.GetApplicationProcessProgramID();
- if (tid != 0) {
- const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
- system.GetContentProvider()};
- const auto control = pm.GetControlMetadata();
- if (control.first) {
- states.tid_from_event = 0;
- states.launch_time_valid = false;
- states.is_suspended = false;
- states.free_communication = false;
- states.stereo_vision = false;
- states.application_info = ApplicationInfo{
- .tid = tid,
- .age_rating = control.first->GetRatingAge(),
- .parental_control_flag = control.first->GetParentalControlFlag(),
- .capability = capability,
- };
-
- if (False(capability & (Capability::System | Capability::Recovery))) {
- // TODO(ogniK): Signal application launch event
- }
- }
- }
-
- rb.Push(ResultSuccess);
- }
-
- void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (!CheckFreeCommunicationPermissionImpl()) {
- rb.Push(Error::ResultNoFreeCommunication);
- } else {
- rb.Push(ResultSuccess);
- }
-
- states.free_communication = true;
- }
-
- void ConfirmSnsPostPermission(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Error::ResultNoFreeCommunication);
- }
-
- void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
- const bool is_temporary_unlocked = false;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
- is_temporary_unlocked);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_temporary_unlocked);
- }
-
- void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
- states.stereo_vision = true;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void EndFreeCommunication(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (!CheckFreeCommunicationPermissionImpl()) {
- rb.Push(Error::ResultNoFreeCommunication);
- } else {
- rb.Push(ResultSuccess);
- }
- }
-
- void IsRestrictionEnabled(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (False(capability & (Capability::Status | Capability::Recovery))) {
- LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
- rb.Push(Error::ResultNoCapability);
- rb.Push(false);
- return;
- }
-
- rb.Push(pin_code[0] != '\0');
- }
-
- void GetSafetyLevel(HLERequestContext& ctx) {
- const u32 safety_level = 0;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(safety_level);
- }
-
- void GetCurrentSettings(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw(restriction_settings);
- }
-
- void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
- const u32 count = 4;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-
- void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
-
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- return;
- }
-
- if (pin_code[0] == '\0') {
- rb.Push(Error::ResultNoRestrictionEnabled);
- return;
- }
-
- rb.Push(ResultSuccess);
- }
-
- void IsStereoVisionPermitted(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (!ConfirmStereoVisionPermissionImpl()) {
- rb.Push(Error::ResultStereoVisionRestricted);
- rb.Push(false);
- } else {
- rb.Push(ResultSuccess);
- rb.Push(true);
- }
- }
-
- void IsPairingActive(HLERequestContext& ctx) {
- const bool is_pairing_active = false;
-
- LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_pairing_active);
- }
-
- void GetSynchronizationEvent(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(synchronization_event->GetReadableEvent());
- }
-
- void GetPlayTimerSettings(HLERequestContext& ctx) {
- LOG_WARNING(Service_PCTL, "(STUBBED) called");
-
- const PlayTimerSettings timer_settings{};
-
- IPC::ResponseBuilder rb{ctx, 15};
- rb.Push(ResultSuccess);
- rb.PushRaw(timer_settings);
- }
-
- void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
- }
-
- void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
- const bool is_play_timer_alarm_disabled = false;
-
- LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
- is_play_timer_alarm_disabled);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(is_play_timer_alarm_disabled);
- }
-
- void GetUnlinkedEvent(HLERequestContext& ctx) {
- LOG_INFO(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(unlinked_event->GetReadableEvent());
- }
-
- void SetStereoVisionRestriction(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto can_use = rp.Pop<bool>();
- LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- return;
- }
-
- SetStereoVisionRestrictionImpl(can_use);
- rb.Push(ResultSuccess);
- }
-
- void GetStereoVisionRestriction(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- if (False(capability & Capability::StereoVision)) {
- LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
- rb.Push(Error::ResultNoCapability);
- rb.Push(false);
- return;
- }
-
- rb.Push(ResultSuccess);
- rb.Push(settings.is_stero_vision_restricted);
- }
-
- void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- states.stereo_vision = false;
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- struct ApplicationInfo {
- u64 tid{};
- std::array<u8, 32> age_rating{};
- u32 parental_control_flag{};
- Capability capability{};
- };
-
- struct States {
- u64 current_tid{};
- ApplicationInfo application_info{};
- u64 tid_from_event{};
- bool launch_time_valid{};
- bool is_suspended{};
- bool temporary_unlocked{};
- bool free_communication{};
- bool stereo_vision{};
- };
-
- struct ParentalControlSettings {
- bool is_stero_vision_restricted{};
- bool is_free_communication_default_on{};
- bool disabled{};
- };
-
- // This is nn::pctl::RestrictionSettings
- struct RestrictionSettings {
- u8 rating_age;
- bool sns_post_restriction;
- bool free_communication_restriction;
- };
- static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
-
- // This is nn::pctl::PlayTimerSettings
- struct PlayTimerSettings {
- std::array<u32, 13> settings;
- };
- static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
-
- States states{};
- ParentalControlSettings settings{};
- RestrictionSettings restriction_settings{};
- std::array<char, 8> pin_code{};
- Capability capability{};
-
- Kernel::KEvent* synchronization_event;
- Kernel::KEvent* unlinked_event;
- Kernel::KEvent* request_suspension_event;
- KernelHelpers::ServiceContext service_context;
-};
-
-void Module::Interface::CreateService(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- // TODO(ogniK): Get TID from process
-
- rb.PushIpcInterface<IParentalControlService>(system, capability);
-}
-
-void Module::Interface::CreateServiceWithoutInitialize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PCTL, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IParentalControlService>(system, capability);
-}
-
-Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name_, Capability capability_)
- : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
-
-Module::Interface::~Interface() = default;
-
-void LoopProcess(Core::System& system) {
- auto server_manager = std::make_unique<ServerManager>(system);
-
- auto module = std::make_shared<Module>();
- server_manager->RegisterNamedService(
- "pctl", std::make_shared<PCTL>(system, module, "pctl",
- Capability::Application | Capability::SnsPost |
- Capability::Status | Capability::StereoVision));
- // TODO(ogniK): Implement remaining capabilities
- server_manager->RegisterNamedService(
- "pctl:a", std::make_shared<PCTL>(system, module, "pctl:a", Capability::None));
- server_manager->RegisterNamedService(
- "pctl:r", std::make_shared<PCTL>(system, module, "pctl:r", Capability::None));
- server_manager->RegisterNamedService(
- "pctl:s", std::make_shared<PCTL>(system, module, "pctl:s", Capability::None));
- ServerManager::RunServer(std::move(server_manager));
-}
-
-} // 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 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/common_funcs.h"
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::PCTL {
-
-enum class Capability : u32 {
- None = 0,
- Application = 1 << 0,
- SnsPost = 1 << 1,
- Recovery = 1 << 6,
- Status = 1 << 8,
- StereoVision = 1 << 9,
- System = 1 << 15,
-};
-DECLARE_ENUM_FLAG_OPERATORS(Capability);
-
-class Module final {
-public:
- class Interface : public ServiceFramework<Interface> {
- public:
- explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
- const char* name_, Capability capability_);
- ~Interface() override;
-
- void CreateService(HLERequestContext& ctx);
- void CreateServiceWithoutInitialize(HLERequestContext& ctx);
-
- protected:
- std::shared_ptr<Module> module;
-
- private:
- Capability capability{};
- };
-};
-
-void LoopProcess(Core::System& system);
-
-} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::PCTL {
+
+constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
+constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
+constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
+constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_funcs.h"
+
+namespace Service::PCTL {
+
+enum class Capability : u32 {
+ None = 0,
+ Application = 1 << 0,
+ SnsPost = 1 << 1,
+ Recovery = 1 << 6,
+ Status = 1 << 8,
+ StereoVision = 1 << 9,
+ System = 1 << 15,
+};
+DECLARE_ENUM_FLAG_OPERATORS(Capability);
+
+struct ApplicationInfo {
+ u64 application_id{};
+ std::array<u8, 32> age_rating{};
+ u32 parental_control_flag{};
+ Capability capability{};
+};
+static_assert(sizeof(ApplicationInfo) == 0x30, "ApplicationInfo has incorrect size.");
+
+// This is nn::pctl::RestrictionSettings
+struct RestrictionSettings {
+ u8 rating_age;
+ bool sns_post_restriction;
+ bool free_communication_restriction;
+};
+static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
+
+// This is nn::pctl::PlayTimerSettings
+struct PlayTimerSettings {
+ std::array<u32, 13> settings;
+};
+static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+namespace Service::PSC {
+
+using OverlayNotification = std::array<u64, 0x10>;
+static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");
+
+union MessageFlags {
+ u64 raw;
+ BitField<0, 8, u64> message_type;
+ BitField<8, 8, u64> queue_type;
+};
+static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/psc/ovln/receiver.h"
+
+namespace Service::PSC {
+
+IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "AddSource"},
+ {1, nullptr, "RemoveSource"},
+ {2, nullptr, "GetReceiveEventHandle"},
+ {3, nullptr, "Receive"},
+ {4, nullptr, "ReceiveWithTick"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IReceiver::~IReceiver() = default;
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class IReceiver final : public ServiceFramework<IReceiver> {
+public:
+ explicit IReceiver(Core::System& system_);
+ ~IReceiver() override;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/psc/ovln/receiver.h"
+#include "core/hle/service/psc/ovln/receiver_service.h"
+
+namespace Service::PSC {
+
+IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IReceiverService::~IReceiverService() = default;
+
+Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
+ LOG_DEBUG(Service_PSC, "called");
+ *out_receiver = std::make_shared<IReceiver>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class IReceiver;
+
+class IReceiverService final : public ServiceFramework<IReceiverService> {
+public:
+ explicit IReceiverService(Core::System& system_);
+ ~IReceiverService() override;
+
+private:
+ Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/psc/ovln/sender.h"
+
+namespace Service::PSC {
+
+ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ISender::Send>, "Send"},
+ {1, nullptr, "GetUnreceivedMessageCount"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ISender::~ISender() = default;
+
+Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
+ std::string data;
+ for (const auto m : notification) {
+ data += fmt::format("{:016X} ", m);
+ }
+
+ LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/psc/ovln/ovln_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class ISender final : public ServiceFramework<ISender> {
+public:
+ explicit ISender(Core::System& system_);
+ ~ISender() override;
+
+private:
+ Result Send(const OverlayNotification& notification, MessageFlags flags);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/psc/ovln/sender.h"
+#include "core/hle/service/psc/ovln/sender_service.h"
+
+namespace Service::PSC {
+
+ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&ISenderService::OpenSender>, "OpenSender"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+ISenderService::~ISenderService() = default;
+
+Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
+ std::array<u64, 2> data) {
+ LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
+ data[0], data[1]);
+ *out_sender = std::make_shared<ISender>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class ISender;
+
+class ISenderService final : public ServiceFramework<ISenderService> {
+public:
+ explicit ISenderService(Core::System& system_);
+ ~ISenderService() override;
+
+private:
+ Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
+ std::array<u64, 2> data);
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/psc/pm_control.h"
+
+namespace Service::PSC {
+
+IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "DispatchRequest"},
+ {2, nullptr, "GetResult"},
+ {3, nullptr, "GetState"},
+ {4, nullptr, "Cancel"},
+ {5, nullptr, "PrintModuleInformation"},
+ {6, nullptr, "GetModuleInformation"},
+ {10, nullptr, "AcquireStateLock"},
+ {11, nullptr, "HasStateLock"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IPmControl::~IPmControl() = default;
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class IPmControl final : public ServiceFramework<IPmControl> {
+public:
+ explicit IPmControl(Core::System& system_);
+ ~IPmControl() override;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/psc/pm_module.h"
+
+namespace Service::PSC {
+
+IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Initialize"},
+ {1, nullptr, "GetRequest"},
+ {2, nullptr, "Acknowledge"},
+ {3, nullptr, "Finalize"},
+ {4, nullptr, "AcknowledgeEx"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IPmModule::~IPmModule() = default;
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class IPmModule final : public ServiceFramework<IPmModule> {
+public:
+ explicit IPmModule(Core::System& system_);
+ ~IPmModule() override;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/cmif_serialization.h"
+#include "core/hle/service/psc/pm_module.h"
+#include "core/hle/service/psc/pm_service.h"
+
+namespace Service::PSC {
+
+IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, D<&IPmService::GetPmModule>, "GetPmModule"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IPmService::~IPmService() = default;
+
+Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
+ LOG_DEBUG(Service_PSC, "called");
+ *out_module = std::make_shared<IPmModule>(system);
+ R_SUCCEED();
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/cmif_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PSC {
+
+class IPmModule;
+
+class IPmService final : public ServiceFramework<IPmService> {
+public:
+ explicit IPmService(Core::System& system_);
+ ~IPmService() override;
+
+private:
+ Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
+};
+
+} // 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 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <memory>
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/psc/ovln/receiver_service.h"
+#include "core/hle/service/psc/ovln/sender_service.h"
+#include "core/hle/service/psc/pm_control.h"
+#include "core/hle/service/psc/pm_service.h"
#include "core/hle/service/psc/psc.h"
#include "core/hle/service/psc/time/manager.h"
#include "core/hle/service/psc/time/power_state_service.h"
@@ -15,71 +14,13 @@
namespace Service::PSC {
-class IPmControl final : public ServiceFramework<IPmControl> {
-public:
- explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {1, nullptr, "DispatchRequest"},
- {2, nullptr, "GetResult"},
- {3, nullptr, "GetState"},
- {4, nullptr, "Cancel"},
- {5, nullptr, "PrintModuleInformation"},
- {6, nullptr, "GetModuleInformation"},
- {10, nullptr, "AcquireStateLock"},
- {11, nullptr, "HasStateLock"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class IPmModule final : public ServiceFramework<IPmModule> {
-public:
- explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {1, nullptr, "GetRequest"},
- {2, nullptr, "Acknowledge"},
- {3, nullptr, "Finalize"},
- {4, nullptr, "AcknowledgeEx"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class IPmService final : public ServiceFramework<IPmService> {
-public:
- explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IPmService::GetPmModule, "GetPmModule"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void GetPmModule(HLERequestContext& ctx) {
- LOG_DEBUG(Service_PSC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IPmModule>(system);
- }
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
+ server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
+ server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));
auto time = std::make_shared<Time::TimeManager>(system);
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 {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::PSC {
void 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) {
Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
Out<bool> out_is_enabled) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled);
+ };
R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
@@ -180,7 +182,9 @@ Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
}
Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
+ };
*out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
@@ -189,7 +193,9 @@ Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> o
Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Out<SteadyClockTimePoint> out_time_point) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
+ };
R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
@@ -200,7 +206,9 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
Out<s64> out_time, const SystemClockContext& context) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
+ };
R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
@@ -219,8 +227,9 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
}
Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
- SCOPE_EXIT(
- { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
+ };
SystemClockContext user_context{};
R_TRY(m_user_system_clock.GetContext(user_context));
@@ -234,11 +243,11 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
Result StaticService::GetClockSnapshotFromSystemClockContext(
TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
const SystemClockContext& network_context) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. type={} user_context={} network_context={} out_snapshot={}", type,
user_context, network_context, *out_snapshot);
- });
+ };
R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
}
@@ -246,9 +255,9 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
InClockSnapshot a,
InClockSnapshot b) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
- });
+ };
auto diff_s =
std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
@@ -276,7 +285,9 @@ Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64>
Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
InClockSnapshot b) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
+ };
s64 time_s{};
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
}
Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -38,7 +40,9 @@ Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point
}
Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -59,7 +63,9 @@ Result SteadyClock::SetTestOffset(s64 test_offset) {
}
Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -68,7 +74,9 @@ Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
}
Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -78,7 +86,9 @@ Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
}
Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -88,8 +98,9 @@ Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
}
Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) {
- SCOPE_EXIT(
- { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
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
}
Result SystemClock::GetCurrentTime(Out<s64> out_time) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
ResultClockUninitialized);
@@ -45,7 +47,9 @@ Result SystemClock::SetCurrentTime(s64 time) {
}
Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context);
+ };
R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
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&
}
Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
+ };
R_RETURN(m_time_zone.GetLocationName(*out_location_name));
}
@@ -50,7 +52,9 @@ Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name)
}
Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
+ };
R_RETURN(m_time_zone.GetTotalLocationCount(*out_count));
}
@@ -69,17 +73,19 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& l
}
Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) {
- SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); });
+ SCOPE_EXIT {
+ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
+ };
R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version));
}
Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}",
*out_location_name, *out_time_point);
- });
+ };
R_TRY(m_time_zone.GetLocationName(*out_location_name));
R_RETURN(m_time_zone.GetTimePoint(*out_time_point));
@@ -116,10 +122,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
Out<CalendarAdditionalInfo> out_additional_info, s64 time,
InRule rule) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
*out_calendar_time, *out_additional_info);
- });
+ };
R_RETURN(
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,
Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
Out<CalendarAdditionalInfo> out_additional_info,
s64 time) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
*out_calendar_time, *out_additional_info);
- });
+ };
R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time));
}
@@ -139,11 +145,11 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_
Result TimeZoneService::ToPosixTime(Out<u32> out_count,
OutArray<s64, BufferAttr_HipcPointer> out_times,
const CalendarTime& calendar_time, InRule rule) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
calendar_time, *out_count, out_times[0], out_times[1]);
- });
+ };
R_RETURN(
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,
Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
OutArray<s64, BufferAttr_HipcPointer> out_times,
const CalendarTime& calendar_time) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
LOG_DEBUG(Service_Time,
"called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
calendar_time, *out_count, out_times[0], out_times[1]);
- });
+ };
R_RETURN(
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,
Kernel::KPort::Register(m_system.Kernel(), port);
// Ensure that our reference to the port is closed if we fail to register it.
- SCOPE_EXIT({
+ SCOPE_EXIT {
port->GetClientPort().Close();
port->GetServerPort().Close();
- });
+ };
// Register the object name with the kernel.
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
}
Result ServerManager::LoopProcess() {
- SCOPE_EXIT({ m_stopped.Set(); });
+ SCOPE_EXIT {
+ m_stopped.Set();
+ };
R_RETURN(this->LoopProcessImpl());
}
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 @@
#include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/omm/omm.h"
#include "core/hle/service/pcie/pcie.h"
-#include "core/hle/service/pctl/pctl_module.h"
+#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/pm/pm.h"
#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 {
SystemRegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
- s64 posix_time;
- Service::PSC::Time::SteadyClockTimePoint timestamp;
+ Service::PSC::Time::SystemClockContext system_clock_context;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
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_)
RegisterHandlers(functions);
SetupSettings();
+
+ m_system_settings.region_code =
+ static_cast<SystemRegionCode>(Settings::values.region_index.GetValue());
+
+ // TODO: Remove this when starter applet is fully functional
+ EulaVersion eula_version{
+ .version = 0x10000,
+ .region_code = m_system_settings.region_code,
+ .clock_type = EulaVersionClockType::SteadyClock,
+ .system_clock_context = m_system_settings.user_system_clock_context,
+ };
+ m_system_settings.eula_versions[0] = eula_version;
+ m_system_settings.eula_version_count = 1;
+
m_save_thread =
std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
}
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 @@
#include "common/polyfill_thread.h"
#include "common/thread.h"
+#include "core/hle/service/vi/vsync_manager.h"
+
namespace Core {
class System;
}
@@ -26,7 +28,6 @@ namespace Service::VI {
class Container;
class DisplayList;
-class VsyncManager;
class Conductor {
public:
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() {
m_is_shut_down = true;
- m_layers.ForEachLayer([&](auto& layer) {
- if (layer.IsOpen()) {
- this->DestroyBufferQueueLocked(&layer);
- }
- });
+ m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); });
m_displays.ForEachDisplay(
[&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
@@ -161,16 +157,29 @@ Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner
auto* const display = m_displays.GetDisplayById(display_id);
R_UNLESS(display != nullptr, VI::ResultNotFound);
- auto* const layer = m_layers.CreateLayer(owner_aruid, display);
+ s32 consumer_binder_id, producer_binder_id;
+ m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
+
+ auto* const layer =
+ m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
R_UNLESS(layer != nullptr, VI::ResultNotFound);
+ m_surface_flinger->CreateLayer(consumer_binder_id);
+
*out_layer_id = layer->GetId();
R_SUCCEED();
}
Result Container::DestroyLayerLocked(u64 layer_id) {
- R_SUCCEED_IF(m_layers.DestroyLayer(layer_id));
- R_THROW(VI::ResultNotFound);
+ auto* const layer = m_layers.GetLayerById(layer_id);
+ R_UNLESS(layer != nullptr, VI::ResultNotFound);
+
+ m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
+ m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
+ layer->GetProducerBinderId());
+ m_layers.DestroyLayer(layer_id);
+
+ R_SUCCEED();
}
Result 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
R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
- this->CreateBufferQueueLocked(layer);
+ layer->Open();
+
+ if (auto* display = layer->GetDisplay(); display != nullptr) {
+ m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
+ }
+
*out_producer_binder_id = layer->GetProducerBinderId();
R_SUCCEED();
@@ -192,30 +206,14 @@ Result Container::CloseLayerLocked(u64 layer_id) {
R_UNLESS(layer != nullptr, VI::ResultNotFound);
R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
- this->DestroyBufferQueueLocked(layer);
-
- R_SUCCEED();
-}
-
-void Container::CreateBufferQueueLocked(Layer* layer) {
- s32 consumer_binder_id, producer_binder_id;
- m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
- layer->Open(consumer_binder_id, producer_binder_id);
-
- if (auto* display = layer->GetDisplay(); display != nullptr) {
- m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
- }
-}
-
-void Container::DestroyBufferQueueLocked(Layer* layer) {
if (auto* display = layer->GetDisplay(); display != nullptr) {
m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
layer->GetConsumerBinderId());
}
layer->Close();
- m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
- layer->GetProducerBinderId());
+
+ R_SUCCEED();
}
bool 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:
Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
Result CloseLayerLocked(u64 layer_id);
- void CreateBufferQueueLocked(Layer* layer);
- void DestroyBufferQueueLocked(Layer* layer);
-
public:
bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
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 {
public:
constexpr Layer() = default;
- void Initialize(u64 id, u64 owner_aruid, Display* display) {
+ void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id,
+ s32 producer_binder_id) {
m_id = id;
m_owner_aruid = owner_aruid;
m_display = display;
+ m_consumer_binder_id = consumer_binder_id;
+ m_producer_binder_id = producer_binder_id;
m_is_initialized = true;
}
void Finalize() {
m_id = {};
+ m_owner_aruid = {};
m_display = {};
+ m_consumer_binder_id = {};
+ m_producer_binder_id = {};
m_is_initialized = {};
}
- void Open(s32 consumer_binder_id, s32 producer_binder_id) {
- m_consumer_binder_id = consumer_binder_id;
- m_producer_binder_id = producer_binder_id;
+ void Open() {
m_is_open = true;
}
void Close() {
- m_producer_binder_id = {};
- m_consumer_binder_id = {};
- m_is_open = {};
+ m_is_open = false;
}
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 {
public:
constexpr LayerList() = default;
- Layer* CreateLayer(u64 owner_aruid, Display* display) {
+ Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id,
+ s32 producer_binder_id) {
Layer* const layer = GetFreeLayer();
if (!layer) {
return nullptr;
}
- layer->Initialize(++m_next_id, owner_aruid, display);
+ layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id,
+ producer_binder_id);
return layer;
}
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) {
auto& session = it->second;
// Destroy the layer.
- R_ASSERT(m_container.DestroyStrayLayer(session.layer_id));
+ m_container.DestroyStrayLayer(session.layer_id);
// Close nvmap handle.
FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -322,8 +322,6 @@ Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
std::array<s32, 4>& out_slot_indexes,
s64* out_target_slot, u64 layer_id) {
- std::scoped_lock lk{m_guard};
-
// Get the producer.
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -347,8 +345,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
Common::Rectangle<s32> crop_region,
u32 transform, s32 swap_interval, u64 layer_id,
s64 slot) {
- std::scoped_lock lk{m_guard};
-
// Get the producer.
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -379,8 +375,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
}
Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
- std::scoped_lock lk{m_guard};
-
// Get the producer.
std::shared_ptr<android::BufferQueueProducer> producer;
R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -394,8 +388,6 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
u64 layer_id) {
- std::scoped_lock lk{m_guard};
-
// Get the producer.
std::shared_ptr<android::BufferQueueProducer> producer;
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)>
mbedtls_sha256_starts_ret(&ctx, 0);
// Ensure we maintain a clean state on exit.
- SCOPE_EXIT({ mbedtls_sha256_free(&ctx); });
+ SCOPE_EXIT {
+ mbedtls_sha256_free(&ctx);
+ };
// Declare counters.
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 {
if (core == sys_core) [[unlikely]] {
sys_core_guard.lock();
}
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (core == sys_core) [[unlikely]] {
sys_core_guard.unlock();
}
- });
+ };
gpu_device_memory->ApplyOpOnPointer(p, scratch_buffers[core], [&](DAddr address) {
auto& current_area = rasterizer_write_areas[core];
PAddr subaddress = address >> YUZU_PAGEBITS;
@@ -866,11 +866,11 @@ struct Memory::Impl {
if (core == sys_core) [[unlikely]] {
sys_core_guard.lock();
}
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (core == sys_core) [[unlikely]] {
sys_core_guard.unlock();
}
- });
+ };
auto& gpu = system.GPU();
gpu_device_memory->ApplyOpOnPointer(
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) {
// If we've ever seen a decode failure, return false.
bool valid = decode_success;
CheatVmOpcode opcode = {};
- SCOPE_EXIT({
+ SCOPE_EXIT {
decode_success &= valid;
if (valid) {
out = opcode;
}
- });
+ };
// Helper function for getting instruction dwords.
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,
if (index >= controller.stick_values.size()) {
return;
}
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring);
+ };
std::scoped_lock lock{mutex};
const auto stick_value = TransformToStick(callback);
@@ -989,8 +990,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
if (index >= controller.trigger_values.size()) {
return;
}
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring);
+ };
std::scoped_lock lock{mutex};
const auto trigger_value = TransformToTrigger(callback);
@@ -1036,7 +1038,9 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
if (index >= controller.motion_values.size()) {
return;
}
- SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
+ SCOPE_EXIT {
+ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring);
+ };
std::scoped_lock lock{mutex};
auto& raw_status = controller.motion_values[index].raw_status;
auto& emulated = controller.motion_values[index].emulated;
@@ -1070,8 +1074,9 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
if (index >= controller.color_values.size()) {
return;
}
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Color, !is_configuring);
+ };
std::scoped_lock lock{mutex};
controller.color_values[index] = TransformToColor(callback);
@@ -1120,7 +1125,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
if (index >= controller.battery_values.size()) {
return;
}
- SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
+ SCOPE_EXIT {
+ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring);
+ };
std::scoped_lock lock{mutex};
controller.battery_values[index] = TransformToBattery(callback);
@@ -1183,7 +1190,9 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
}
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
- SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
+ SCOPE_EXIT {
+ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring);
+ };
std::scoped_lock lock{mutex};
controller.camera_values = TransformToCamera(callback);
@@ -1198,7 +1207,9 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
}
void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
- SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
+ SCOPE_EXIT {
+ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring);
+ };
std::scoped_lock lock{mutex};
const auto force_value = TransformToStick(callback);
@@ -1212,7 +1223,9 @@ void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& call
}
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
- SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
+ SCOPE_EXIT {
+ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring);
+ };
std::scoped_lock lock{mutex};
controller.nfc_values = TransformToNfc(callback);
@@ -1685,8 +1698,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
return;
}
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring);
+ };
std::scoped_lock lock{connect_mutex, mutex};
if (is_configuring) {
tmp_is_connected = true;
@@ -1701,8 +1715,9 @@ void EmulatedController::Connect(bool use_temporary_value) {
}
void EmulatedController::Disconnect() {
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring);
+ };
std::scoped_lock lock{connect_mutex, mutex};
if (is_configuring) {
tmp_is_connected = false;
@@ -1738,8 +1753,9 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
}
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
- auto trigger_guard =
- SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
+ auto trigger_guard = SCOPE_GUARD {
+ TriggerOnChange(ControllerTriggerType::Type, !is_configuring);
+ };
std::scoped_lock lock{mutex, npad_mutex};
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 @@
#include <set>
#include <common/settings_input.h>
+#include <common/thread.h>
#include <jni.h>
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
@@ -10,7 +11,18 @@
namespace InputCommon {
-Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
+Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
+ vibration_thread = std::jthread([this](std::stop_token token) {
+ Common::SetCurrentThreadName("Android_Vibration");
+ auto env = Common::Android::GetEnvForThread();
+ using namespace std::chrono_literals;
+ while (!token.stop_requested()) {
+ SendVibrations(env, token);
+ }
+ });
+}
+
+Android::~Android() = default;
void Android::RegisterController(jobject j_input_device) {
auto env = Common::Android::GetEnvForThread();
@@ -57,17 +69,11 @@ void Android::SetMotionState(std::string guid, size_t port, u64 delta_timestamp,
Common::Input::DriverResult Android::SetVibration(
[[maybe_unused]] const PadIdentifier& identifier,
[[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
- auto device = input_devices.find(identifier);
- if (device != input_devices.end()) {
- Common::Android::RunJNIOnFiber<void>([&](JNIEnv* env) {
- float average_intensity =
- static_cast<float>((vibration.high_amplitude + vibration.low_amplitude) / 2.0);
- env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
- average_intensity);
- });
- return Common::Input::DriverResult::Success;
- }
- return Common::Input::DriverResult::NotSupported;
+ vibration_queue.Push(VibrationRequest{
+ .identifier = identifier,
+ .vibration = vibration,
+ });
+ return Common::Input::DriverResult::Success;
}
bool Android::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
@@ -347,4 +353,15 @@ PadIdentifier Android::GetIdentifier(const std::string& guid, size_t port) const
};
}
+void Android::SendVibrations(JNIEnv* env, std::stop_token token) {
+ VibrationRequest request = vibration_queue.PopWait(token);
+ auto device = input_devices.find(request.identifier);
+ if (device != input_devices.end()) {
+ float average_intensity = static_cast<float>(
+ (request.vibration.high_amplitude + request.vibration.low_amplitude) / 2.0);
+ env->CallVoidMethod(device->second, Common::Android::GetYuzuDeviceVibrate(),
+ average_intensity);
+ }
+}
+
} // 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 @@
#pragma once
#include <set>
+#include <common/threadsafe_queue.h>
#include <jni.h>
#include "input_common/input_engine.h"
@@ -16,6 +17,8 @@ class Android final : public InputEngine {
public:
explicit Android(std::string input_engine_);
+ ~Android() override;
+
/**
* Registers controller number to accept new inputs.
* @param j_input_device YuzuInputDevice object from the Android frontend to register.
@@ -89,6 +92,9 @@ private:
/// Returns the correct identifier corresponding to the player index
PadIdentifier GetIdentifier(const std::string& guid, size_t port) const;
+ /// Takes all vibrations from the queue and sends the command to the controller
+ void SendVibrations(JNIEnv* env, std::stop_token token);
+
static constexpr s32 AXIS_X = 0;
static constexpr s32 AXIS_Y = 1;
static constexpr s32 AXIS_Z = 11;
@@ -133,6 +139,10 @@ private:
redmagic_vid, backbone_labs_vid, xbox_vid};
const std::vector<std::string> flipped_xy_vids{sony_vid, razer_vid, redmagic_vid,
backbone_labs_vid, xbox_vid};
+
+ /// Queue of vibration request to controllers
+ Common::SPSCQueue<VibrationRequest> vibration_queue;
+ std::jthread vibration_thread;
};
} // 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:
bool IsVibrationEnabled(const PadIdentifier& identifier) override;
private:
- struct VibrationRequest {
- PadIdentifier identifier;
- Common::Input::VibrationStatus vibration;
- };
-
void InitJoystick(int joystick_index);
void CloseJoystick(SDL_Joystick* sdl_joystick);
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) {
}
Common::Input::DriverResult JoyconDriver::SetPollingMode() {
- SCOPE_EXIT({ disable_input_thread = false; });
+ SCOPE_EXIT {
+ disable_input_thread = false;
+ };
disable_input_thread = true;
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 {
Nfc,
};
+struct VibrationRequest {
+ PadIdentifier identifier;
+ Common::Input::VibrationStatus vibration;
+};
+
namespace std {
// Hash used to create lists from PadIdentifier data
template <>
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) {
case Stage::Geometry:
execution_model = spv::ExecutionModel::Geometry;
ctx.AddCapability(spv::Capability::Geometry);
- ctx.AddCapability(spv::Capability::GeometryStreams);
+ if (ctx.profile.support_geometry_streams) {
+ ctx.AddCapability(spv::Capability::GeometryStreams);
+ }
switch (ctx.runtime_info.input_topology) {
case InputTopology::Points:
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) {
if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
ConvertDepthMode(ctx);
}
- if (stream.IsImmediate()) {
+ if (!ctx.profile.support_geometry_streams) {
+ throw NotImplementedException("Geometry streams");
+ } else if (stream.IsImmediate()) {
ctx.OpEmitStreamVertex(ctx.Def(stream));
} else {
LOG_WARNING(Shader_SPIRV, "Stream is not immediate");
@@ -140,7 +142,9 @@ void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
}
void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) {
- if (stream.IsImmediate()) {
+ if (!ctx.profile.support_geometry_streams) {
+ throw NotImplementedException("Geometry streams");
+ } else if (stream.IsImmediate()) {
ctx.OpEndStreamPrimitive(ctx.Def(stream));
} else {
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 {
bool support_gl_derivative_control{};
bool support_scaled_attributes{};
bool support_multi_viewport{};
+ bool support_geometry_streams{};
bool warp_size_potentially_larger_than_guest{};
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
const s64 min_spacing_critical = device_local_memory - 512_MiB;
const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
- const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
+ const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
minimum_memory = static_cast<u64>(
std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
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) {
}
void Maxwell3D::ConsumeSinkImpl() {
- SCOPE_EXIT({ method_sink.clear(); });
+ SCOPE_EXIT {
+ method_sink.clear();
+ };
const auto control = shadow_state.shadow_ram_control;
if (control == Regs::ShadowRamControl::Track ||
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:
MicroProfileOnThreadCreate(name.c_str());
// Cleanup
- SCOPE_EXIT({ MicroProfileOnThreadExit(); });
+ SCOPE_EXIT {
+ MicroProfileOnThreadExit();
+ };
Common::SetCurrentThreadName(name.c_str());
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,
Tegra::Control::Scheduler& scheduler, SynchState& state) {
std::string name = "GPU";
MicroProfileOnThreadCreate(name.c_str());
- SCOPE_EXIT({ MicroProfileOnThreadExit(); });
+ SCOPE_EXIT {
+ MicroProfileOnThreadExit();
+ };
Common::SetCurrentThreadName(name.c_str());
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) {
const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
AVFilterInOut* inputs = avfilter_inout_alloc();
AVFilterInOut* outputs = avfilter_inout_alloc();
- SCOPE_EXIT({
+ SCOPE_EXIT {
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
- });
+ };
// Don't know how to get the accurate time_base but it doesn't matter for yadif filter
// 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:
private:
void Fallback(const std::vector<u32>& parameters) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (extended) {
maxwell3d.engine_state = Maxwell3D::EngineHint::None;
maxwell3d.replace_table.clear();
}
- });
+ };
maxwell3d.RefreshParameters();
const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]);
@@ -281,12 +281,12 @@ public:
private:
void Fallback(const std::vector<u32>& parameters) {
- SCOPE_EXIT({
+ SCOPE_EXIT {
// Clean everything.
maxwell3d.regs.vertex_id_base = 0x0;
maxwell3d.engine_state = Maxwell3D::EngineHint::None;
maxwell3d.replace_table.clear();
- });
+ };
maxwell3d.RefreshParameters();
const u32 start_indirect = parameters[0];
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>
void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
MICROPROFILE_SCOPE(OpenGL_Drawing);
- SCOPE_EXIT({ gpu.TickWork(); });
+ SCOPE_EXIT {
+ gpu.TickWork();
+ };
gpu_memory->FlushCaching();
GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
@@ -355,7 +357,9 @@ void RasterizerOpenGL::DrawIndirect() {
void RasterizerOpenGL::DrawTexture() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
- SCOPE_EXIT({ gpu.TickWork(); });
+ SCOPE_EXIT {
+ gpu.TickWork();
+ };
texture_cache.SynchronizeGraphicsDescriptors();
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,
// Finish any pending renderpass
scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Wait(resource_ticks[image_index]);
- SCOPE_EXIT({ resource_ticks[image_index] = scheduler.CurrentTick(); });
+ SCOPE_EXIT {
+ resource_ticks[image_index] = scheduler.CurrentTick();
+ };
if (!use_accelerated) {
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
return;
}
- SCOPE_EXIT({ render_window.OnFrameDisplayed(); });
+ SCOPE_EXIT {
+ render_window.OnFrameDisplayed();
+ };
RenderAppletCaptureLayer(framebuffers);
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_,
.support_native_ndc = device.IsExtDepthClipControlSupported(),
.support_scaled_attributes = !device.MustEmulateScaledFormats(),
.support_multi_viewport = device.SupportsMultiViewport(),
+ .support_geometry_streams = device.AreTransformFeedbackGeometryStreamsSupported(),
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
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>
void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
MICROPROFILE_SCOPE(Vulkan_Drawing);
- SCOPE_EXIT({ gpu.TickWork(); });
+ SCOPE_EXIT {
+ gpu.TickWork();
+ };
FlushWork();
gpu_memory->FlushCaching();
@@ -288,7 +290,9 @@ void RasterizerVulkan::DrawIndirect() {
void RasterizerVulkan::DrawTexture() {
MICROPROFILE_SCOPE(Vulkan_Drawing);
- SCOPE_EXIT({ gpu.TickWork(); });
+ SCOPE_EXIT {
+ gpu.TickWork();
+ };
FlushWork();
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 @@
#include "common/common_types.h"
#include "common/math_util.h"
+#include "common/settings.h"
#include "video_core/surface.h"
namespace VideoCore::Surface {
@@ -400,11 +401,20 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
}
-u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) {
+u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
constexpr u64 RGBA8_PIXEL_SIZE = 4;
const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
- return (base_size * base_block_size) / BytesPerBlock(format);
+ const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
+
+ switch (Settings::values.astc_recompression.GetValue()) {
+ case Settings::AstcRecompression::Bc1:
+ return uncompressed_size / 8;
+ case Settings::AstcRecompression::Bc3:
+ return uncompressed_size / 4;
+ default:
+ return uncompressed_size;
+ }
}
} // 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);
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
-u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format);
+u64 TranscodedAstcSize(u64 base_size, PixelFormat format);
} // 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
const s64 min_spacing_critical = device_local_memory - 512_MiB;
const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
- const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
+ const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
expected_memory = static_cast<u64>(
std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
DEFAULT_EXPECTED_MEMORY));
@@ -1979,7 +1979,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
- tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
+ tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory += Common::AlignUp(tentative_size, 1024);
image.lru_index = lru_cache.Insert(image_id, frame_tick);
@@ -2149,7 +2149,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
- tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
+ tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory -= Common::AlignUp(tentative_size, 1024);
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,
LOG_ERROR(Render_Vulkan, "Failed to create decoder");
return;
}
- SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); });
+ SCOPE_EXIT {
+ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder);
+ };
u32 json_size = 0;
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 {
}
void Device::CollectPhysicalMemoryInfo() {
- // Account for resolution scaling in memory limits
- const size_t normal_memory = 6_GiB;
- const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
-
// Calculate limits using memory budget
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@@ -1331,7 +1327,15 @@ void Device::CollectPhysicalMemoryInfo() {
if (!is_integrated) {
const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
device_access_memory -= reserve_memory;
- device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory);
+
+ if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
+ // Account for resolution scaling in memory limits
+ const size_t normal_memory = 6_GiB;
+ const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
+ device_access_memory =
+ std::min<u64>(device_access_memory, normal_memory + scaler_memory);
+ }
+
return;
}
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:
return extensions.transform_feedback;
}
+ /// Returns true if the device supports VK_EXT_transform_feedback properly.
+ bool AreTransformFeedbackGeometryStreamsSupported() const {
+ return features.transform_feedback.geometryStreams;
+ }
+
/// Returns true if the device supports VK_EXT_custom_border_color.
bool IsExtCustomBorderColorSupported() const {
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) {
"the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
"This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
"negatively affecting image quality."));
+ INSERT(Settings, vram_usage_mode, tr("VRAM Usage Mode:"),
+ tr("Selects whether the emulator should prefer to conserve memory or make maximum usage "
+ "of available video memory for performance. Has no effect on integrated graphics. "
+ "Aggressive mode may severely impact the performance of other applications such as "
+ "recording software."));
INSERT(
Settings, vsync_mode, tr("VSync Mode:"),
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) {
PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
}});
+ translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
+ {
+ PAIR(VramUsageMode, Conservative, tr("Conservative")),
+ PAIR(VramUsageMode, Aggressive, tr("Aggressive")),
+ }});
translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
{
#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
std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
cabinet_applet =
new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
- SCOPE_EXIT({
+ SCOPE_EXIT {
cabinet_applet->deleteLater();
cabinet_applet = nullptr;
- });
+ };
cabinet_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@@ -673,10 +673,10 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) {
controller_applet =
new QtControllerSelectorDialog(this, parameters, input_subsystem.get(), *system);
- SCOPE_EXIT({
+ SCOPE_EXIT {
controller_applet->deleteLater();
controller_applet = nullptr;
- });
+ };
controller_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -703,10 +703,10 @@ void GMainWindow::ControllerSelectorRequestExit() {
void GMainWindow::ProfileSelectorSelectProfile(
const Core::Frontend::ProfileSelectParameters& parameters) {
profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters);
- SCOPE_EXIT({
+ SCOPE_EXIT {
profile_select_applet->deleteLater();
profile_select_applet = nullptr;
- });
+ };
profile_select_applet->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint |
Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
@@ -1604,6 +1604,7 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
connect_menu(ui->action_Install_Firmware, &GMainWindow::OnInstallFirmware);
+ connect_menu(ui->action_Install_Keys, &GMainWindow::OnInstallDecryptionKeys);
connect_menu(ui->action_About, &GMainWindow::OnAbout);
}
@@ -1633,6 +1634,7 @@ void GMainWindow::UpdateMenuState() {
}
ui->action_Install_Firmware->setEnabled(!emulation_running);
+ ui->action_Install_Keys->setEnabled(!emulation_running);
for (QAction* action : applet_actions) {
action->setEnabled(is_firmware_available && !emulation_running);
@@ -2323,15 +2325,15 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
- {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
- FileSys::SaveDataType::SaveData, program_id, user_id->AsU128(), 0);
+ {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
+ program_id, user_id->AsU128(), 0);
path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
} else {
// Device save data
const auto device_save_data_path = FileSys::SaveDataFactory::GetFullPath(
- {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
- FileSys::SaveDataType::SaveData, program_id, {}, 0);
+ {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account,
+ program_id, {}, 0);
path = Common::FS::ConcatPathSafe(nand_dir, device_save_data_path);
}
@@ -2672,7 +2674,7 @@ void GMainWindow::RemoveCacheStorage(u64 program_id) {
vfs->OpenDirectory(Common::FS::PathToUTF8String(nand_dir), FileSys::OpenMode::Read);
const auto cache_storage_path = FileSys::SaveDataFactory::GetFullPath(
- {}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::CacheStorage,
+ {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Cache,
0 /* program_id */, {}, 0);
const auto path = Common::FS::ConcatPathSafe(nand_dir, cache_storage_path);
@@ -2885,17 +2887,19 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
LOG_ERROR(Frontend, "CoInitialize failed");
return false;
}
- SCOPE_EXIT({ CoUninitialize(); });
+ SCOPE_EXIT {
+ CoUninitialize();
+ };
IShellLinkW* ps1 = nullptr;
IPersistFile* persist_file = nullptr;
- SCOPE_EXIT({
+ SCOPE_EXIT {
if (persist_file != nullptr) {
persist_file->Release();
}
if (ps1 != nullptr) {
ps1->Release();
}
- });
+ };
HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
reinterpret_cast<void**>(&ps1));
if (FAILED(hres)) {
@@ -3006,9 +3010,6 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
GameListShortcutTarget target) {
- std::string game_title;
- QString qt_game_title;
- std::filesystem::path out_icon_path;
// Get path to yuzu executable
const QStringList args = QApplication::arguments();
std::filesystem::path yuzu_command = args[0].toStdString();
@@ -3025,48 +3026,51 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
shortcut_path =
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
}
- // Icon path and title
- if (std::filesystem::exists(shortcut_path)) {
- // Get title from game file
- const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
- system->GetContentProvider()};
- const auto control = pm.GetControlMetadata();
- const auto loader =
- Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
- game_title = fmt::format("{:016X}", program_id);
- if (control.first != nullptr) {
- game_title = control.first->GetApplicationName();
- } else {
- loader->ReadTitle(game_title);
- }
- // Delete illegal characters from title
- const std::string illegal_chars = "<>:\"/\\|?*.";
- for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
- if (illegal_chars.find(*it) != std::string::npos) {
- game_title.erase(it.base() - 1);
- }
- }
- qt_game_title = QString::fromStdString(game_title);
- // Get icon from game file
- std::vector<u8> icon_image_file{};
- if (control.second != nullptr) {
- icon_image_file = control.second->ReadAllBytes();
- } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
- LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
+
+ if (!std::filesystem::exists(shortcut_path)) {
+ GMainWindow::CreateShortcutMessagesGUI(
+ this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
+ QString::fromStdString(shortcut_path.generic_string()));
+ LOG_ERROR(Frontend, "Invalid shortcut target {}", shortcut_path.generic_string());
+ return;
+ }
+
+ // Get title from game file
+ const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
+ system->GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ const auto loader =
+ Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::OpenMode::Read));
+ std::string game_title = fmt::format("{:016X}", program_id);
+ if (control.first != nullptr) {
+ game_title = control.first->GetApplicationName();
+ } else {
+ loader->ReadTitle(game_title);
+ }
+ // Delete illegal characters from title
+ const std::string illegal_chars = "<>:\"/\\|?*.";
+ for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
+ if (illegal_chars.find(*it) != std::string::npos) {
+ game_title.erase(it.base() - 1);
}
- QImage icon_data =
- QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
- if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
- if (!SaveIconToFile(out_icon_path, icon_data)) {
- LOG_ERROR(Frontend, "Could not write icon to file");
- }
+ }
+ const QString qt_game_title = QString::fromStdString(game_title);
+ // Get icon from game file
+ std::vector<u8> icon_image_file{};
+ if (control.second != nullptr) {
+ icon_image_file = control.second->ReadAllBytes();
+ } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
+ LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
+ }
+ QImage icon_data =
+ QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
+ std::filesystem::path out_icon_path;
+ if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
+ if (!SaveIconToFile(out_icon_path, icon_data)) {
+ LOG_ERROR(Frontend, "Could not write icon to file");
}
- } else {
- GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
- qt_game_title);
- LOG_ERROR(Frontend, "Invalid shortcut target");
- return;
}
+
#if defined(__linux__)
// Special case for AppImages
// Warn once if we are making a shortcut to a volatile AppImage
@@ -3520,10 +3524,10 @@ void GMainWindow::OnSaveConfig() {
void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
error_applet = new OverlayDialog(render_window, *system, error_code, error_text, QString{},
tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
- SCOPE_EXIT({
+ SCOPE_EXIT {
error_applet->deleteLater();
error_applet = nullptr;
- });
+ };
error_applet->exec();
emit ErrorDisplayFinished();
@@ -4167,9 +4171,8 @@ void GMainWindow::OnInstallFirmware() {
return;
}
- QString firmware_source_location =
- QFileDialog::getExistingDirectory(this, tr("Select Dumped Firmware Source Location"),
- QString::fromStdString(""), QFileDialog::ShowDirsOnly);
+ const QString firmware_source_location = QFileDialog::getExistingDirectory(
+ this, tr("Select Dumped Firmware Source Location"), {}, QFileDialog::ShowDirsOnly);
if (firmware_source_location.isEmpty()) {
return;
}
@@ -4200,8 +4203,9 @@ void GMainWindow::OnInstallFirmware() {
std::vector<std::filesystem::path> out;
const Common::FS::DirEntryCallable callback =
[&out](const std::filesystem::directory_entry& entry) {
- if (entry.path().has_extension() && entry.path().extension() == ".nca")
+ if (entry.path().has_extension() && entry.path().extension() == ".nca") {
out.emplace_back(entry.path());
+ }
return true;
};
@@ -4233,7 +4237,6 @@ void GMainWindow::OnInstallFirmware() {
auto firmware_vdir = sysnand_content_vdir->GetDirectoryRelative("registered");
bool success = true;
- bool cancelled = false;
int i = 0;
for (const auto& firmware_src_path : out) {
i++;
@@ -4248,24 +4251,22 @@ void GMainWindow::OnInstallFirmware() {
success = false;
}
- if (QtProgressCallback(100, 20 + (int)(((float)(i) / (float)out.size()) * 70.0))) {
- success = false;
- cancelled = true;
- break;
+ if (QtProgressCallback(
+ 100, 20 + static_cast<int>(((i) / static_cast<float>(out.size())) * 70.0))) {
+ progress.close();
+ QMessageBox::warning(
+ this, tr("Firmware install failed"),
+ tr("Firmware installation cancelled, firmware may be in bad state, "
+ "restart yuzu or re-install firmware."));
+ return;
}
}
- if (!success && !cancelled) {
+ if (!success) {
progress.close();
QMessageBox::critical(this, tr("Firmware install failed"),
tr("One or more firmware files failed to copy into NAND."));
return;
- } else if (cancelled) {
- progress.close();
- QMessageBox::warning(this, tr("Firmware install failed"),
- tr("Firmware installation cancelled, firmware may be in bad state, "
- "restart yuzu or re-install firmware."));
- return;
}
// Re-scan VFS for the newly placed firmware files.
@@ -4293,6 +4294,84 @@ void GMainWindow::OnInstallFirmware() {
OnCheckFirmwareDecryption();
}
+void GMainWindow::OnInstallDecryptionKeys() {
+ // Don't do this while emulation is running.
+ if (emu_thread != nullptr && emu_thread->IsRunning()) {
+ return;
+ }
+
+ const QString key_source_location = QFileDialog::getOpenFileName(
+ this, tr("Select Dumped Keys Location"), {}, QStringLiteral("prod.keys (prod.keys)"), {},
+ QFileDialog::ReadOnly);
+ if (key_source_location.isEmpty()) {
+ return;
+ }
+
+ // Verify that it contains prod.keys, title.keys and optionally, key_retail.bin
+ LOG_INFO(Frontend, "Installing key files from {}", key_source_location.toStdString());
+
+ const std::filesystem::path prod_key_path = key_source_location.toStdString();
+ const std::filesystem::path key_source_path = prod_key_path.parent_path();
+ if (!Common::FS::IsDir(key_source_path)) {
+ return;
+ }
+
+ bool prod_keys_found = false;
+ std::vector<std::filesystem::path> source_key_files;
+
+ if (Common::FS::Exists(prod_key_path)) {
+ prod_keys_found = true;
+ source_key_files.emplace_back(prod_key_path);
+ }
+
+ if (Common::FS::Exists(key_source_path / "title.keys")) {
+ source_key_files.emplace_back(key_source_path / "title.keys");
+ }
+
+ if (Common::FS::Exists(key_source_path / "key_retail.bin")) {
+ source_key_files.emplace_back(key_source_path / "key_retail.bin");
+ }
+
+ // There should be at least prod.keys.
+ if (source_key_files.empty() || !prod_keys_found) {
+ QMessageBox::warning(this, tr("Decryption Keys install failed"),
+ tr("prod.keys is a required decryption key file."));
+ return;
+ }
+
+ const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
+ for (auto key_file : source_key_files) {
+ std::filesystem::path destination_key_file = yuzu_keys_dir / key_file.filename();
+ if (!std::filesystem::copy_file(key_file, destination_key_file,
+ std::filesystem::copy_options::overwrite_existing)) {
+ LOG_ERROR(Frontend, "Failed to copy file {} to {}", key_file.string(),
+ destination_key_file.string());
+ QMessageBox::critical(this, tr("Decryption Keys install failed"),
+ tr("One or more keys failed to copy."));
+ return;
+ }
+ }
+
+ // Reinitialize the key manager, re-read the vfs (for update/dlc files),
+ // and re-populate the game list in the UI if the user has already added
+ // game folders.
+ Core::Crypto::KeyManager::Instance().ReloadKeys();
+ system->GetFileSystemController().CreateFactories(*vfs);
+ game_list->PopulateAsync(UISettings::values.game_dirs);
+
+ if (ContentManager::AreKeysPresent()) {
+ QMessageBox::information(this, tr("Decryption Keys install succeeded"),
+ tr("Decryption Keys were successfully installed"));
+ } else {
+ QMessageBox::critical(
+ this, tr("Decryption Keys install failed"),
+ tr("Decryption Keys failed to initialize. Check that your dumping tools are "
+ "up to date and re-dump keys."));
+ }
+
+ OnCheckFirmwareDecryption();
+}
+
void GMainWindow::OnAbout() {
AboutDialog aboutDialog(this);
aboutDialog.exec();
@@ -5192,7 +5271,9 @@ int main(int argc, char* argv[]) {
Common::DetachedTasks detached_tasks;
MicroProfileOnThreadCreate("Frontend");
- SCOPE_EXIT({ MicroProfileShutdown(); });
+ SCOPE_EXIT {
+ MicroProfileShutdown();
+ };
Common::ConfigureNvidiaEnvironmentFlags();
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:
void OnOpenYuzuFolder();
void OnVerifyInstalledContents();
void OnInstallFirmware();
+ void OnInstallDecryptionKeys();
void OnAbout();
void OnToggleFilterBar();
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 @@
<addaction name="separator"/>
<addaction name="action_Configure_Tas"/>
</widget>
- <addaction name="action_Verify_installed_contents"/>
+ <addaction name="action_Install_Keys"/>
<addaction name="action_Install_Firmware"/>
+ <addaction name="action_Verify_installed_contents"/>
<addaction name="separator"/>
<addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/>
@@ -469,6 +470,11 @@
<string>Install Firmware</string>
</property>
</action>
+ <action name="action_Install_Keys">
+ <property name="text">
+ <string>Install Decryption Keys</string>
+ </property>
+ </action>
</widget>
<resources>
<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) {
#endif
MicroProfileOnThreadCreate("EmuThread");
- SCOPE_EXIT({ MicroProfileShutdown(); });
+ SCOPE_EXIT {
+ MicroProfileShutdown();
+ };
Common::ConfigureNvidiaEnvironmentFlags();