summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-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
161 files changed, 5101 insertions, 4272 deletions
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index 472e8571c..3e01e3b67 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -24,7 +24,9 @@ Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
24 // Create a session request. 24 // Create a session request.
25 KSessionRequest* request = KSessionRequest::Create(m_kernel); 25 KSessionRequest* request = KSessionRequest::Create(m_kernel);
26 R_UNLESS(request != nullptr, ResultOutOfResource); 26 R_UNLESS(request != nullptr, ResultOutOfResource);
27 SCOPE_EXIT({ request->Close(); }); 27 SCOPE_EXIT {
28 request->Close();
29 };
28 30
29 // Initialize the request. 31 // Initialize the request.
30 request->Initialize(nullptr, address, size); 32 request->Initialize(nullptr, address, size);
@@ -37,7 +39,9 @@ Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t
37 // Create a session request. 39 // Create a session request.
38 KSessionRequest* request = KSessionRequest::Create(m_kernel); 40 KSessionRequest* request = KSessionRequest::Create(m_kernel);
39 R_UNLESS(request != nullptr, ResultOutOfResource); 41 R_UNLESS(request != nullptr, ResultOutOfResource);
40 SCOPE_EXIT({ request->Close(); }); 42 SCOPE_EXIT {
43 request->Close();
44 };
41 45
42 // Initialize the request. 46 // Initialize the request.
43 request->Initialize(event, address, size); 47 request->Initialize(event, address, size);
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 1dd86fb3c..19cdf4f3a 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -1305,11 +1305,11 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
1305 1305
1306 // Ensure that we maintain the instruction cache. 1306 // Ensure that we maintain the instruction cache.
1307 bool reprotected_pages = false; 1307 bool reprotected_pages = false;
1308 SCOPE_EXIT({ 1308 SCOPE_EXIT {
1309 if (reprotected_pages && any_code_pages) { 1309 if (reprotected_pages && any_code_pages) {
1310 InvalidateInstructionCache(m_kernel, this, dst_address, size); 1310 InvalidateInstructionCache(m_kernel, this, dst_address, size);
1311 } 1311 }
1312 }); 1312 };
1313 1313
1314 // Unmap. 1314 // Unmap.
1315 { 1315 {
@@ -1397,7 +1397,9 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
1397 // Close the opened pages when we're done with them. 1397 // Close the opened pages when we're done with them.
1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 1398 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
1399 // automatically. 1399 // automatically.
1400 SCOPE_EXIT({ pg.Close(); }); 1400 SCOPE_EXIT {
1401 pg.Close();
1402 };
1401 1403
1402 // Clear all the newly allocated pages. 1404 // Clear all the newly allocated pages.
1403 for (const auto& it : pg) { 1405 for (const auto& it : pg) {
@@ -1603,7 +1605,9 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
1603 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); 1605 m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
1604 1606
1605 // Ensure that the page group is closed when we're done working with it. 1607 // Ensure that the page group is closed when we're done working with it.
1606 SCOPE_EXIT({ pg.Close(); }); 1608 SCOPE_EXIT {
1609 pg.Close();
1610 };
1607 1611
1608 // Clear all pages. 1612 // Clear all pages.
1609 for (const auto& it : pg) { 1613 for (const auto& it : pg) {
@@ -2191,7 +2195,9 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
2191 // Close the opened pages when we're done with them. 2195 // Close the opened pages when we're done with them.
2192 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed 2196 // If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
2193 // automatically. 2197 // automatically.
2194 SCOPE_EXIT({ pg.Close(); }); 2198 SCOPE_EXIT {
2199 pg.Close();
2200 };
2195 2201
2196 // Clear all the newly allocated pages. 2202 // Clear all the newly allocated pages.
2197 for (const auto& it : pg) { 2203 for (const auto& it : pg) {
@@ -2592,7 +2598,9 @@ Result KPageTableBase::UnmapIoRegion(KProcessAddress dst_address, KPhysicalAddre
2592 // Temporarily unlock ourselves, so that other operations can occur while we flush the 2598 // Temporarily unlock ourselves, so that other operations can occur while we flush the
2593 // region. 2599 // region.
2594 m_general_lock.Unlock(); 2600 m_general_lock.Unlock();
2595 SCOPE_EXIT({ m_general_lock.Lock(); }); 2601 SCOPE_EXIT {
2602 m_general_lock.Lock();
2603 };
2596 2604
2597 // Flush the region. 2605 // Flush the region.
2598 R_ASSERT(FlushDataCache(dst_address, size)); 2606 R_ASSERT(FlushDataCache(dst_address, size));
@@ -3311,10 +3319,10 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre
3311 // Ensure we unmap the io memory when we're done with it. 3319 // Ensure we unmap the io memory when we're done with it.
3312 const KPageProperties unmap_properties = 3320 const KPageProperties unmap_properties =
3313 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3321 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3314 SCOPE_EXIT({ 3322 SCOPE_EXIT {
3315 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3323 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3316 unmap_properties, OperationType::Unmap, true)); 3324 unmap_properties, OperationType::Unmap, true));
3317 }); 3325 };
3318 3326
3319 // Read the memory. 3327 // Read the memory.
3320 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3328 const KProcessAddress read_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -3347,10 +3355,10 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd
3347 // Ensure we unmap the io memory when we're done with it. 3355 // Ensure we unmap the io memory when we're done with it.
3348 const KPageProperties unmap_properties = 3356 const KPageProperties unmap_properties =
3349 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None}; 3357 KPageProperties{KMemoryPermission::None, false, false, DisableMergeAttribute::None};
3350 SCOPE_EXIT({ 3358 SCOPE_EXIT {
3351 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false, 3359 R_ASSERT(this->Operate(updater.GetPageList(), io_addr, map_size / PageSize, 0, false,
3352 unmap_properties, OperationType::Unmap, true)); 3360 unmap_properties, OperationType::Unmap, true));
3353 }); 3361 };
3354 3362
3355 // Write the memory. 3363 // Write the memory.
3356 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1)); 3364 const KProcessAddress write_addr = io_addr + (GetInteger(phys_addr) & (PageSize - 1));
@@ -4491,14 +4499,14 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
4491 4499
4492 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll 4500 // If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
4493 // free on scope exit. 4501 // free on scope exit.
4494 SCOPE_EXIT({ 4502 SCOPE_EXIT {
4495 if (start_partial_page != 0) { 4503 if (start_partial_page != 0) {
4496 m_kernel.MemoryManager().Close(start_partial_page, 1); 4504 m_kernel.MemoryManager().Close(start_partial_page, 1);
4497 } 4505 }
4498 if (end_partial_page != 0) { 4506 if (end_partial_page != 0) {
4499 m_kernel.MemoryManager().Close(end_partial_page, 1); 4507 m_kernel.MemoryManager().Close(end_partial_page, 1);
4500 } 4508 }
4501 }); 4509 };
4502 4510
4503 ON_RESULT_FAILURE { 4511 ON_RESULT_FAILURE {
4504 if (cur_mapped_addr != dst_addr) { 4512 if (cur_mapped_addr != dst_addr) {
@@ -5166,10 +5174,10 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
5166 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); 5174 GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value));
5167 5175
5168 // If we fail in the next bit (or retry), we need to cleanup the pages. 5176 // If we fail in the next bit (or retry), we need to cleanup the pages.
5169 auto pg_guard = SCOPE_GUARD({ 5177 auto pg_guard = SCOPE_GUARD {
5170 pg.OpenFirst(); 5178 pg.OpenFirst();
5171 pg.Close(); 5179 pg.Close();
5172 }); 5180 };
5173 5181
5174 // Map the memory. 5182 // Map the memory.
5175 { 5183 {
@@ -5694,7 +5702,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
5694 5702
5695 // Ensure that any pages we track are closed on exit. 5703 // Ensure that any pages we track are closed on exit.
5696 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); 5704 KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager());
5697 SCOPE_EXIT({ pages_to_close.CloseAndReset(); }); 5705 SCOPE_EXIT {
5706 pages_to_close.CloseAndReset();
5707 };
5698 5708
5699 // Make a page group representing the region to unmap. 5709 // Make a page group representing the region to unmap.
5700 this->MakePageGroup(pages_to_close, virt_addr, num_pages); 5710 this->MakePageGroup(pages_to_close, virt_addr, num_pages);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 1bcc42890..cb9a11a63 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -77,7 +77,9 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process,
77 } 77 }
78 78
79 // Terminate and close the thread. 79 // Terminate and close the thread.
80 SCOPE_EXIT({ cur_child->Close(); }); 80 SCOPE_EXIT {
81 cur_child->Close();
82 };
81 83
82 if (const Result terminate_result = cur_child->Terminate(); 84 if (const Result terminate_result = cur_child->Terminate();
83 ResultTerminationRequested == terminate_result) { 85 ResultTerminationRequested == terminate_result) {
@@ -466,11 +468,11 @@ void KProcess::DoWorkerTaskImpl() {
466 468
467Result KProcess::StartTermination() { 469Result KProcess::StartTermination() {
468 // Finalize the handle table when we're done, if the process isn't immortal. 470 // Finalize the handle table when we're done, if the process isn't immortal.
469 SCOPE_EXIT({ 471 SCOPE_EXIT {
470 if (!m_is_immortal) { 472 if (!m_is_immortal) {
471 this->FinalizeHandleTable(); 473 this->FinalizeHandleTable();
472 } 474 }
473 }); 475 };
474 476
475 // Terminate child threads other than the current one. 477 // Terminate child threads other than the current one.
476 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel))); 478 R_RETURN(TerminateChildren(m_kernel, this, GetCurrentThreadPointer(m_kernel)));
@@ -964,7 +966,9 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
964 // Create a new thread for the process. 966 // Create a new thread for the process.
965 KThread* main_thread = KThread::Create(m_kernel); 967 KThread* main_thread = KThread::Create(m_kernel);
966 R_UNLESS(main_thread != nullptr, ResultOutOfResource); 968 R_UNLESS(main_thread != nullptr, ResultOutOfResource);
967 SCOPE_EXIT({ main_thread->Close(); }); 969 SCOPE_EXIT {
970 main_thread->Close();
971 };
968 972
969 // Initialize the thread. 973 // Initialize the thread.
970 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0, 974 R_TRY(KThread::InitializeUserThread(m_kernel.System(), main_thread, this->GetEntryPoint(), 0,
@@ -1155,7 +1159,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
1155 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); 1159 Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
1156 1160
1157 // Ensure we maintain a clean state on exit. 1161 // Ensure we maintain a clean state on exit.
1158 SCOPE_EXIT({ res_limit->Close(); }); 1162 SCOPE_EXIT {
1163 res_limit->Close();
1164 };
1159 1165
1160 // Declare flags and code address. 1166 // Declare flags and code address.
1161 Svc::CreateProcessFlag flag{}; 1167 Svc::CreateProcessFlag flag{};
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index adaabdd6d..40c3323ef 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -651,11 +651,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
651 // Process any special data. 651 // Process any special data.
652 if (src_header.GetHasSpecialHeader()) { 652 if (src_header.GetHasSpecialHeader()) {
653 // After we process, make sure we track whether the receive list is broken. 653 // After we process, make sure we track whether the receive list is broken.
654 SCOPE_EXIT({ 654 SCOPE_EXIT {
655 if (offset > dst_recv_list_idx) { 655 if (offset > dst_recv_list_idx) {
656 recv_list_broken = true; 656 recv_list_broken = true;
657 } 657 }
658 }); 658 };
659 659
660 // Process special data. 660 // Process special data.
661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread, 661 R_TRY(ProcessMessageSpecialData<false>(offset, dst_process, src_process, src_thread,
@@ -665,11 +665,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
665 // Process any pointer buffers. 665 // Process any pointer buffers.
666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) { 666 for (auto i = 0; i < src_header.GetPointerCount(); ++i) {
667 // After we process, make sure we track whether the receive list is broken. 667 // After we process, make sure we track whether the receive list is broken.
668 SCOPE_EXIT({ 668 SCOPE_EXIT {
669 if (offset > dst_recv_list_idx) { 669 if (offset > dst_recv_list_idx) {
670 recv_list_broken = true; 670 recv_list_broken = true;
671 } 671 }
672 }); 672 };
673 673
674 R_TRY(ProcessReceiveMessagePointerDescriptors( 674 R_TRY(ProcessReceiveMessagePointerDescriptors(
675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, 675 offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list,
@@ -680,11 +680,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
680 // Process any map alias buffers. 680 // Process any map alias buffers.
681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) { 681 for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
682 // After we process, make sure we track whether the receive list is broken. 682 // After we process, make sure we track whether the receive list is broken.
683 SCOPE_EXIT({ 683 SCOPE_EXIT {
684 if (offset > dst_recv_list_idx) { 684 if (offset > dst_recv_list_idx) {
685 recv_list_broken = true; 685 recv_list_broken = true;
686 } 686 }
687 }); 687 };
688 688
689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. 689 // We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite.
690 const KMemoryPermission perm = (i >= src_header.GetSendCount()) 690 const KMemoryPermission perm = (i >= src_header.GetSendCount())
@@ -702,11 +702,11 @@ Result ReceiveMessage(KernelCore& kernel, bool& recv_list_broken, uint64_t dst_m
702 // Process any raw data. 702 // Process any raw data.
703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) { 703 if (const auto raw_count = src_header.GetRawCount(); raw_count != 0) {
704 // After we process, make sure we track whether the receive list is broken. 704 // After we process, make sure we track whether the receive list is broken.
705 SCOPE_EXIT({ 705 SCOPE_EXIT {
706 if (offset + raw_count > dst_recv_list_idx) { 706 if (offset + raw_count > dst_recv_list_idx) {
707 recv_list_broken = true; 707 recv_list_broken = true;
708 } 708 }
709 }); 709 };
710 710
711 // Get the offset and size. 711 // Get the offset and size.
712 const size_t offset_words = offset * sizeof(u32); 712 const size_t offset_words = offset * sizeof(u32);
@@ -1124,7 +1124,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1124 client_thread->Open(); 1124 client_thread->Open();
1125 } 1125 }
1126 1126
1127 SCOPE_EXIT({ client_thread->Close(); }); 1127 SCOPE_EXIT {
1128 client_thread->Close();
1129 };
1128 1130
1129 // Set the request as our current. 1131 // Set the request as our current.
1130 m_current_request = request; 1132 m_current_request = request;
@@ -1174,7 +1176,9 @@ Result KServerSession::ReceiveRequest(uintptr_t server_message, uintptr_t server
1174 // Reply to the client. 1176 // Reply to the client.
1175 { 1177 {
1176 // After we reply, close our reference to the request. 1178 // After we reply, close our reference to the request.
1177 SCOPE_EXIT({ request->Close(); }); 1179 SCOPE_EXIT {
1180 request->Close();
1181 };
1178 1182
1179 // Get the event to check whether the request is async. 1183 // Get the event to check whether the request is async.
1180 if (KEvent* event = request->GetEvent(); event != nullptr) { 1184 if (KEvent* event = request->GetEvent(); event != nullptr) {
@@ -1236,7 +1240,9 @@ Result KServerSession::SendReply(uintptr_t server_message, uintptr_t server_buff
1236 } 1240 }
1237 1241
1238 // Close reference to the request once we're done processing it. 1242 // Close reference to the request once we're done processing it.
1239 SCOPE_EXIT({ request->Close(); }); 1243 SCOPE_EXIT {
1244 request->Close();
1245 };
1240 1246
1241 // Extract relevant information from the request. 1247 // Extract relevant information from the request.
1242 const uint64_t client_message = request->GetAddress(); 1248 const uint64_t client_message = request->GetAddress();
@@ -1394,7 +1400,9 @@ void KServerSession::CleanupRequests() {
1394 } 1400 }
1395 1401
1396 // Close a reference to the request once it's cleaned up. 1402 // Close a reference to the request once it's cleaned up.
1397 SCOPE_EXIT({ request->Close(); }); 1403 SCOPE_EXIT {
1404 request->Close();
1405 };
1398 1406
1399 // Extract relevant information from the request. 1407 // Extract relevant information from the request.
1400 const uint64_t client_message = request->GetAddress(); 1408 const uint64_t client_message = request->GetAddress();
@@ -1491,7 +1499,9 @@ void KServerSession::OnClientClosed() {
1491 ASSERT(thread != nullptr); 1499 ASSERT(thread != nullptr);
1492 1500
1493 // Ensure that we close the request when done. 1501 // Ensure that we close the request when done.
1494 SCOPE_EXIT({ request->Close(); }); 1502 SCOPE_EXIT {
1503 request->Close();
1504 };
1495 1505
1496 // If we're terminating, close a reference to the thread and event. 1506 // If we're terminating, close a reference to the thread and event.
1497 if (terminate) { 1507 if (terminate) {
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
index a632d1634..1952c0083 100644
--- a/src/core/hle/kernel/k_thread_local_page.cpp
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -21,7 +21,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
21 // Allocate a new page. 21 // Allocate a new page.
22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel); 22 KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory); 23 R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
24 auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); }); 24 auto page_buf_guard = SCOPE_GUARD {
25 KPageBuffer::Free(kernel, page_buf);
26 };
25 27
26 // Map the address in. 28 // Map the address in.
27 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); 29 const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index cbb1b02bb..09295e8ad 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -24,7 +24,9 @@ Result KTransferMemory::Initialize(KProcessAddress addr, std::size_t size,
24 24
25 // Construct the page group, guarding to make sure our state is valid on exit. 25 // Construct the page group, guarding to make sure our state is valid on exit.
26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); 26 m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
27 auto pg_guard = SCOPE_GUARD({ m_page_group.reset(); }); 27 auto pg_guard = SCOPE_GUARD {
28 m_page_group.reset();
29 };
28 30
29 // Lock the memory. 31 // Lock the memory.
30 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size, 32 R_TRY(page_table.LockForTransferMemory(std::addressof(*m_page_group), addr, size,
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f4b02fac..9e5eaeec4 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -109,7 +109,9 @@ struct KernelCore::Impl {
109 109
110 void Shutdown() { 110 void Shutdown() {
111 is_shutting_down.store(true, std::memory_order_relaxed); 111 is_shutting_down.store(true, std::memory_order_relaxed);
112 SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); 112 SCOPE_EXIT {
113 is_shutting_down.store(false, std::memory_order_relaxed);
114 };
113 115
114 CloseServices(); 116 CloseServices();
115 117
@@ -1080,7 +1082,9 @@ std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
1080 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1082 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1081 1083
1082 // Ensure that we don't hold onto any extra references. 1084 // Ensure that we don't hold onto any extra references.
1083 SCOPE_EXIT({ process->Close(); }); 1085 SCOPE_EXIT {
1086 process->Close();
1087 };
1084 1088
1085 // Register the new process. 1089 // Register the new process.
1086 KProcess::Register(*this, process); 1090 KProcess::Register(*this, process);
@@ -1108,7 +1112,9 @@ void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function
1108 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false))); 1112 process->Initialize(Svc::CreateProcessParameter{}, GetSystemResourceLimit(), false)));
1109 1113
1110 // Ensure that we don't hold onto any extra references. 1114 // Ensure that we don't hold onto any extra references.
1111 SCOPE_EXIT({ process->Close(); }); 1115 SCOPE_EXIT {
1116 process->Close();
1117 };
1112 1118
1113 // Register the new process. 1119 // Register the new process.
1114 KProcess::Register(*this, process); 1120 KProcess::Register(*this, process);
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp
index bae4cb0cd..7be2802f0 100644
--- a/src/core/hle/kernel/svc/svc_code_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_code_memory.cpp
@@ -45,7 +45,9 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t
45 45
46 KCodeMemory* code_mem = KCodeMemory::Create(kernel); 46 KCodeMemory* code_mem = KCodeMemory::Create(kernel);
47 R_UNLESS(code_mem != nullptr, ResultOutOfResource); 47 R_UNLESS(code_mem != nullptr, ResultOutOfResource);
48 SCOPE_EXIT({ code_mem->Close(); }); 48 SCOPE_EXIT {
49 code_mem->Close();
50 };
49 51
50 // Verify that the region is in range. 52 // Verify that the region is in range.
51 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), 53 R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size),
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp
index 42add9473..ac828320f 100644
--- a/src/core/hle/kernel/svc/svc_device_address_space.cpp
+++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp
@@ -28,7 +28,9 @@ Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_
28 // Create the device address space. 28 // Create the device address space.
29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel()); 29 KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
30 R_UNLESS(das != nullptr, ResultOutOfResource); 30 R_UNLESS(das != nullptr, ResultOutOfResource);
31 SCOPE_EXIT({ das->Close(); }); 31 SCOPE_EXIT {
32 das->Close();
33 };
32 34
33 // Initialize the device address space. 35 // Initialize the device address space.
34 R_TRY(das->Initialize(das_address, das_size)); 36 R_TRY(das->Initialize(das_address, das_size));
diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp
index 901202e6a..8e4beb396 100644
--- a/src/core/hle/kernel/svc/svc_event.cpp
+++ b/src/core/hle/kernel/svc/svc_event.cpp
@@ -72,10 +72,10 @@ Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
72 event_reservation.Commit(); 72 event_reservation.Commit();
73 73
74 // Ensure that we clean up the event (and its only references are handle table) on function end. 74 // Ensure that we clean up the event (and its only references are handle table) on function end.
75 SCOPE_EXIT({ 75 SCOPE_EXIT {
76 event->GetReadableEvent().Close(); 76 event->GetReadableEvent().Close();
77 event->Close(); 77 event->Close();
78 }); 78 };
79 79
80 // Register the event. 80 // Register the event.
81 KEvent::Register(kernel, event); 81 KEvent::Register(kernel, event);
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index 85cc4f561..b619bd70a 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -129,11 +129,11 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
129 } 129 }
130 130
131 // Ensure handles are closed when we're done. 131 // Ensure handles are closed when we're done.
132 SCOPE_EXIT({ 132 SCOPE_EXIT {
133 for (auto i = 0; i < num_handles; ++i) { 133 for (auto i = 0; i < num_handles; ++i) {
134 objs[i]->Close(); 134 objs[i]->Close();
135 } 135 }
136 }); 136 };
137 137
138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, 138 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
139 num_handles, reply_target, timeout_ns)); 139 num_handles, reply_target, timeout_ns));
@@ -208,10 +208,10 @@ Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_ha
208 event_reservation.Commit(); 208 event_reservation.Commit();
209 209
210 // At end of scope, kill the standing references to the sub events. 210 // At end of scope, kill the standing references to the sub events.
211 SCOPE_EXIT({ 211 SCOPE_EXIT {
212 event->GetReadableEvent().Close(); 212 event->GetReadableEvent().Close();
213 event->Close(); 213 event->Close();
214 }); 214 };
215 215
216 // Register the event. 216 // Register the event.
217 KEvent::Register(system.Kernel(), event); 217 KEvent::Register(system.Kernel(), event);
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 737749f7d..9a22dadaf 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -68,10 +68,10 @@ Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
68 port->Initialize(max_sessions, is_light, name); 68 port->Initialize(max_sessions, is_light, name);
69 69
70 // Ensure that we clean up the port (and its only references are handle table) on function end. 70 // Ensure that we clean up the port (and its only references are handle table) on function end.
71 SCOPE_EXIT({ 71 SCOPE_EXIT {
72 port->GetServerPort().Close(); 72 port->GetServerPort().Close();
73 port->GetClientPort().Close(); 73 port->GetClientPort().Close();
74 }); 74 };
75 75
76 // Register the port. 76 // Register the port.
77 KPort::Register(kernel, port); 77 KPort::Register(kernel, port);
@@ -150,10 +150,10 @@ Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t
150 KPort::Register(system.Kernel(), port); 150 KPort::Register(system.Kernel(), port);
151 151
152 // Ensure that our only reference to the port is in the handle table when we're done. 152 // Ensure that our only reference to the port is in the handle table when we're done.
153 SCOPE_EXIT({ 153 SCOPE_EXIT {
154 port->GetClientPort().Close(); 154 port->GetClientPort().Close();
155 port->GetServerPort().Close(); 155 port->GetServerPort().Close();
156 }); 156 };
157 157
158 // Register the handle in the table. 158 // Register the handle in the table.
159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort()))); 159 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp
index c8e820b6a..6f3972482 100644
--- a/src/core/hle/kernel/svc/svc_resource_limit.cpp
+++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp
@@ -18,7 +18,9 @@ Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource); 18 R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
19 19
20 // Ensure we don't leak a reference to the limit. 20 // Ensure we don't leak a reference to the limit.
21 SCOPE_EXIT({ resource_limit->Close(); }); 21 SCOPE_EXIT {
22 resource_limit->Close();
23 };
22 24
23 // Initialize the resource limit. 25 // Initialize the resource limit.
24 resource_limit->Initialize(); 26 resource_limit->Initialize();
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp
index 2f5905f32..b034d21d1 100644
--- a/src/core/hle/kernel/svc/svc_session.cpp
+++ b/src/core/hle/kernel/svc/svc_session.cpp
@@ -69,10 +69,10 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
69 69
70 // Ensure that we clean up the session (and its only references are handle table) on function 70 // Ensure that we clean up the session (and its only references are handle table) on function
71 // end. 71 // end.
72 SCOPE_EXIT({ 72 SCOPE_EXIT {
73 session->GetClientSession().Close(); 73 session->GetClientSession().Close();
74 session->GetServerSession().Close(); 74 session->GetServerSession().Close();
75 }); 75 };
76 76
77 // Register the session. 77 // Register the session.
78 T::Register(system.Kernel(), session); 78 T::Register(system.Kernel(), session);
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
index 6c79cfd8d..fb03908d7 100644
--- a/src/core/hle/kernel/svc/svc_synchronization.cpp
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -78,11 +78,11 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
78 } 78 }
79 79
80 // Ensure handles are closed when we're done. 80 // Ensure handles are closed when we're done.
81 SCOPE_EXIT({ 81 SCOPE_EXIT {
82 for (auto i = 0; i < num_handles; ++i) { 82 for (auto i = 0; i < num_handles; ++i) {
83 objs[i]->Close(); 83 objs[i]->Close();
84 } 84 }
85 }); 85 };
86 86
87 // Convert the timeout from nanoseconds to ticks. 87 // Convert the timeout from nanoseconds to ticks.
88 s64 timeout; 88 s64 timeout;
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index 7681afa33..7517bb9d3 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -51,7 +51,9 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
51 // Create the thread. 51 // Create the thread.
52 KThread* thread = KThread::Create(kernel); 52 KThread* thread = KThread::Create(kernel);
53 R_UNLESS(thread != nullptr, ResultOutOfResource) 53 R_UNLESS(thread != nullptr, ResultOutOfResource)
54 SCOPE_EXIT({ thread->Close(); }); 54 SCOPE_EXIT {
55 thread->Close();
56 };
55 57
56 // Initialize the thread. 58 // Initialize the thread.
57 { 59 {
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 671bca23f..2ea0d4421 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -52,7 +52,9 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64
52 R_UNLESS(trmem != nullptr, ResultOutOfResource); 52 R_UNLESS(trmem != nullptr, ResultOutOfResource);
53 53
54 // Ensure the only reference is in the handle table when we're done. 54 // Ensure the only reference is in the handle table when we're done.
55 SCOPE_EXIT({ trmem->Close(); }); 55 SCOPE_EXIT {
56 trmem->Close();
57 };
56 58
57 // Ensure that the region is in range. 59 // Ensure that the region is in range.
58 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); 60 R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory);
diff --git a/src/core/hle/service/am/applet_data_broker.cpp b/src/core/hle/service/am/applet_data_broker.cpp
index 4d58c4db5..9057244a9 100644
--- a/src/core/hle/service/am/applet_data_broker.cpp
+++ b/src/core/hle/service/am/applet_data_broker.cpp
@@ -24,11 +24,11 @@ void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) { 24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
25 std::scoped_lock lk{m_lock}; 25 std::scoped_lock lk{m_lock};
26 26
27 SCOPE_EXIT({ 27 SCOPE_EXIT {
28 if (m_data.empty()) { 28 if (m_data.empty()) {
29 m_event.Clear(); 29 m_event.Clear();
30 } 30 }
31 }); 31 };
32 32
33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); 33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
34 34
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
index 992c50713..388d2045c 100644
--- a/src/core/hle/service/am/process.cpp
+++ b/src/core/hle/service/am/process.cpp
@@ -68,7 +68,9 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
68 Kernel::KProcess::Register(m_system.Kernel(), process); 68 Kernel::KProcess::Register(m_system.Kernel(), process);
69 69
70 // On exit, ensure we free the additional reference to the process. 70 // On exit, ensure we free the additional reference to the process.
71 SCOPE_EXIT({ process->Close(); }); 71 SCOPE_EXIT {
72 process->Close();
73 };
72 74
73 // Insert process modules into memory. 75 // Insert process modules into memory.
74 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); 76 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index cb53b07e0..bfccb6b09 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -123,13 +123,13 @@ Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID use
123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString()); 123 LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
124 124
125 FileSys::SaveDataAttribute attribute{}; 125 FileSys::SaveDataAttribute attribute{};
126 attribute.title_id = m_applet->program_id; 126 attribute.program_id = m_applet->program_id;
127 attribute.user_id = user_id.AsU128(); 127 attribute.user_id = user_id.AsU128();
128 attribute.type = FileSys::SaveDataType::SaveData; 128 attribute.type = FileSys::SaveDataType::Account;
129 129
130 FileSys::VirtualDir save_data{}; 130 FileSys::VirtualDir save_data{};
131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( 131 R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
132 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute)); 132 &save_data, FileSys::SaveDataSpaceId::User, attribute));
133 133
134 *out_size = 0; 134 *out_size = 0;
135 R_SUCCEED(); 135 R_SUCCEED();
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
deleted file mode 100644
index de2aa6906..000000000
--- a/src/core/hle/service/audio/audin_u.cpp
+++ /dev/null
@@ -1,393 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/in/audio_in_system.h"
5#include "audio_core/renderer/audio_device.h"
6#include "common/common_funcs.h"
7#include "common/logging/log.h"
8#include "common/scratch_buffer.h"
9#include "common/string_util.h"
10#include "core/core.h"
11#include "core/hle/kernel/k_event.h"
12#include "core/hle/service/audio/audin_u.h"
13#include "core/hle/service/ipc_helpers.h"
14
15namespace Service::Audio {
16using namespace AudioCore::AudioIn;
17
18class IAudioIn final : public ServiceFramework<IAudioIn> {
19public:
20 explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
21 const std::string& device_name, const AudioInParameter& in_params,
22 Kernel::KProcess* handle, u64 applet_resource_user_id)
23 : ServiceFramework{system_, "IAudioIn"},
24 service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")},
25 process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &IAudioIn::GetAudioInState, "GetAudioInState"},
29 {1, &IAudioIn::Start, "Start"},
30 {2, &IAudioIn::Stop, "Stop"},
31 {3, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBuffer"},
32 {4, &IAudioIn::RegisterBufferEvent, "RegisterBufferEvent"},
33 {5, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffer"},
34 {6, &IAudioIn::ContainsAudioInBuffer, "ContainsAudioInBuffer"},
35 {7, &IAudioIn::AppendAudioInBuffer, "AppendUacInBuffer"},
36 {8, &IAudioIn::AppendAudioInBuffer, "AppendAudioInBufferAuto"},
37 {9, &IAudioIn::GetReleasedAudioInBuffer, "GetReleasedAudioInBuffersAuto"},
38 {10, &IAudioIn::AppendAudioInBuffer, "AppendUacInBufferAuto"},
39 {11, &IAudioIn::GetAudioInBufferCount, "GetAudioInBufferCount"},
40 {12, &IAudioIn::SetDeviceGain, "SetDeviceGain"},
41 {13, &IAudioIn::GetDeviceGain, "GetDeviceGain"},
42 {14, &IAudioIn::FlushAudioInBuffers, "FlushAudioInBuffers"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47
48 process->Open();
49
50 if (impl->GetSystem()
51 .Initialize(device_name, in_params, handle, applet_resource_user_id)
52 .IsError()) {
53 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
54 }
55 }
56
57 ~IAudioIn() override {
58 impl->Free();
59 service_context.CloseEvent(event);
60 process->Close();
61 }
62
63 [[nodiscard]] std::shared_ptr<In> GetImpl() {
64 return impl;
65 }
66
67private:
68 void GetAudioInState(HLERequestContext& ctx) {
69 const auto state = static_cast<u32>(impl->GetState());
70
71 LOG_DEBUG(Service_Audio, "called. State={}", state);
72
73 IPC::ResponseBuilder rb{ctx, 3};
74 rb.Push(ResultSuccess);
75 rb.Push(state);
76 }
77
78 void Start(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_Audio, "called");
80
81 auto result = impl->StartSystem();
82
83 IPC::ResponseBuilder rb{ctx, 2};
84 rb.Push(result);
85 }
86
87 void Stop(HLERequestContext& ctx) {
88 LOG_DEBUG(Service_Audio, "called");
89
90 auto result = impl->StopSystem();
91
92 IPC::ResponseBuilder rb{ctx, 2};
93 rb.Push(result);
94 }
95
96 void AppendAudioInBuffer(HLERequestContext& ctx) {
97 IPC::RequestParser rp{ctx};
98 u64 tag = rp.PopRaw<u64>();
99
100 const auto in_buffer_size{ctx.GetReadBufferSize()};
101 if (in_buffer_size < sizeof(AudioInBuffer)) {
102 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
103 }
104
105 const auto& in_buffer = ctx.ReadBuffer();
106 AudioInBuffer buffer{};
107 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioInBuffer));
108
109 [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", sessionid, tag);
111
112 auto result = impl->AppendBuffer(buffer, tag);
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(result);
116 }
117
118 void RegisterBufferEvent(HLERequestContext& ctx) {
119 LOG_DEBUG(Service_Audio, "called");
120
121 auto& buffer_event = impl->GetBufferEvent();
122
123 IPC::ResponseBuilder rb{ctx, 2, 1};
124 rb.Push(ResultSuccess);
125 rb.PushCopyObjects(buffer_event);
126 }
127
128 void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
129 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
130 released_buffer.resize_destructive(write_buffer_size);
131 released_buffer[0] = 0;
132
133 const auto count = impl->GetReleasedBuffers(released_buffer);
134
135 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
136 impl->GetSystem().GetSessionId(), count);
137
138 ctx.WriteBuffer(released_buffer);
139
140 IPC::ResponseBuilder rb{ctx, 3};
141 rb.Push(ResultSuccess);
142 rb.Push(count);
143 }
144
145 void ContainsAudioInBuffer(HLERequestContext& ctx) {
146 IPC::RequestParser rp{ctx};
147
148 const u64 tag{rp.Pop<u64>()};
149 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
150
151 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
152
153 IPC::ResponseBuilder rb{ctx, 3};
154 rb.Push(ResultSuccess);
155 rb.Push(buffer_queued);
156 }
157
158 void GetAudioInBufferCount(HLERequestContext& ctx) {
159 const auto buffer_count = impl->GetBufferCount();
160
161 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
162
163 IPC::ResponseBuilder rb{ctx, 3};
164 rb.Push(ResultSuccess);
165 rb.Push(buffer_count);
166 }
167
168 void SetDeviceGain(HLERequestContext& ctx) {
169 IPC::RequestParser rp{ctx};
170
171 const auto volume{rp.Pop<f32>()};
172 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
173
174 impl->SetVolume(volume);
175
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(ResultSuccess);
178 }
179
180 void GetDeviceGain(HLERequestContext& ctx) {
181 auto volume{impl->GetVolume()};
182
183 LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
184
185 IPC::ResponseBuilder rb{ctx, 3};
186 rb.Push(ResultSuccess);
187 rb.Push(volume);
188 }
189
190 void FlushAudioInBuffers(HLERequestContext& ctx) {
191 bool flushed{impl->FlushAudioInBuffers()};
192
193 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
194
195 IPC::ResponseBuilder rb{ctx, 3};
196 rb.Push(ResultSuccess);
197 rb.Push(flushed);
198 }
199
200 KernelHelpers::ServiceContext service_context;
201 Kernel::KEvent* event;
202 Kernel::KProcess* process;
203 std::shared_ptr<AudioCore::AudioIn::In> impl;
204 Common::ScratchBuffer<u64> released_buffer;
205};
206
207AudInU::AudInU(Core::System& system_)
208 : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
209 impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
210 // clang-format off
211 static const FunctionInfo functions[] = {
212 {0, &AudInU::ListAudioIns, "ListAudioIns"},
213 {1, &AudInU::OpenAudioIn, "OpenAudioIn"},
214 {2, &AudInU::ListAudioIns, "ListAudioInsAuto"},
215 {3, &AudInU::OpenAudioIn, "OpenAudioInAuto"},
216 {4, &AudInU::ListAudioInsAutoFiltered, "ListAudioInsAutoFiltered"},
217 {5, &AudInU::OpenAudioInProtocolSpecified, "OpenAudioInProtocolSpecified"},
218 };
219 // clang-format on
220
221 RegisterHandlers(functions);
222}
223
224AudInU::~AudInU() = default;
225
226void AudInU::ListAudioIns(HLERequestContext& ctx) {
227 using namespace AudioCore::Renderer;
228
229 LOG_DEBUG(Service_Audio, "called");
230
231 const auto write_count =
232 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
233 std::vector<AudioDevice::AudioDeviceName> device_names{};
234
235 u32 out_count{0};
236 if (write_count > 0) {
237 out_count = impl->GetDeviceNames(device_names, write_count, false);
238 ctx.WriteBuffer(device_names);
239 }
240
241 IPC::ResponseBuilder rb{ctx, 3};
242 rb.Push(ResultSuccess);
243 rb.Push(out_count);
244}
245
246void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
247 using namespace AudioCore::Renderer;
248
249 LOG_DEBUG(Service_Audio, "called");
250
251 const auto write_count =
252 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
253 std::vector<AudioDevice::AudioDeviceName> device_names{};
254
255 u32 out_count{0};
256 if (write_count > 0) {
257 out_count = impl->GetDeviceNames(device_names, write_count, true);
258 ctx.WriteBuffer(device_names);
259 }
260
261 IPC::ResponseBuilder rb{ctx, 3};
262 rb.Push(ResultSuccess);
263 rb.Push(out_count);
264}
265
266void AudInU::OpenAudioIn(HLERequestContext& ctx) {
267 IPC::RequestParser rp{ctx};
268 auto in_params{rp.PopRaw<AudioInParameter>()};
269 auto applet_resource_user_id{rp.PopRaw<u64>()};
270 const auto device_name_data{ctx.ReadBuffer()};
271 auto device_name = Common::StringFromBuffer(device_name_data);
272 auto handle{ctx.GetCopyHandle(0)};
273
274 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
275 if (process.IsNull()) {
276 LOG_ERROR(Service_Audio, "Failed to get process handle");
277 IPC::ResponseBuilder rb{ctx, 2};
278 rb.Push(ResultUnknown);
279 return;
280 }
281
282 std::scoped_lock l{impl->mutex};
283 auto link{impl->LinkToManager()};
284 if (link.IsError()) {
285 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
286 IPC::ResponseBuilder rb{ctx, 2};
287 rb.Push(link);
288 return;
289 }
290
291 size_t new_session_id{};
292 auto result{impl->AcquireSessionId(new_session_id)};
293 if (result.IsError()) {
294 IPC::ResponseBuilder rb{ctx, 2};
295 rb.Push(result);
296 return;
297 }
298
299 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
300 impl->num_free_sessions);
301
302 auto audio_in =
303 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
304 process.GetPointerUnsafe(), applet_resource_user_id);
305 impl->sessions[new_session_id] = audio_in->GetImpl();
306 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
307
308 auto& out_system = impl->sessions[new_session_id]->GetSystem();
309 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
310 .channel_count = out_system.GetChannelCount(),
311 .sample_format =
312 static_cast<u32>(out_system.GetSampleFormat()),
313 .state = static_cast<u32>(out_system.GetState())};
314
315 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
316
317 std::string out_name{out_system.GetName()};
318 ctx.WriteBuffer(out_name);
319
320 rb.Push(ResultSuccess);
321 rb.PushRaw<AudioInParameterInternal>(out_params);
322 rb.PushIpcInterface<IAudioIn>(audio_in);
323}
324
325void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
326 IPC::RequestParser rp{ctx};
327 auto protocol_specified{rp.PopRaw<u64>()};
328 auto in_params{rp.PopRaw<AudioInParameter>()};
329 auto applet_resource_user_id{rp.PopRaw<u64>()};
330 const auto device_name_data{ctx.ReadBuffer()};
331 auto device_name = Common::StringFromBuffer(device_name_data);
332 auto handle{ctx.GetCopyHandle(0)};
333
334 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
335 if (process.IsNull()) {
336 LOG_ERROR(Service_Audio, "Failed to get process handle");
337 IPC::ResponseBuilder rb{ctx, 2};
338 rb.Push(ResultUnknown);
339 return;
340 }
341
342 std::scoped_lock l{impl->mutex};
343 auto link{impl->LinkToManager()};
344 if (link.IsError()) {
345 LOG_ERROR(Service_Audio, "Failed to link Audio In to Audio Manager");
346 IPC::ResponseBuilder rb{ctx, 2};
347 rb.Push(link);
348 return;
349 }
350
351 size_t new_session_id{};
352 auto result{impl->AcquireSessionId(new_session_id)};
353 if (result.IsError()) {
354 IPC::ResponseBuilder rb{ctx, 2};
355 rb.Push(result);
356 return;
357 }
358
359 LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id,
360 impl->num_free_sessions);
361
362 auto audio_in =
363 std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params,
364 process.GetPointerUnsafe(), applet_resource_user_id);
365 impl->sessions[new_session_id] = audio_in->GetImpl();
366 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
367
368 auto& out_system = impl->sessions[new_session_id]->GetSystem();
369 AudioInParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
370 .channel_count = out_system.GetChannelCount(),
371 .sample_format =
372 static_cast<u32>(out_system.GetSampleFormat()),
373 .state = static_cast<u32>(out_system.GetState())};
374
375 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
376
377 std::string out_name{out_system.GetName()};
378 if (protocol_specified == 0) {
379 if (out_system.IsUac()) {
380 out_name = "UacIn";
381 } else {
382 out_name = "DeviceIn";
383 }
384 }
385
386 ctx.WriteBuffer(out_name);
387
388 rb.Push(ResultSuccess);
389 rb.PushRaw<AudioInParameterInternal>(out_params);
390 rb.PushIpcInterface<IAudioIn>(audio_in);
391}
392
393} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
deleted file mode 100644
index 51e770ff9..000000000
--- a/src/core/hle/service/audio/audin_u.h
+++ /dev/null
@@ -1,38 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class In;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class AudInU final : public ServiceFramework<AudInU> {
23public:
24 explicit AudInU(Core::System& system_);
25 ~AudInU() override;
26
27private:
28 void ListAudioIns(HLERequestContext& ctx);
29 void ListAudioInsAutoFiltered(HLERequestContext& ctx);
30 void OpenInOutImpl(HLERequestContext& ctx);
31 void OpenAudioIn(HLERequestContext& ctx);
32 void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
33
34 KernelHelpers::ServiceContext service_context;
35 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
36};
37
38} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 44af030eb..331176bf7 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -2,14 +2,14 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/service/audio/audin_u.h"
6#include "core/hle/service/audio/audio.h" 5#include "core/hle/service/audio/audio.h"
7#include "core/hle/service/audio/audio_controller.h" 6#include "core/hle/service/audio/audio_controller.h"
8#include "core/hle/service/audio/audout_u.h" 7#include "core/hle/service/audio/audio_in_manager.h"
9#include "core/hle/service/audio/audrec_a.h" 8#include "core/hle/service/audio/audio_out_manager.h"
10#include "core/hle/service/audio/audrec_u.h" 9#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/audio/audren_u.h" 10#include "core/hle/service/audio/final_output_recorder_manager.h"
12#include "core/hle/service/audio/hwopus.h" 11#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
12#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
13#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
14#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
15 15
@@ -19,12 +19,16 @@ void LoopProcess(Core::System& system) {
19 auto server_manager = std::make_unique<ServerManager>(system); 19 auto server_manager = std::make_unique<ServerManager>(system);
20 20
21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system)); 21 server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system));
22 server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system)); 22 server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system));
23 server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system)); 23 server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system));
24 server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system)); 24 server_manager->RegisterNamedService(
25 server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system)); 25 "audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system));
26 server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system)); 26 server_manager->RegisterNamedService("audrec:u",
27 server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system)); 27 std::make_shared<IFinalOutputRecorderManager>(system));
28 server_manager->RegisterNamedService("audren:u",
29 std::make_shared<IAudioRendererManager>(system));
30 server_manager->RegisterNamedService("hwopus",
31 std::make_shared<IHardwareOpusDecoderManager>(system));
28 ServerManager::RunServer(std::move(server_manager)); 32 ServerManager::RunServer(std::move(server_manager));
29} 33}
30 34
diff --git a/src/core/hle/service/audio/audio_controller.cpp b/src/core/hle/service/audio/audio_controller.cpp
index a6da66d0f..7a51d1023 100644
--- a/src/core/hle/service/audio/audio_controller.cpp
+++ b/src/core/hle/service/audio/audio_controller.cpp
@@ -16,27 +16,27 @@ IAudioController::IAudioController(Core::System& system_)
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetTargetVolume"}, 17 {0, nullptr, "GetTargetVolume"},
18 {1, nullptr, "SetTargetVolume"}, 18 {1, nullptr, "SetTargetVolume"},
19 {2, C<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"}, 19 {2, D<&IAudioController::GetTargetVolumeMin>, "GetTargetVolumeMin"},
20 {3, C<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"}, 20 {3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
21 {4, nullptr, "IsTargetMute"}, 21 {4, nullptr, "IsTargetMute"},
22 {5, nullptr, "SetTargetMute"}, 22 {5, nullptr, "SetTargetMute"},
23 {6, nullptr, "IsTargetConnected"}, 23 {6, nullptr, "IsTargetConnected"},
24 {7, nullptr, "SetDefaultTarget"}, 24 {7, nullptr, "SetDefaultTarget"},
25 {8, nullptr, "GetDefaultTarget"}, 25 {8, nullptr, "GetDefaultTarget"},
26 {9, C<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"}, 26 {9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
27 {10, C<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"}, 27 {10, D<&IAudioController::SetAudioOutputMode>, "SetAudioOutputMode"},
28 {11, nullptr, "SetForceMutePolicy"}, 28 {11, nullptr, "SetForceMutePolicy"},
29 {12, C<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"}, 29 {12, D<&IAudioController::GetForceMutePolicy>, "GetForceMutePolicy"},
30 {13, C<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"}, 30 {13, D<&IAudioController::GetOutputModeSetting>, "GetOutputModeSetting"},
31 {14, C<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"}, 31 {14, D<&IAudioController::SetOutputModeSetting>, "SetOutputModeSetting"},
32 {15, nullptr, "SetOutputTarget"}, 32 {15, nullptr, "SetOutputTarget"},
33 {16, nullptr, "SetInputTargetForceEnabled"}, 33 {16, nullptr, "SetInputTargetForceEnabled"},
34 {17, C<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"}, 34 {17, D<&IAudioController::SetHeadphoneOutputLevelMode>, "SetHeadphoneOutputLevelMode"},
35 {18, C<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"}, 35 {18, D<&IAudioController::GetHeadphoneOutputLevelMode>, "GetHeadphoneOutputLevelMode"},
36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, 36 {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"},
37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, 37 {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"},
38 {21, nullptr, "GetAudioOutputTargetForPlayReport"}, 38 {21, nullptr, "GetAudioOutputTargetForPlayReport"},
39 {22, nullptr, "NotifyHeadphoneVolumeWarningDisplayedEvent"}, 39 {22, D<&IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent>, "NotifyHeadphoneVolumeWarningDisplayedEvent"},
40 {23, nullptr, "SetSystemOutputMasterVolume"}, 40 {23, nullptr, "SetSystemOutputMasterVolume"},
41 {24, nullptr, "GetSystemOutputMasterVolume"}, 41 {24, nullptr, "GetSystemOutputMasterVolume"},
42 {25, nullptr, "GetAudioVolumeDataForPlayReport"}, 42 {25, nullptr, "GetAudioVolumeDataForPlayReport"},
@@ -44,11 +44,11 @@ IAudioController::IAudioController(Core::System& system_)
44 {27, nullptr, "SetVolumeMappingTableForDev"}, 44 {27, nullptr, "SetVolumeMappingTableForDev"},
45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, 45 {28, nullptr, "GetAudioOutputChannelCountForPlayReport"},
46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, 46 {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
47 {30, C<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"}, 47 {30, D<&IAudioController::SetSpeakerAutoMuteEnabled>, "SetSpeakerAutoMuteEnabled"},
48 {31, C<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"}, 48 {31, D<&IAudioController::IsSpeakerAutoMuteEnabled>, "IsSpeakerAutoMuteEnabled"},
49 {32, nullptr, "GetActiveOutputTarget"}, 49 {32, nullptr, "GetActiveOutputTarget"},
50 {33, nullptr, "GetTargetDeviceInfo"}, 50 {33, nullptr, "GetTargetDeviceInfo"},
51 {34, C<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"}, 51 {34, D<&IAudioController::AcquireTargetNotification>, "AcquireTargetNotification"},
52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 52 {35, nullptr, "SetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"}, 53 {36, nullptr, "GetHearingProtectionSafeguardTimerRemainingTimeForDebug"},
54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"}, 54 {37, nullptr, "SetHearingProtectionSafeguardEnabled"},
@@ -138,7 +138,7 @@ Result IAudioController::SetOutputModeSetting(Set::AudioOutputModeTarget target,
138} 138}
139 139
140Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) { 140Result IAudioController::SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode) {
141 LOG_WARNING(Audio, "(STUBBED) called"); 141 LOG_WARNING(Audio, "(STUBBED) called, output_level_mode={}", output_level_mode);
142 R_SUCCEED(); 142 R_SUCCEED();
143} 143}
144 144
@@ -150,6 +150,11 @@ Result IAudioController::GetHeadphoneOutputLevelMode(
150 R_SUCCEED(); 150 R_SUCCEED();
151} 151}
152 152
153Result IAudioController::NotifyHeadphoneVolumeWarningDisplayedEvent() {
154 LOG_WARNING(Service_Audio, "(STUBBED) called");
155 R_SUCCEED();
156}
157
153Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) { 158Result IAudioController::SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled) {
154 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); 159 LOG_INFO(Audio, "called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled);
155 160
diff --git a/src/core/hle/service/audio/audio_controller.h b/src/core/hle/service/audio/audio_controller.h
index 9e8514373..d37c4843e 100644
--- a/src/core/hle/service/audio/audio_controller.h
+++ b/src/core/hle/service/audio/audio_controller.h
@@ -45,6 +45,7 @@ private:
45 Set::AudioOutputMode output_mode); 45 Set::AudioOutputMode output_mode);
46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode); 46 Result SetHeadphoneOutputLevelMode(HeadphoneOutputLevelMode output_level_mode);
47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode); 47 Result GetHeadphoneOutputLevelMode(Out<HeadphoneOutputLevelMode> out_output_level_mode);
48 Result NotifyHeadphoneVolumeWarningDisplayedEvent();
48 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled); 49 Result SetSpeakerAutoMuteEnabled(bool is_speaker_auto_mute_enabled);
49 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled); 50 Result IsSpeakerAutoMuteEnabled(Out<bool> out_is_speaker_auto_mute_enabled);
50 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event); 51 Result AcquireTargetNotification(OutCopyHandle<Kernel::KReadableEvent> out_notification_event);
diff --git a/src/core/hle/service/audio/audio_device.cpp b/src/core/hle/service/audio/audio_device.cpp
new file mode 100644
index 000000000..438f3cccd
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.cpp
@@ -0,0 +1,163 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_core.h"
5#include "common/string_util.h"
6#include "core/hle/service/audio/audio_device.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::Renderer;
11
12IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
13 u32 device_num)
14 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
15 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
16 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
17 static const FunctionInfo functions[] = {
18 {0, D<&IAudioDevice::ListAudioDeviceName>, "ListAudioDeviceName"},
19 {1, D<&IAudioDevice::SetAudioDeviceOutputVolume>, "SetAudioDeviceOutputVolume"},
20 {2, D<&IAudioDevice::GetAudioDeviceOutputVolume>, "GetAudioDeviceOutputVolume"},
21 {3, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioDeviceName"},
22 {4, D<&IAudioDevice::QueryAudioDeviceSystemEvent>, "QueryAudioDeviceSystemEvent"},
23 {5, D<&IAudioDevice::GetActiveChannelCount>, "GetActiveChannelCount"},
24 {6, D<&IAudioDevice::ListAudioDeviceNameAuto>, "ListAudioDeviceNameAuto"},
25 {7, D<&IAudioDevice::SetAudioDeviceOutputVolumeAuto>, "SetAudioDeviceOutputVolumeAuto"},
26 {8, D<&IAudioDevice::GetAudioDeviceOutputVolumeAuto>, "GetAudioDeviceOutputVolumeAuto"},
27 {10, D<&IAudioDevice::GetActiveAudioDeviceNameAuto>, "GetActiveAudioDeviceNameAuto"},
28 {11, D<&IAudioDevice::QueryAudioDeviceInputEvent>, "QueryAudioDeviceInputEvent"},
29 {12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
30 {13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
31 {14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
32 };
33 RegisterHandlers(functions);
34
35 event->Signal();
36}
37
38IAudioDevice::~IAudioDevice() {
39 service_context.CloseEvent(event);
40}
41
42Result IAudioDevice::ListAudioDeviceName(
43 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
44 R_RETURN(this->ListAudioDeviceNameAuto(out_names, out_count));
45}
46
47Result IAudioDevice::SetAudioDeviceOutputVolume(
48 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume) {
49 R_RETURN(this->SetAudioDeviceOutputVolumeAuto(name, volume));
50}
51
52Result IAudioDevice::GetAudioDeviceOutputVolume(
53 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name) {
54 R_RETURN(this->GetAudioDeviceOutputVolumeAuto(out_volume, name));
55}
56
57Result IAudioDevice::GetActiveAudioDeviceName(
58 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name) {
59 R_RETURN(this->GetActiveAudioDeviceNameAuto(out_name));
60}
61
62Result IAudioDevice::ListAudioDeviceNameAuto(
63 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
64 Out<s32> out_count) {
65 *out_count = impl->ListAudioDeviceName(out_names);
66
67 std::string out{};
68 for (s32 i = 0; i < *out_count; i++) {
69 std::string a{};
70 u32 j = 0;
71 while (out_names[i].name[j] != '\0') {
72 a += out_names[i].name[j];
73 j++;
74 }
75 out += "\n\t" + a;
76 }
77
78 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
79 R_SUCCEED();
80}
81
82Result IAudioDevice::SetAudioDeviceOutputVolumeAuto(
83 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume) {
84 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
85
86 const std::string device_name = Common::StringFromBuffer(name[0].name);
87 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", device_name, volume);
88
89 if (device_name == "AudioTvOutput") {
90 impl->SetDeviceVolumes(volume);
91 }
92
93 R_SUCCEED();
94}
95
96Result IAudioDevice::GetAudioDeviceOutputVolumeAuto(
97 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name) {
98 R_UNLESS(!name.empty(), Audio::ResultInsufficientBuffer);
99
100 const std::string device_name = Common::StringFromBuffer(name[0].name);
101 LOG_DEBUG(Service_Audio, "called. Name={}", device_name);
102
103 *out_volume = 1.0f;
104 if (device_name == "AudioTvOutput") {
105 *out_volume = impl->GetDeviceVolume(device_name);
106 }
107
108 R_SUCCEED();
109}
110
111Result IAudioDevice::GetActiveAudioDeviceNameAuto(
112 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name) {
113 R_UNLESS(!out_name.empty(), Audio::ResultInsufficientBuffer);
114 out_name[0] = AudioDevice::AudioDeviceName("AudioTvOutput");
115 LOG_DEBUG(Service_Audio, "(STUBBED) called");
116 R_SUCCEED();
117}
118
119Result IAudioDevice::QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
120 LOG_DEBUG(Service_Audio, "(STUBBED) called");
121 event->Signal();
122 *out_event = &event->GetReadableEvent();
123 R_SUCCEED();
124}
125
126Result IAudioDevice::QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
127 LOG_DEBUG(Service_Audio, "(STUBBED) called");
128 *out_event = &event->GetReadableEvent();
129 R_SUCCEED();
130}
131
132Result IAudioDevice::QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
133 LOG_DEBUG(Service_Audio, "called");
134 *out_event = &event->GetReadableEvent();
135 R_SUCCEED();
136}
137
138Result IAudioDevice::GetActiveChannelCount(Out<u32> out_active_channel_count) {
139 *out_active_channel_count = system.AudioCore().GetOutputSink().GetSystemChannels();
140 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", *out_active_channel_count);
141 R_SUCCEED();
142}
143
144Result IAudioDevice::ListAudioOutputDeviceName(
145 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names, Out<s32> out_count) {
146 *out_count = impl->ListAudioOutputDeviceName(out_names);
147
148 std::string out{};
149 for (s32 i = 0; i < *out_count; i++) {
150 std::string a{};
151 u32 j = 0;
152 while (out_names[i].name[j] != '\0') {
153 a += out_names[i].name[j];
154 j++;
155 }
156 out += "\n\t" + a;
157 }
158
159 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
160 R_SUCCEED();
161}
162
163} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_device.h b/src/core/hle/service/audio/audio_device.h
new file mode 100644
index 000000000..752157272
--- /dev/null
+++ b/src/core/hle/service/audio/audio_device.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_device.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17using AudioCore::Renderer::AudioDevice;
18
19class IAudioDevice final : public ServiceFramework<IAudioDevice> {
20
21public:
22 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
23 u32 device_num);
24 ~IAudioDevice() override;
25
26private:
27 Result ListAudioDeviceName(
28 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
29 Out<s32> out_count);
30 Result SetAudioDeviceOutputVolume(
31 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name, f32 volume);
32 Result GetAudioDeviceOutputVolume(
33 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> name);
34 Result GetActiveAudioDeviceName(
35 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_name);
36 Result ListAudioDeviceNameAuto(
37 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_names,
38 Out<s32> out_count);
39 Result SetAudioDeviceOutputVolumeAuto(
40 InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name, f32 volume);
41 Result GetAudioDeviceOutputVolumeAuto(
42 Out<f32> out_volume, InArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> name);
43 Result GetActiveAudioDeviceNameAuto(
44 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcAutoSelect> out_name);
45 Result QueryAudioDeviceSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
46 Result QueryAudioDeviceInputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
47 Result QueryAudioDeviceOutputEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
48 Result GetActiveChannelCount(Out<u32> out_active_channel_count);
49 Result ListAudioOutputDeviceName(
50 OutArray<AudioDevice::AudioDeviceName, BufferAttr_HipcMapAlias> out_names,
51 Out<s32> out_count);
52
53 KernelHelpers::ServiceContext service_context;
54 std::unique_ptr<AudioCore::Renderer::AudioDevice> impl;
55 Kernel::KEvent* event;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.cpp b/src/core/hle/service/audio/audio_in.cpp
new file mode 100644
index 000000000..416803acc
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_in.h"
5#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::Audio {
9using namespace AudioCore::AudioIn;
10
11IAudioIn::IAudioIn(Core::System& system_, Manager& manager, size_t session_id,
12 const std::string& device_name, const AudioInParameter& in_params,
13 Kernel::KProcess* handle, u64 applet_resource_user_id)
14 : ServiceFramework{system_, "IAudioIn"}, process{handle}, service_context{system_, "IAudioIn"},
15 event{service_context.CreateEvent("AudioInEvent")}, impl{std::make_shared<In>(system_,
16 manager, event,
17 session_id)} {
18 // clang-format off
19 static const FunctionInfo functions[] = {
20 {0, D<&IAudioIn::GetAudioInState>, "GetAudioInState"},
21 {1, D<&IAudioIn::Start>, "Start"},
22 {2, D<&IAudioIn::Stop>, "Stop"},
23 {3, D<&IAudioIn::AppendAudioInBuffer>, "AppendAudioInBuffer"},
24 {4, D<&IAudioIn::RegisterBufferEvent>, "RegisterBufferEvent"},
25 {5, D<&IAudioIn::GetReleasedAudioInBuffers>, "GetReleasedAudioInBuffers"},
26 {6, D<&IAudioIn::ContainsAudioInBuffer>, "ContainsAudioInBuffer"},
27 {7, D<&IAudioIn::AppendAudioInBuffer>, "AppendUacInBuffer"},
28 {8, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendAudioInBufferAuto"},
29 {9, D<&IAudioIn::GetReleasedAudioInBuffersAuto>, "GetReleasedAudioInBuffersAuto"},
30 {10, D<&IAudioIn::AppendAudioInBufferAuto>, "AppendUacInBufferAuto"},
31 {11, D<&IAudioIn::GetAudioInBufferCount>, "GetAudioInBufferCount"},
32 {12, D<&IAudioIn::SetDeviceGain>, "SetDeviceGain"},
33 {13, D<&IAudioIn::GetDeviceGain>, "GetDeviceGain"},
34 {14, D<&IAudioIn::FlushAudioInBuffers>, "FlushAudioInBuffers"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39
40 process->Open();
41
42 if (impl->GetSystem()
43 .Initialize(device_name, in_params, handle, applet_resource_user_id)
44 .IsError()) {
45 LOG_ERROR(Service_Audio, "Failed to initialize the AudioIn System!");
46 }
47}
48
49IAudioIn::~IAudioIn() {
50 impl->Free();
51 service_context.CloseEvent(event);
52 process->Close();
53}
54
55Result IAudioIn::GetAudioInState(Out<u32> out_state) {
56 *out_state = static_cast<u32>(impl->GetState());
57 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
58 R_SUCCEED();
59}
60
61Result IAudioIn::Start() {
62 LOG_DEBUG(Service_Audio, "called");
63 R_RETURN(impl->StartSystem());
64}
65
66Result IAudioIn::Stop() {
67 LOG_DEBUG(Service_Audio, "called");
68 R_RETURN(impl->StopSystem());
69}
70
71Result IAudioIn::AppendAudioInBuffer(InArray<AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
72 u64 buffer_client_ptr) {
73 R_RETURN(this->AppendAudioInBufferAuto(buffer, buffer_client_ptr));
74}
75
76Result IAudioIn::AppendAudioInBufferAuto(InArray<AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
77 u64 buffer_client_ptr) {
78 if (buffer.empty()) {
79 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioInBuffer!");
80 R_THROW(Audio::ResultInsufficientBuffer);
81 }
82
83 [[maybe_unused]] const auto session_id{impl->GetSystem().GetSessionId()};
84 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}", session_id,
85 buffer_client_ptr);
86
87 R_RETURN(impl->AppendBuffer(buffer[0], buffer_client_ptr));
88}
89
90Result IAudioIn::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
91 LOG_DEBUG(Service_Audio, "called");
92 *out_event = &impl->GetBufferEvent();
93 R_SUCCEED();
94}
95
96Result IAudioIn::GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
97 Out<u32> out_count) {
98 R_RETURN(this->GetReleasedAudioInBuffersAuto(out_audio_buffer, out_count));
99}
100
101Result IAudioIn::GetReleasedAudioInBuffersAuto(
102 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
103
104 if (!out_audio_buffer.empty()) {
105 out_audio_buffer[0] = 0;
106 }
107 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
108
109 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
110 impl->GetSystem().GetSessionId(), *out_count);
111 R_SUCCEED();
112}
113
114Result IAudioIn::ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
115 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
116
117 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
118 *out_contains_buffer);
119 R_SUCCEED();
120}
121
122Result IAudioIn::GetAudioInBufferCount(Out<u32> out_buffer_count) {
123 *out_buffer_count = impl->GetBufferCount();
124 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
125 R_SUCCEED();
126}
127
128Result IAudioIn::SetDeviceGain(f32 device_gain) {
129 impl->SetVolume(device_gain);
130 LOG_DEBUG(Service_Audio, "called. Gain {}", device_gain);
131 R_SUCCEED();
132}
133
134Result IAudioIn::GetDeviceGain(Out<f32> out_device_gain) {
135 *out_device_gain = impl->GetVolume();
136 LOG_DEBUG(Service_Audio, "called. Gain {}", *out_device_gain);
137 R_SUCCEED();
138}
139
140Result IAudioIn::FlushAudioInBuffers(Out<bool> out_flushed) {
141 *out_flushed = impl->FlushAudioInBuffers();
142 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in.h b/src/core/hle/service/audio/audio_in.h
new file mode 100644
index 000000000..3fe1e1e87
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/in/audio_in.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13class IAudioIn final : public ServiceFramework<IAudioIn> {
14public:
15 explicit IAudioIn(Core::System& system_, AudioCore::AudioIn::Manager& manager,
16 size_t session_id, const std::string& device_name,
17 const AudioCore::AudioIn::AudioInParameter& in_params,
18 Kernel::KProcess* handle, u64 applet_resource_user_id);
19 ~IAudioIn() override;
20
21 std::shared_ptr<AudioCore::AudioIn::In> GetImpl() {
22 return impl;
23 }
24
25 Result GetAudioInState(Out<u32> out_state);
26 Result Start();
27 Result Stop();
28 Result AppendAudioInBuffer(
29 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcMapAlias> buffer,
30 u64 buffer_client_ptr);
31 Result AppendAudioInBufferAuto(
32 InArray<AudioCore::AudioIn::AudioInBuffer, BufferAttr_HipcAutoSelect> buffer,
33 u64 buffer_client_ptr);
34 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
35 Result GetReleasedAudioInBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
36 Out<u32> out_count);
37 Result GetReleasedAudioInBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
38 Out<u32> out_count);
39 Result ContainsAudioInBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
40 Result GetAudioInBufferCount(Out<u32> out_buffer_count);
41 Result SetDeviceGain(f32 device_gain);
42 Result GetDeviceGain(Out<f32> out_device_gain);
43 Result FlushAudioInBuffers(Out<bool> out_flushed);
44
45private:
46 Kernel::KProcess* process;
47 KernelHelpers::ServiceContext service_context;
48 Kernel::KEvent* event;
49 std::shared_ptr<AudioCore::AudioIn::In> impl;
50 Common::ScratchBuffer<u64> released_buffer;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.cpp b/src/core/hle/service/audio/audio_in_manager.cpp
new file mode 100644
index 000000000..2675a5773
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.cpp
@@ -0,0 +1,125 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_in.h"
6#include "core/hle/service/audio/audio_in_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::Audio {
10using namespace AudioCore::AudioIn;
11
12IAudioInManager::IAudioInManager(Core::System& system_)
13 : ServiceFramework{system_, "audin:u"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
14 system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioInManager::ListAudioIns>, "ListAudioIns"},
18 {1, D<&IAudioInManager::OpenAudioIn>, "OpenAudioIn"},
19 {2, D<&IAudioInManager::ListAudioIns>, "ListAudioInsAuto"},
20 {3, D<&IAudioInManager::OpenAudioIn>, "OpenAudioInAuto"},
21 {4, D<&IAudioInManager::ListAudioInsAutoFiltered>, "ListAudioInsAutoFiltered"},
22 {5, D<&IAudioInManager::OpenAudioInProtocolSpecified>, "OpenAudioInProtocolSpecified"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IAudioInManager::~IAudioInManager() = default;
30
31Result IAudioInManager::ListAudioIns(
32 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins, Out<u32> out_count) {
33 LOG_DEBUG(Service_Audio, "called");
34 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
35}
36
37Result IAudioInManager::OpenAudioIn(Out<AudioInParameterInternal> out_parameter_internal,
38 Out<SharedPointer<IAudioIn>> out_audio_in,
39 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
40 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
41 AudioInParameter parameter,
42 InCopyHandle<Kernel::KProcess> process_handle,
43 ClientAppletResourceUserId aruid) {
44 LOG_DEBUG(Service_Audio, "called");
45 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
46 name, {}, parameter, process_handle, aruid));
47}
48
49Result IAudioInManager::ListAudioInsAuto(
50 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
51 LOG_DEBUG(Service_Audio, "called");
52 R_RETURN(this->ListAudioInsAutoFiltered(out_audio_ins, out_count));
53}
54
55Result IAudioInManager::OpenAudioInAuto(
56 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
57 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
58 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioInParameter parameter,
59 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
60 LOG_DEBUG(Service_Audio, "called");
61 R_RETURN(this->OpenAudioInProtocolSpecified(out_parameter_internal, out_audio_in, out_name,
62 name, {}, parameter, process_handle, aruid));
63}
64
65Result IAudioInManager::ListAudioInsAutoFiltered(
66 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count) {
67 LOG_DEBUG(Service_Audio, "called");
68 *out_count = impl->GetDeviceNames(out_audio_ins, true);
69 R_SUCCEED();
70}
71
72Result IAudioInManager::OpenAudioInProtocolSpecified(
73 Out<AudioInParameterInternal> out_parameter_internal, Out<SharedPointer<IAudioIn>> out_audio_in,
74 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
75 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
76 AudioInParameter parameter, InCopyHandle<Kernel::KProcess> process_handle,
77 ClientAppletResourceUserId aruid) {
78 LOG_DEBUG(Service_Audio, "called");
79
80 if (!process_handle) {
81 LOG_ERROR(Service_Audio, "Failed to get process handle");
82 R_THROW(ResultUnknown);
83 }
84 if (name.empty() || out_name.empty()) {
85 LOG_ERROR(Service_Audio, "Invalid buffers");
86 R_THROW(ResultUnknown);
87 }
88
89 std::scoped_lock l{impl->mutex};
90
91 size_t new_session_id{};
92
93 R_TRY(impl->LinkToManager());
94 R_TRY(impl->AcquireSessionId(new_session_id));
95
96 LOG_DEBUG(Service_Audio, "Opening new AudioIn, session_id={}, free sessions={}", new_session_id,
97 impl->num_free_sessions);
98
99 const auto device_name = Common::StringFromBuffer(name[0].name);
100 *out_audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name,
101 parameter, process_handle.Get(), aruid.pid);
102 impl->sessions[new_session_id] = (*out_audio_in)->GetImpl();
103 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
104
105 auto& out_system = impl->sessions[new_session_id]->GetSystem();
106 *out_parameter_internal =
107 AudioInParameterInternal{.sample_rate = out_system.GetSampleRate(),
108 .channel_count = out_system.GetChannelCount(),
109 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
110 .state = static_cast<u32>(out_system.GetState())};
111
112 out_name[0] = AudioDeviceName(out_system.GetName());
113
114 if (protocol == Protocol{}) {
115 if (out_system.IsUac()) {
116 out_name[0] = AudioDeviceName("UacIn");
117 } else {
118 out_name[0] = AudioDeviceName("DeviceIn");
119 }
120 }
121
122 R_SUCCEED();
123}
124
125} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_in_manager.h b/src/core/hle/service/audio/audio_in_manager.h
new file mode 100644
index 000000000..2a983bc60
--- /dev/null
+++ b/src/core/hle/service/audio/audio_in_manager.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_in_manager.h"
7#include "audio_core/in/audio_in_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14using Protocol = std::array<u32, 2>;
15
16class IAudioIn;
17
18class IAudioInManager final : public ServiceFramework<IAudioInManager> {
19public:
20 explicit IAudioInManager(Core::System& system_);
21 ~IAudioInManager() override;
22
23private:
24 Result ListAudioIns(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_ins,
25 Out<u32> out_count);
26 Result OpenAudioIn(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
27 Out<SharedPointer<IAudioIn>> out_audio_in,
28 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
29 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
30 AudioCore::AudioIn::AudioInParameter parameter,
31 InCopyHandle<Kernel::KProcess> process_handle,
32 ClientAppletResourceUserId aruid);
33
34 Result ListAudioInsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins,
35 Out<u32> out_count);
36 Result OpenAudioInAuto(Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
37 Out<SharedPointer<IAudioIn>> out_audio_in,
38 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
39 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
40 AudioCore::AudioIn::AudioInParameter parameter,
41 InCopyHandle<Kernel::KProcess> process_handle,
42 ClientAppletResourceUserId aruid);
43
44 Result ListAudioInsAutoFiltered(
45 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_ins, Out<u32> out_count);
46 Result OpenAudioInProtocolSpecified(
47 Out<AudioCore::AudioIn::AudioInParameterInternal> out_parameter_internal,
48 Out<SharedPointer<IAudioIn>> out_audio_in,
49 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
50 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, Protocol protocol,
51 AudioCore::AudioIn::AudioInParameter parameter,
52 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
53
54 std::unique_ptr<AudioCore::AudioIn::Manager> impl;
55};
56
57} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.cpp b/src/core/hle/service/audio/audio_out.cpp
new file mode 100644
index 000000000..53009d5d7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.cpp
@@ -0,0 +1,146 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/out/audio_out.h"
5#include "audio_core/out/audio_out_system.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/service/audio/audio_out.h"
8#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Service::Audio {
13using namespace AudioCore::AudioOut;
14
15IAudioOut::IAudioOut(Core::System& system_, Manager& manager, size_t session_id,
16 const std::string& device_name, const AudioOutParameter& in_params,
17 Kernel::KProcess* handle, u64 applet_resource_user_id)
18 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
19 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
20 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
21
22 // clang-format off
23 static const FunctionInfo functions[] = {
24 {0, D<&IAudioOut::GetAudioOutState>, "GetAudioOutState"},
25 {1, D<&IAudioOut::Start>, "Start"},
26 {2, D<&IAudioOut::Stop>, "Stop"},
27 {3, D<&IAudioOut::AppendAudioOutBuffer>, "AppendAudioOutBuffer"},
28 {4, D<&IAudioOut::RegisterBufferEvent>, "RegisterBufferEvent"},
29 {5, D<&IAudioOut::GetReleasedAudioOutBuffers>, "GetReleasedAudioOutBuffers"},
30 {6, D<&IAudioOut::ContainsAudioOutBuffer>, "ContainsAudioOutBuffer"},
31 {7, D<&IAudioOut::AppendAudioOutBufferAuto>, "AppendAudioOutBufferAuto"},
32 {8, D<&IAudioOut::GetReleasedAudioOutBuffersAuto>, "GetReleasedAudioOutBuffersAuto"},
33 {9, D<&IAudioOut::GetAudioOutBufferCount>, "GetAudioOutBufferCount"},
34 {10, D<&IAudioOut::GetAudioOutPlayedSampleCount>, "GetAudioOutPlayedSampleCount"},
35 {11, D<&IAudioOut::FlushAudioOutBuffers>, "FlushAudioOutBuffers"},
36 {12, D<&IAudioOut::SetAudioOutVolume>, "SetAudioOutVolume"},
37 {13, D<&IAudioOut::GetAudioOutVolume>, "GetAudioOutVolume"},
38 };
39 // clang-format on
40 RegisterHandlers(functions);
41
42 process->Open();
43}
44
45IAudioOut::~IAudioOut() {
46 impl->Free();
47 service_context.CloseEvent(event);
48 process->Close();
49}
50
51Result IAudioOut::GetAudioOutState(Out<u32> out_state) {
52 *out_state = static_cast<u32>(impl->GetState());
53 LOG_DEBUG(Service_Audio, "called. state={}", *out_state);
54 R_SUCCEED();
55}
56
57Result IAudioOut::Start() {
58 LOG_DEBUG(Service_Audio, "called");
59 R_RETURN(impl->StartSystem());
60}
61
62Result IAudioOut::Stop() {
63 LOG_DEBUG(Service_Audio, "called");
64 R_RETURN(impl->StopSystem());
65}
66
67Result IAudioOut::AppendAudioOutBuffer(
68 InArray<AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer, u64 buffer_client_ptr) {
69 R_RETURN(this->AppendAudioOutBufferAuto(audio_out_buffer, buffer_client_ptr));
70}
71
72Result IAudioOut::AppendAudioOutBufferAuto(
73 InArray<AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer, u64 buffer_client_ptr) {
74 if (audio_out_buffer.empty()) {
75 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
76 R_THROW(Audio::ResultInsufficientBuffer);
77 }
78
79 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
80 impl->GetSystem().GetSessionId(), buffer_client_ptr);
81 R_RETURN(impl->AppendBuffer(audio_out_buffer[0], buffer_client_ptr));
82}
83
84Result IAudioOut::RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
85 LOG_DEBUG(Service_Audio, "called");
86 *out_event = &impl->GetBufferEvent();
87 R_SUCCEED();
88}
89
90Result IAudioOut::GetReleasedAudioOutBuffers(
91 OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer, Out<u32> out_count) {
92 R_RETURN(this->GetReleasedAudioOutBuffersAuto(out_audio_buffer, out_count));
93}
94
95Result IAudioOut::GetReleasedAudioOutBuffersAuto(
96 OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer, Out<u32> out_count) {
97
98 if (!out_audio_buffer.empty()) {
99 out_audio_buffer[0] = 0;
100 }
101 *out_count = impl->GetReleasedBuffers(out_audio_buffer);
102
103 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
104 impl->GetSystem().GetSessionId(), *out_count);
105 R_SUCCEED();
106}
107
108Result IAudioOut::ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr) {
109 *out_contains_buffer = impl->ContainsAudioBuffer(buffer_client_ptr);
110
111 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", buffer_client_ptr,
112 *out_contains_buffer);
113 R_SUCCEED();
114}
115
116Result IAudioOut::GetAudioOutBufferCount(Out<u32> out_buffer_count) {
117 *out_buffer_count = impl->GetBufferCount();
118 LOG_DEBUG(Service_Audio, "called. Buffer count={}", *out_buffer_count);
119 R_SUCCEED();
120}
121
122Result IAudioOut::GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count) {
123 *out_played_sample_count = impl->GetPlayedSampleCount();
124 LOG_DEBUG(Service_Audio, "called. Played samples={}", *out_played_sample_count);
125 R_SUCCEED();
126}
127
128Result IAudioOut::FlushAudioOutBuffers(Out<bool> out_flushed) {
129 *out_flushed = impl->FlushAudioOutBuffers();
130 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", *out_flushed);
131 R_SUCCEED();
132}
133
134Result IAudioOut::SetAudioOutVolume(f32 volume) {
135 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
136 impl->SetVolume(volume);
137 R_SUCCEED();
138}
139
140Result IAudioOut::GetAudioOutVolume(Out<f32> out_volume) {
141 *out_volume = impl->GetVolume();
142 LOG_DEBUG(Service_Audio, "called. Volume={}", *out_volume);
143 R_SUCCEED();
144}
145
146} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out.h b/src/core/hle/service/audio/audio_out.h
new file mode 100644
index 000000000..779b213e7
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out.h
@@ -0,0 +1,58 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out_system.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Kernel {
13class KReadableEvent;
14}
15
16namespace Service::Audio {
17
18class IAudioOut : public ServiceFramework<IAudioOut> {
19public:
20 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
21 size_t session_id, const std::string& device_name,
22 const AudioCore::AudioOut::AudioOutParameter& in_params,
23 Kernel::KProcess* handle, u64 applet_resource_user_id);
24 ~IAudioOut() override;
25
26 std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
27 return impl;
28 }
29
30 Result GetAudioOutState(Out<u32> out_state);
31 Result Start();
32 Result Stop();
33 Result AppendAudioOutBuffer(
34 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcMapAlias> audio_out_buffer,
35 u64 buffer_client_ptr);
36 Result AppendAudioOutBufferAuto(
37 InArray<AudioCore::AudioOut::AudioOutBuffer, BufferAttr_HipcAutoSelect> audio_out_buffer,
38 u64 buffer_client_ptr);
39 Result RegisterBufferEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result GetReleasedAudioOutBuffers(OutArray<u64, BufferAttr_HipcMapAlias> out_audio_buffer,
41 Out<u32> out_count);
42 Result GetReleasedAudioOutBuffersAuto(OutArray<u64, BufferAttr_HipcAutoSelect> out_audio_buffer,
43 Out<u32> out_count);
44 Result ContainsAudioOutBuffer(Out<bool> out_contains_buffer, u64 buffer_client_ptr);
45 Result GetAudioOutBufferCount(Out<u32> out_buffer_count);
46 Result GetAudioOutPlayedSampleCount(Out<u64> out_played_sample_count);
47 Result FlushAudioOutBuffers(Out<bool> out_flushed);
48 Result SetAudioOutVolume(f32 volume);
49 Result GetAudioOutVolume(Out<f32> out_volume);
50
51private:
52 KernelHelpers::ServiceContext service_context;
53 Kernel::KEvent* event;
54 Kernel::KProcess* process;
55 std::shared_ptr<AudioCore::AudioOut::Out> impl;
56};
57
58} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.cpp b/src/core/hle/service/audio/audio_out_manager.cpp
new file mode 100644
index 000000000..153445097
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.cpp
@@ -0,0 +1,101 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/string_util.h"
5#include "core/hle/service/audio/audio_out.h"
6#include "core/hle/service/audio/audio_out_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/memory.h"
9
10namespace Service::Audio {
11using namespace AudioCore::AudioOut;
12
13IAudioOutManager::IAudioOutManager(Core::System& system_)
14 : ServiceFramework{system_, "audout:u"}, impl{std::make_unique<Manager>(system_)} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, D<&IAudioOutManager::ListAudioOuts>, "ListAudioOuts"},
18 {1, D<&IAudioOutManager::OpenAudioOut>, "OpenAudioOut"},
19 {2, D<&IAudioOutManager::ListAudioOutsAuto>, "ListAudioOutsAuto"},
20 {3, D<&IAudioOutManager::OpenAudioOutAuto>, "OpenAudioOutAuto"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25}
26
27IAudioOutManager::~IAudioOutManager() = default;
28
29Result IAudioOutManager::ListAudioOuts(
30 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs, Out<u32> out_count) {
31 R_RETURN(this->ListAudioOutsAuto(out_audio_outs, out_count));
32}
33
34Result IAudioOutManager::OpenAudioOut(Out<AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
38 AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle,
40 ClientAppletResourceUserId aruid) {
41 R_RETURN(this->OpenAudioOutAuto(out_parameter_internal, out_audio_out, out_name, name,
42 parameter, process_handle, aruid));
43}
44
45Result IAudioOutManager::ListAudioOutsAuto(
46 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs, Out<u32> out_count) {
47 if (!out_audio_outs.empty()) {
48 out_audio_outs[0] = AudioDeviceName("DeviceOut");
49 *out_count = 1;
50 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
51 } else {
52 *out_count = 0;
53 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
54 }
55
56 R_SUCCEED();
57}
58
59Result IAudioOutManager::OpenAudioOutAuto(
60 Out<AudioOutParameterInternal> out_parameter_internal,
61 Out<SharedPointer<IAudioOut>> out_audio_out,
62 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
63 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name, AudioOutParameter parameter,
64 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
65 if (!process_handle) {
66 LOG_ERROR(Service_Audio, "Failed to get process handle");
67 R_THROW(ResultUnknown);
68 }
69 if (name.empty() || out_name.empty()) {
70 LOG_ERROR(Service_Audio, "Invalid buffers");
71 R_THROW(ResultUnknown);
72 }
73
74 size_t new_session_id{};
75 R_TRY(impl->LinkToManager());
76 R_TRY(impl->AcquireSessionId(new_session_id));
77
78 const auto device_name = Common::StringFromBuffer(name[0].name);
79 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
80 impl->num_free_sessions);
81
82 auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
83 parameter, process_handle.Get(), aruid.pid);
84 R_TRY(audio_out->GetImpl()->GetSystem().Initialize(device_name, parameter, process_handle.Get(),
85 aruid.pid));
86
87 *out_audio_out = audio_out;
88 impl->sessions[new_session_id] = audio_out->GetImpl();
89 impl->applet_resource_user_ids[new_session_id] = aruid.pid;
90
91 auto& out_system = impl->sessions[new_session_id]->GetSystem();
92 *out_parameter_internal =
93 AudioOutParameterInternal{.sample_rate = out_system.GetSampleRate(),
94 .channel_count = out_system.GetChannelCount(),
95 .sample_format = static_cast<u32>(out_system.GetSampleFormat()),
96 .state = static_cast<u32>(out_system.GetState())};
97
98 R_SUCCEED();
99}
100
101} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_out_manager.h b/src/core/hle/service/audio/audio_out_manager.h
new file mode 100644
index 000000000..eaa27bc79
--- /dev/null
+++ b/src/core/hle/service/audio/audio_out_manager.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::Audio {
12
13using AudioDeviceName = AudioCore::Renderer::AudioDevice::AudioDeviceName;
14class IAudioOut;
15
16class IAudioOutManager final : public ServiceFramework<IAudioOutManager> {
17public:
18 explicit IAudioOutManager(Core::System& system_);
19 ~IAudioOutManager() override;
20
21private:
22 Result ListAudioOuts(OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_audio_outs,
23 Out<u32> out_count);
24 Result OpenAudioOut(Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
25 Out<SharedPointer<IAudioOut>> out_audio_out,
26 OutArray<AudioDeviceName, BufferAttr_HipcMapAlias> out_name,
27 InArray<AudioDeviceName, BufferAttr_HipcMapAlias> name,
28 AudioCore::AudioOut::AudioOutParameter parameter,
29 InCopyHandle<Kernel::KProcess> process_handle,
30 ClientAppletResourceUserId aruid);
31 Result ListAudioOutsAuto(OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_audio_outs,
32 Out<u32> out_count);
33 Result OpenAudioOutAuto(
34 Out<AudioCore::AudioOut::AudioOutParameterInternal> out_parameter_internal,
35 Out<SharedPointer<IAudioOut>> out_audio_out,
36 OutArray<AudioDeviceName, BufferAttr_HipcAutoSelect> out_name,
37 InArray<AudioDeviceName, BufferAttr_HipcAutoSelect> name,
38 AudioCore::AudioOut::AudioOutParameter parameter,
39 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid);
40
41 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
42};
43
44} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.cpp b/src/core/hle/service/audio/audio_renderer.cpp
new file mode 100644
index 000000000..fc4aad233
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.cpp
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/audio_renderer.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8using namespace AudioCore::Renderer;
9
10IAudioRenderer::IAudioRenderer(Core::System& system_, Manager& manager_,
11 AudioCore::AudioRendererParameterInternal& params,
12 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
13 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
14 s32 session_id)
15 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
16 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
17 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process_handle{
18 process_handle_} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRenderer::GetSampleRate>, "GetSampleRate"},
22 {1, D<&IAudioRenderer::GetSampleCount>, "GetSampleCount"},
23 {2, D<&IAudioRenderer::GetMixBufferCount>, "GetMixBufferCount"},
24 {3, D<&IAudioRenderer::GetState>, "GetState"},
25 {4, D<&IAudioRenderer::RequestUpdate>, "RequestUpdate"},
26 {5, D<&IAudioRenderer::Start>, "Start"},
27 {6, D<&IAudioRenderer::Stop>, "Stop"},
28 {7, D<&IAudioRenderer::QuerySystemEvent>, "QuerySystemEvent"},
29 {8, D<&IAudioRenderer::SetRenderingTimeLimit>, "SetRenderingTimeLimit"},
30 {9, D<&IAudioRenderer::GetRenderingTimeLimit>, "GetRenderingTimeLimit"},
31 {10, D<&IAudioRenderer::RequestUpdateAuto>, "RequestUpdateAuto"},
32 {11, nullptr, "ExecuteAudioRendererRendering"},
33 {12, D<&IAudioRenderer::SetVoiceDropParameter>, "SetVoiceDropParameter"},
34 {13, D<&IAudioRenderer::GetVoiceDropParameter>, "GetVoiceDropParameter"},
35 };
36 // clang-format on
37 RegisterHandlers(functions);
38
39 process_handle->Open();
40 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle,
41 applet_resource_user_id, session_id);
42}
43
44IAudioRenderer::~IAudioRenderer() {
45 impl->Finalize();
46 service_context.CloseEvent(rendered_event);
47 process_handle->Close();
48}
49
50Result IAudioRenderer::GetSampleRate(Out<u32> out_sample_rate) {
51 *out_sample_rate = impl->GetSystem().GetSampleRate();
52 LOG_DEBUG(Service_Audio, "called. Sample rate {}", *out_sample_rate);
53 R_SUCCEED();
54}
55
56Result IAudioRenderer::GetSampleCount(Out<u32> out_sample_count) {
57 *out_sample_count = impl->GetSystem().GetSampleCount();
58 LOG_DEBUG(Service_Audio, "called. Sample count {}", *out_sample_count);
59 R_SUCCEED();
60}
61
62Result IAudioRenderer::GetState(Out<u32> out_state) {
63 *out_state = !impl->GetSystem().IsActive();
64 LOG_DEBUG(Service_Audio, "called, state {}", *out_state);
65 R_SUCCEED();
66}
67
68Result IAudioRenderer::GetMixBufferCount(Out<u32> out_mix_buffer_count) {
69 LOG_DEBUG(Service_Audio, "called");
70 *out_mix_buffer_count = impl->GetSystem().GetMixBufferCount();
71 R_SUCCEED();
72}
73
74Result IAudioRenderer::RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
75 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
76 InBuffer<BufferAttr_HipcMapAlias> input) {
77 R_RETURN(this->RequestUpdateAuto(out_buffer, out_performance_buffer, input));
78}
79
80Result IAudioRenderer::RequestUpdateAuto(
81 OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
82 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
83 InBuffer<BufferAttr_HipcAutoSelect> input) {
84 LOG_TRACE(Service_Audio, "called");
85
86 const auto result = impl->RequestUpdate(input, out_performance_buffer, out_buffer);
87 if (result.IsFailure()) {
88 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.GetDescription());
89 }
90
91 R_RETURN(result);
92}
93
94Result IAudioRenderer::Start() {
95 LOG_DEBUG(Service_Audio, "called");
96 impl->Start();
97 R_SUCCEED();
98}
99
100Result IAudioRenderer::Stop() {
101 LOG_DEBUG(Service_Audio, "called");
102 impl->Stop();
103 R_SUCCEED();
104}
105
106Result IAudioRenderer::QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
107 LOG_DEBUG(Service_Audio, "called");
108 R_UNLESS(impl->GetSystem().GetExecutionMode() != AudioCore::ExecutionMode::Manual,
109 Audio::ResultNotSupported);
110 *out_event = &rendered_event->GetReadableEvent();
111 R_SUCCEED();
112}
113
114Result IAudioRenderer::SetRenderingTimeLimit(u32 rendering_time_limit) {
115 LOG_DEBUG(Service_Audio, "called");
116 impl->GetSystem().SetRenderingTimeLimit(rendering_time_limit);
117 ;
118 R_SUCCEED();
119}
120
121Result IAudioRenderer::GetRenderingTimeLimit(Out<u32> out_rendering_time_limit) {
122 LOG_DEBUG(Service_Audio, "called");
123 *out_rendering_time_limit = impl->GetSystem().GetRenderingTimeLimit();
124 R_SUCCEED();
125}
126
127Result IAudioRenderer::SetVoiceDropParameter(f32 voice_drop_parameter) {
128 LOG_DEBUG(Service_Audio, "called");
129 impl->GetSystem().SetVoiceDropParameter(voice_drop_parameter);
130 R_SUCCEED();
131}
132
133Result IAudioRenderer::GetVoiceDropParameter(Out<f32> out_voice_drop_parameter) {
134 LOG_DEBUG(Service_Audio, "called");
135 *out_voice_drop_parameter = impl->GetSystem().GetVoiceDropParameter();
136 R_SUCCEED();
137}
138
139} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer.h b/src/core/hle/service/audio/audio_renderer.h
new file mode 100644
index 000000000..f25c50ce8
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer.h
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/audio_renderer.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13}
14
15namespace Service::Audio {
16
17class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
18public:
19 explicit IAudioRenderer(Core::System& system_, AudioCore::Renderer::Manager& manager_,
20 AudioCore::AudioRendererParameterInternal& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
22 Kernel::KProcess* process_handle_, u64 applet_resource_user_id,
23 s32 session_id);
24 ~IAudioRenderer() override;
25
26private:
27 Result GetSampleRate(Out<u32> out_sample_rate);
28 Result GetSampleCount(Out<u32> out_sample_count);
29 Result GetState(Out<u32> out_state);
30 Result GetMixBufferCount(Out<u32> out_mix_buffer_count);
31 Result RequestUpdate(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
32 OutBuffer<BufferAttr_HipcMapAlias> out_performance_buffer,
33 InBuffer<BufferAttr_HipcMapAlias> input);
34 Result RequestUpdateAuto(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer,
35 OutBuffer<BufferAttr_HipcAutoSelect> out_performance_buffer,
36 InBuffer<BufferAttr_HipcAutoSelect> input);
37 Result Start();
38 Result Stop();
39 Result QuerySystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
40 Result SetRenderingTimeLimit(u32 rendering_time_limit);
41 Result GetRenderingTimeLimit(Out<u32> out_rendering_time_limit);
42 Result SetVoiceDropParameter(f32 voice_drop_parameter);
43 Result GetVoiceDropParameter(Out<f32> out_voice_drop_parameter);
44
45 KernelHelpers::ServiceContext service_context;
46 Kernel::KEvent* rendered_event;
47 AudioCore::Renderer::Manager& manager;
48 std::unique_ptr<AudioCore::Renderer::Renderer> impl;
49 Kernel::KProcess* process_handle;
50 Common::ScratchBuffer<u8> output_buffer;
51 Common::ScratchBuffer<u8> performance_buffer;
52};
53
54} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.cpp b/src/core/hle/service/audio/audio_renderer_manager.cpp
new file mode 100644
index 000000000..6a1345c07
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.cpp
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/audio_render_manager.h"
5#include "audio_core/common/feature_support.h"
6#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_transfer_memory.h"
8#include "core/hle/service/audio/audio_device.h"
9#include "core/hle/service/audio/audio_renderer.h"
10#include "core/hle/service/audio/audio_renderer_manager.h"
11#include "core/hle/service/cmif_serialization.h"
12
13namespace Service::Audio {
14
15using namespace AudioCore::Renderer;
16
17IAudioRendererManager::IAudioRendererManager(Core::System& system_)
18 : ServiceFramework{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, D<&IAudioRendererManager::OpenAudioRenderer>, "OpenAudioRenderer"},
22 {1, D<&IAudioRendererManager::GetWorkBufferSize>, "GetWorkBufferSize"},
23 {2, D<&IAudioRendererManager::GetAudioDeviceService>, "GetAudioDeviceService"},
24 {3, nullptr, "OpenAudioRendererForManualExecution"},
25 {4, D<&IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo>, "GetAudioDeviceServiceWithRevisionInfo"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IAudioRendererManager::~IAudioRendererManager() = default;
33
34Result IAudioRendererManager::OpenAudioRenderer(
35 Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
36 AudioCore::AudioRendererParameterInternal parameter,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
38 InCopyHandle<Kernel::KProcess> process_handle, ClientAppletResourceUserId aruid) {
39 LOG_DEBUG(Service_Audio, "called");
40
41 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
42 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
43 R_THROW(Audio::ResultOutOfSessions);
44 }
45
46 const auto session_id{impl->GetSessionId()};
47 if (session_id == -1) {
48 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
49 R_THROW(Audio::ResultOutOfSessions);
50 }
51
52 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
53 impl->GetSessionCount());
54
55 *out_audio_renderer =
56 std::make_shared<IAudioRenderer>(system, *impl, parameter, tmem_handle.Get(), tmem_size,
57 process_handle.Get(), aruid.pid, session_id);
58 R_SUCCEED();
59}
60
61Result IAudioRendererManager::GetWorkBufferSize(Out<u64> out_size,
62 AudioCore::AudioRendererParameterInternal params) {
63 LOG_DEBUG(Service_Audio, "called");
64
65 R_TRY(impl->GetWorkBufferSize(params, *out_size))
66
67 std::string output_info{};
68 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
69 output_info +=
70 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
71 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
72 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
73 output_info += fmt::format(
74 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
75 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
76 "Context {:04X}",
77 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
78 params.splitter_destinations, params.voices, params.perf_frames,
79 params.external_context_size);
80
81 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
82 output_info, *out_size);
83 R_SUCCEED();
84}
85
86Result IAudioRendererManager::GetAudioDeviceService(
87 Out<SharedPointer<IAudioDevice>> out_audio_device, ClientAppletResourceUserId aruid) {
88 LOG_DEBUG(Service_Audio, "called, aruid={:#x}", aruid.pid);
89 *out_audio_device = std::make_shared<IAudioDevice>(
90 system, aruid.pid, Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
91 R_SUCCEED();
92}
93
94Result IAudioRendererManager::GetAudioDeviceServiceWithRevisionInfo(
95 Out<SharedPointer<IAudioDevice>> out_audio_device, u32 revision,
96 ClientAppletResourceUserId aruid) {
97 LOG_DEBUG(Service_Audio, "called, revision={} aruid={:#x}", AudioCore::GetRevisionNum(revision),
98 aruid.pid);
99 *out_audio_device =
100 std::make_shared<IAudioDevice>(system, aruid.pid, revision, num_audio_devices++);
101 R_SUCCEED();
102}
103
104} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio_renderer_manager.h b/src/core/hle/service/audio/audio_renderer_manager.h
new file mode 100644
index 000000000..69eee664c
--- /dev/null
+++ b/src/core/hle/service/audio/audio_renderer_manager.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_render_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IAudioDevice;
13class IAudioRenderer;
14
15class IAudioRendererManager final : public ServiceFramework<IAudioRendererManager> {
16public:
17 explicit IAudioRendererManager(Core::System& system_);
18 ~IAudioRendererManager() override;
19
20private:
21 Result OpenAudioRenderer(Out<SharedPointer<IAudioRenderer>> out_audio_renderer,
22 AudioCore::AudioRendererParameterInternal parameter,
23 InCopyHandle<Kernel::KTransferMemory> tmem_handle, u64 tmem_size,
24 InCopyHandle<Kernel::KProcess> process_handle,
25 ClientAppletResourceUserId aruid);
26 Result GetWorkBufferSize(Out<u64> out_size,
27 AudioCore::AudioRendererParameterInternal parameter);
28 Result GetAudioDeviceService(Out<SharedPointer<IAudioDevice>> out_audio_device,
29 ClientAppletResourceUserId aruid);
30 Result GetAudioDeviceServiceWithRevisionInfo(Out<SharedPointer<IAudioDevice>> out_audio_device,
31 u32 revision, ClientAppletResourceUserId aruid);
32
33 std::unique_ptr<AudioCore::Renderer::Manager> impl;
34 u32 num_audio_devices{0};
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
deleted file mode 100644
index 8cc7b69f4..000000000
--- a/src/core/hle/service/audio/audout_u.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <cstring>
6#include <vector>
7
8#include "audio_core/out/audio_out_system.h"
9#include "audio_core/renderer/audio_device.h"
10#include "common/common_funcs.h"
11#include "common/logging/log.h"
12#include "common/scratch_buffer.h"
13#include "common/string_util.h"
14#include "common/swap.h"
15#include "core/core.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/audio/audout_u.h"
18#include "core/hle/service/audio/errors.h"
19#include "core/hle/service/ipc_helpers.h"
20#include "core/memory.h"
21
22namespace Service::Audio {
23using namespace AudioCore::AudioOut;
24
25class IAudioOut final : public ServiceFramework<IAudioOut> {
26public:
27 explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
28 size_t session_id, const std::string& device_name,
29 const AudioOutParameter& in_params, Kernel::KProcess* handle,
30 u64 applet_resource_user_id)
31 : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
32 event{service_context.CreateEvent("AudioOutEvent")}, process{handle},
33 impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
34
35 // clang-format off
36 static const FunctionInfo functions[] = {
37 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
38 {1, &IAudioOut::Start, "Start"},
39 {2, &IAudioOut::Stop, "Stop"},
40 {3, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBuffer"},
41 {4, &IAudioOut::RegisterBufferEvent, "RegisterBufferEvent"},
42 {5, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffers"},
43 {6, &IAudioOut::ContainsAudioOutBuffer, "ContainsAudioOutBuffer"},
44 {7, &IAudioOut::AppendAudioOutBuffer, "AppendAudioOutBufferAuto"},
45 {8, &IAudioOut::GetReleasedAudioOutBuffers, "GetReleasedAudioOutBuffersAuto"},
46 {9, &IAudioOut::GetAudioOutBufferCount, "GetAudioOutBufferCount"},
47 {10, &IAudioOut::GetAudioOutPlayedSampleCount, "GetAudioOutPlayedSampleCount"},
48 {11, &IAudioOut::FlushAudioOutBuffers, "FlushAudioOutBuffers"},
49 {12, &IAudioOut::SetAudioOutVolume, "SetAudioOutVolume"},
50 {13, &IAudioOut::GetAudioOutVolume, "GetAudioOutVolume"},
51 };
52 // clang-format on
53 RegisterHandlers(functions);
54
55 process->Open();
56 }
57
58 ~IAudioOut() override {
59 impl->Free();
60 service_context.CloseEvent(event);
61 process->Close();
62 }
63
64 [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() {
65 return impl;
66 }
67
68private:
69 void GetAudioOutState(HLERequestContext& ctx) {
70 const auto state = static_cast<u32>(impl->GetState());
71
72 LOG_DEBUG(Service_Audio, "called. State={}", state);
73
74 IPC::ResponseBuilder rb{ctx, 3};
75 rb.Push(ResultSuccess);
76 rb.Push(state);
77 }
78
79 void Start(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Audio, "called");
81
82 auto result = impl->StartSystem();
83
84 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(result);
86 }
87
88 void Stop(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_Audio, "called");
90
91 auto result = impl->StopSystem();
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(result);
95 }
96
97 void AppendAudioOutBuffer(HLERequestContext& ctx) {
98 IPC::RequestParser rp{ctx};
99 u64 tag = rp.PopRaw<u64>();
100
101 const auto in_buffer_size{ctx.GetReadBufferSize()};
102 if (in_buffer_size < sizeof(AudioOutBuffer)) {
103 LOG_ERROR(Service_Audio, "Input buffer is too small for an AudioOutBuffer!");
104 }
105
106 const auto& in_buffer = ctx.ReadBuffer();
107 AudioOutBuffer buffer{};
108 std::memcpy(&buffer, in_buffer.data(), sizeof(AudioOutBuffer));
109
110 LOG_TRACE(Service_Audio, "called. Session {} Appending buffer {:08X}",
111 impl->GetSystem().GetSessionId(), tag);
112
113 auto result = impl->AppendBuffer(buffer, tag);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void RegisterBufferEvent(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_Audio, "called");
121
122 auto& buffer_event = impl->GetBufferEvent();
123
124 IPC::ResponseBuilder rb{ctx, 2, 1};
125 rb.Push(ResultSuccess);
126 rb.PushCopyObjects(buffer_event);
127 }
128
129 void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
130 const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
131 released_buffer.resize_destructive(write_buffer_size);
132 released_buffer[0] = 0;
133
134 const auto count = impl->GetReleasedBuffers(released_buffer);
135
136 ctx.WriteBuffer(released_buffer);
137
138 LOG_TRACE(Service_Audio, "called. Session {} released {} buffers",
139 impl->GetSystem().GetSessionId(), count);
140
141 IPC::ResponseBuilder rb{ctx, 3};
142 rb.Push(ResultSuccess);
143 rb.Push(count);
144 }
145
146 void ContainsAudioOutBuffer(HLERequestContext& ctx) {
147 IPC::RequestParser rp{ctx};
148
149 const u64 tag{rp.Pop<u64>()};
150 const auto buffer_queued{impl->ContainsAudioBuffer(tag)};
151
152 LOG_DEBUG(Service_Audio, "called. Is buffer {:08X} registered? {}", tag, buffer_queued);
153
154 IPC::ResponseBuilder rb{ctx, 3};
155 rb.Push(ResultSuccess);
156 rb.Push(buffer_queued);
157 }
158
159 void GetAudioOutBufferCount(HLERequestContext& ctx) {
160 const auto buffer_count = impl->GetBufferCount();
161
162 LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
163
164 IPC::ResponseBuilder rb{ctx, 3};
165 rb.Push(ResultSuccess);
166 rb.Push(buffer_count);
167 }
168
169 void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
170 const auto samples_played = impl->GetPlayedSampleCount();
171
172 LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
173
174 IPC::ResponseBuilder rb{ctx, 4};
175 rb.Push(ResultSuccess);
176 rb.Push(samples_played);
177 }
178
179 void FlushAudioOutBuffers(HLERequestContext& ctx) {
180 bool flushed{impl->FlushAudioOutBuffers()};
181
182 LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
183
184 IPC::ResponseBuilder rb{ctx, 3};
185 rb.Push(ResultSuccess);
186 rb.Push(flushed);
187 }
188
189 void SetAudioOutVolume(HLERequestContext& ctx) {
190 IPC::RequestParser rp{ctx};
191 const auto volume = rp.Pop<f32>();
192
193 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
194
195 impl->SetVolume(volume);
196
197 IPC::ResponseBuilder rb{ctx, 2};
198 rb.Push(ResultSuccess);
199 }
200
201 void GetAudioOutVolume(HLERequestContext& ctx) {
202 const auto volume = impl->GetVolume();
203
204 LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
205
206 IPC::ResponseBuilder rb{ctx, 3};
207 rb.Push(ResultSuccess);
208 rb.Push(volume);
209 }
210
211 KernelHelpers::ServiceContext service_context;
212 Kernel::KEvent* event;
213 Kernel::KProcess* process;
214 std::shared_ptr<AudioCore::AudioOut::Out> impl;
215 Common::ScratchBuffer<u64> released_buffer;
216};
217
218AudOutU::AudOutU(Core::System& system_)
219 : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
220 impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
221 // clang-format off
222 static const FunctionInfo functions[] = {
223 {0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
224 {1, &AudOutU::OpenAudioOut, "OpenAudioOut"},
225 {2, &AudOutU::ListAudioOuts, "ListAudioOutsAuto"},
226 {3, &AudOutU::OpenAudioOut, "OpenAudioOutAuto"},
227 };
228 // clang-format on
229
230 RegisterHandlers(functions);
231}
232
233AudOutU::~AudOutU() = default;
234
235void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
236 using namespace AudioCore::Renderer;
237
238 std::scoped_lock l{impl->mutex};
239
240 const auto write_count =
241 static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
242 std::vector<AudioDevice::AudioDeviceName> device_names{};
243 if (write_count > 0) {
244 device_names.emplace_back("DeviceOut");
245 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
246 } else {
247 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
248 }
249
250 ctx.WriteBuffer(device_names);
251
252 IPC::ResponseBuilder rb{ctx, 3};
253 rb.Push(ResultSuccess);
254 rb.Push<u32>(static_cast<u32>(device_names.size()));
255}
256
257void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
258 IPC::RequestParser rp{ctx};
259 auto in_params{rp.PopRaw<AudioOutParameter>()};
260 auto applet_resource_user_id{rp.PopRaw<u64>()};
261 const auto device_name_data{ctx.ReadBuffer()};
262 auto device_name = Common::StringFromBuffer(device_name_data);
263 auto handle{ctx.GetCopyHandle(0)};
264
265 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)};
266 if (process.IsNull()) {
267 LOG_ERROR(Service_Audio, "Failed to get process handle");
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(ResultUnknown);
270 return;
271 }
272
273 auto link{impl->LinkToManager()};
274 if (link.IsError()) {
275 LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager");
276 IPC::ResponseBuilder rb{ctx, 2};
277 rb.Push(link);
278 return;
279 }
280
281 size_t new_session_id{};
282 auto result{impl->AcquireSessionId(new_session_id)};
283 if (result.IsError()) {
284 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(result);
286 return;
287 }
288
289 LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id,
290 impl->num_free_sessions);
291
292 auto audio_out =
293 std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params,
294 process.GetPointerUnsafe(), applet_resource_user_id);
295 result = audio_out->GetImpl()->GetSystem().Initialize(
296 device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id);
297 if (result.IsError()) {
298 LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
299 IPC::ResponseBuilder rb{ctx, 2};
300 rb.Push(result);
301 return;
302 }
303
304 impl->sessions[new_session_id] = audio_out->GetImpl();
305 impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
306
307 auto& out_system = impl->sessions[new_session_id]->GetSystem();
308 AudioOutParameterInternal out_params{.sample_rate = out_system.GetSampleRate(),
309 .channel_count = out_system.GetChannelCount(),
310 .sample_format =
311 static_cast<u32>(out_system.GetSampleFormat()),
312 .state = static_cast<u32>(out_system.GetState())};
313
314 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
315
316 ctx.WriteBuffer(out_system.GetName());
317
318 rb.Push(ResultSuccess);
319 rb.PushRaw<AudioOutParameterInternal>(out_params);
320 rb.PushIpcInterface<IAudioOut>(audio_out);
321}
322
323} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
deleted file mode 100644
index 8f288c6e0..000000000
--- a/src/core/hle/service/audio/audout_u.h
+++ /dev/null
@@ -1,37 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_out_manager.h"
7#include "audio_core/out/audio_out.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace AudioCore::AudioOut {
16class Manager;
17class Out;
18} // namespace AudioCore::AudioOut
19
20namespace Service::Audio {
21
22class IAudioOut;
23
24class AudOutU final : public ServiceFramework<AudOutU> {
25public:
26 explicit AudOutU(Core::System& system_);
27 ~AudOutU() override;
28
29private:
30 void ListAudioOuts(HLERequestContext& ctx);
31 void OpenAudioOut(HLERequestContext& ctx);
32
33 KernelHelpers::ServiceContext service_context;
34 std::unique_ptr<AudioCore::AudioOut::Manager> impl;
35};
36
37} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
deleted file mode 100644
index 10108abc0..000000000
--- a/src/core/hle/service/audio/audren_u.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <array>
5#include <memory>
6
7#include "audio_core/audio_core.h"
8#include "audio_core/common/audio_renderer_parameter.h"
9#include "audio_core/common/feature_support.h"
10#include "audio_core/renderer/audio_device.h"
11#include "audio_core/renderer/audio_renderer.h"
12#include "audio_core/renderer/voice/voice_info.h"
13#include "common/alignment.h"
14#include "common/bit_util.h"
15#include "common/common_funcs.h"
16#include "common/logging/log.h"
17#include "common/polyfill_ranges.h"
18#include "common/scratch_buffer.h"
19#include "common/string_util.h"
20#include "core/core.h"
21#include "core/hle/kernel/k_event.h"
22#include "core/hle/kernel/k_process.h"
23#include "core/hle/kernel/k_transfer_memory.h"
24#include "core/hle/service/audio/audren_u.h"
25#include "core/hle/service/audio/errors.h"
26#include "core/hle/service/ipc_helpers.h"
27#include "core/memory.h"
28
29using namespace AudioCore::Renderer;
30
31namespace Service::Audio {
32
33class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
34public:
35 explicit IAudioRenderer(Core::System& system_, Manager& manager_,
36 AudioCore::AudioRendererParameterInternal& params,
37 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
38 u32 process_handle, Kernel::KProcess& process_,
39 u64 applet_resource_user_id, s32 session_id)
40 : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
41 rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
42 impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} {
43 // clang-format off
44 static const FunctionInfo functions[] = {
45 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
46 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
47 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
48 {3, &IAudioRenderer::GetState, "GetState"},
49 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
50 {5, &IAudioRenderer::Start, "Start"},
51 {6, &IAudioRenderer::Stop, "Stop"},
52 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
53 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
54 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
55 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
56 {11, nullptr, "ExecuteAudioRendererRendering"},
57 {12, &IAudioRenderer::SetVoiceDropParameter, "SetVoiceDropParameter"},
58 {13, &IAudioRenderer::GetVoiceDropParameter, "GetVoiceDropParameter"},
59 };
60 // clang-format on
61 RegisterHandlers(functions);
62
63 process.Open();
64 impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process,
65 applet_resource_user_id, session_id);
66 }
67
68 ~IAudioRenderer() override {
69 impl->Finalize();
70 service_context.CloseEvent(rendered_event);
71 process.Close();
72 }
73
74private:
75 void GetSampleRate(HLERequestContext& ctx) {
76 const auto sample_rate{impl->GetSystem().GetSampleRate()};
77
78 LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(ResultSuccess);
82 rb.Push(sample_rate);
83 }
84
85 void GetSampleCount(HLERequestContext& ctx) {
86 const auto sample_count{impl->GetSystem().GetSampleCount()};
87
88 LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
89
90 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(ResultSuccess);
92 rb.Push(sample_count);
93 }
94
95 void GetState(HLERequestContext& ctx) {
96 const u32 state{!impl->GetSystem().IsActive()};
97
98 LOG_DEBUG(Service_Audio, "called, state {}", state);
99
100 IPC::ResponseBuilder rb{ctx, 3};
101 rb.Push(ResultSuccess);
102 rb.Push(state);
103 }
104
105 void GetMixBufferCount(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Audio, "called");
107
108 const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
109
110 IPC::ResponseBuilder rb{ctx, 3};
111 rb.Push(ResultSuccess);
112 rb.Push(buffer_count);
113 }
114
115 void RequestUpdate(HLERequestContext& ctx) {
116 LOG_TRACE(Service_Audio, "called");
117
118 const auto input{ctx.ReadBuffer(0)};
119
120 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
121 // checking size 0. Performance size is 0 for most games.
122
123 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
124 if (is_buffer_b) {
125 const auto buffersB{ctx.BufferDescriptorB()};
126 output_buffer.resize_destructive(buffersB[0].Size());
127 performance_buffer.resize_destructive(buffersB[1].Size());
128 } else {
129 const auto buffersC{ctx.BufferDescriptorC()};
130 output_buffer.resize_destructive(buffersC[0].Size());
131 performance_buffer.resize_destructive(buffersC[1].Size());
132 }
133
134 auto result = impl->RequestUpdate(input, performance_buffer, output_buffer);
135
136 if (result.IsSuccess()) {
137 if (is_buffer_b) {
138 ctx.WriteBufferB(output_buffer.data(), output_buffer.size(), 0);
139 ctx.WriteBufferB(performance_buffer.data(), performance_buffer.size(), 1);
140 } else {
141 ctx.WriteBufferC(output_buffer.data(), output_buffer.size(), 0);
142 ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1);
143 }
144 } else {
145 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!",
146 result.GetDescription());
147 }
148
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(result);
151 }
152
153 void Start(HLERequestContext& ctx) {
154 LOG_DEBUG(Service_Audio, "called");
155
156 impl->Start();
157
158 IPC::ResponseBuilder rb{ctx, 2};
159 rb.Push(ResultSuccess);
160 }
161
162 void Stop(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called");
164
165 impl->Stop();
166
167 IPC::ResponseBuilder rb{ctx, 2};
168 rb.Push(ResultSuccess);
169 }
170
171 void QuerySystemEvent(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called");
173
174 if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
175 IPC::ResponseBuilder rb{ctx, 2};
176 rb.Push(Audio::ResultNotSupported);
177 return;
178 }
179
180 IPC::ResponseBuilder rb{ctx, 2, 1};
181 rb.Push(ResultSuccess);
182 rb.PushCopyObjects(rendered_event->GetReadableEvent());
183 }
184
185 void SetRenderingTimeLimit(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Audio, "called");
187
188 IPC::RequestParser rp{ctx};
189 auto limit = rp.PopRaw<u32>();
190
191 auto& system_ = impl->GetSystem();
192 system_.SetRenderingTimeLimit(limit);
193
194 IPC::ResponseBuilder rb{ctx, 2};
195 rb.Push(ResultSuccess);
196 }
197
198 void GetRenderingTimeLimit(HLERequestContext& ctx) {
199 LOG_DEBUG(Service_Audio, "called");
200
201 auto& system_ = impl->GetSystem();
202 auto time = system_.GetRenderingTimeLimit();
203
204 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess);
206 rb.Push(time);
207 }
208
209 void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Audio, "called");
211 }
212
213 void SetVoiceDropParameter(HLERequestContext& ctx) {
214 LOG_DEBUG(Service_Audio, "called");
215
216 IPC::RequestParser rp{ctx};
217 auto voice_drop_param{rp.Pop<f32>()};
218
219 auto& system_ = impl->GetSystem();
220 system_.SetVoiceDropParameter(voice_drop_param);
221
222 IPC::ResponseBuilder rb{ctx, 2};
223 rb.Push(ResultSuccess);
224 }
225
226 void GetVoiceDropParameter(HLERequestContext& ctx) {
227 LOG_DEBUG(Service_Audio, "called");
228
229 auto& system_ = impl->GetSystem();
230 auto voice_drop_param{system_.GetVoiceDropParameter()};
231
232 IPC::ResponseBuilder rb{ctx, 3};
233 rb.Push(ResultSuccess);
234 rb.Push(voice_drop_param);
235 }
236
237 KernelHelpers::ServiceContext service_context;
238 Kernel::KEvent* rendered_event;
239 Manager& manager;
240 std::unique_ptr<Renderer> impl;
241 Kernel::KProcess& process;
242 Common::ScratchBuffer<u8> output_buffer;
243 Common::ScratchBuffer<u8> performance_buffer;
244};
245
246class IAudioDevice final : public ServiceFramework<IAudioDevice> {
247
248public:
249 explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
250 u32 device_num)
251 : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
252 impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
253 event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
254 static const FunctionInfo functions[] = {
255 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
256 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
257 {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
258 {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
259 {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
260 {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
261 {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
262 {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
263 {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
264 {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
265 {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
266 {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
267 {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
268 {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
269 };
270 RegisterHandlers(functions);
271
272 event->Signal();
273 }
274
275 ~IAudioDevice() override {
276 service_context.CloseEvent(event);
277 }
278
279private:
280 void ListAudioDeviceName(HLERequestContext& ctx) {
281 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
282
283 std::vector<AudioDevice::AudioDeviceName> out_names{};
284
285 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
286
287 std::string out{};
288 for (u32 i = 0; i < out_count; i++) {
289 std::string a{};
290 u32 j = 0;
291 while (out_names[i].name[j] != '\0') {
292 a += out_names[i].name[j];
293 j++;
294 }
295 out += "\n\t" + a;
296 }
297
298 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
299
300 IPC::ResponseBuilder rb{ctx, 3};
301
302 ctx.WriteBuffer(out_names);
303
304 rb.Push(ResultSuccess);
305 rb.Push(out_count);
306 }
307
308 void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx};
310 const f32 volume = rp.Pop<f32>();
311
312 const auto device_name_buffer = ctx.ReadBuffer();
313 const std::string name = Common::StringFromBuffer(device_name_buffer);
314
315 LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);
316
317 if (name == "AudioTvOutput") {
318 impl->SetDeviceVolumes(volume);
319 }
320
321 IPC::ResponseBuilder rb{ctx, 2};
322 rb.Push(ResultSuccess);
323 }
324
325 void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
326 const auto device_name_buffer = ctx.ReadBuffer();
327 const std::string name = Common::StringFromBuffer(device_name_buffer);
328
329 LOG_DEBUG(Service_Audio, "called. Name={}", name);
330
331 f32 volume{1.0f};
332 if (name == "AudioTvOutput") {
333 volume = impl->GetDeviceVolume(name);
334 }
335
336 IPC::ResponseBuilder rb{ctx, 3};
337 rb.Push(ResultSuccess);
338 rb.Push(volume);
339 }
340
341 void GetActiveAudioDeviceName(HLERequestContext& ctx) {
342 const auto write_size = ctx.GetWriteBufferSize();
343 std::string out_name{"AudioTvOutput"};
344
345 LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
346
347 out_name.resize(write_size);
348
349 ctx.WriteBuffer(out_name);
350
351 IPC::ResponseBuilder rb{ctx, 2};
352 rb.Push(ResultSuccess);
353 }
354
355 void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
356 LOG_DEBUG(Service_Audio, "(STUBBED) called");
357
358 event->Signal();
359
360 IPC::ResponseBuilder rb{ctx, 2, 1};
361 rb.Push(ResultSuccess);
362 rb.PushCopyObjects(event->GetReadableEvent());
363 }
364
365 void GetActiveChannelCount(HLERequestContext& ctx) {
366 const auto& sink{system.AudioCore().GetOutputSink()};
367 u32 channel_count{sink.GetSystemChannels()};
368
369 LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);
370
371 IPC::ResponseBuilder rb{ctx, 3};
372
373 rb.Push(ResultSuccess);
374 rb.Push<u32>(channel_count);
375 }
376
377 void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
378 LOG_DEBUG(Service_Audio, "(STUBBED) called");
379
380 IPC::ResponseBuilder rb{ctx, 2, 1};
381 rb.Push(ResultSuccess);
382 rb.PushCopyObjects(event->GetReadableEvent());
383 }
384
385 void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
386 LOG_DEBUG(Service_Audio, "called");
387
388 IPC::ResponseBuilder rb{ctx, 2, 1};
389 rb.Push(ResultSuccess);
390 rb.PushCopyObjects(event->GetReadableEvent());
391 }
392
393 void ListAudioOutputDeviceName(HLERequestContext& ctx) {
394 const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
395
396 std::vector<AudioDevice::AudioDeviceName> out_names{};
397
398 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
399
400 std::string out{};
401 for (u32 i = 0; i < out_count; i++) {
402 std::string a{};
403 u32 j = 0;
404 while (out_names[i].name[j] != '\0') {
405 a += out_names[i].name[j];
406 j++;
407 }
408 out += "\n\t" + a;
409 }
410
411 LOG_DEBUG(Service_Audio, "called.\nNames={}", out);
412
413 IPC::ResponseBuilder rb{ctx, 3};
414
415 ctx.WriteBuffer(out_names);
416
417 rb.Push(ResultSuccess);
418 rb.Push(out_count);
419 }
420
421 KernelHelpers::ServiceContext service_context;
422 std::unique_ptr<AudioDevice> impl;
423 Kernel::KEvent* event;
424};
425
426AudRenU::AudRenU(Core::System& system_)
427 : ServiceFramework{system_, "audren:u"},
428 service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
429 // clang-format off
430 static const FunctionInfo functions[] = {
431 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
432 {1, &AudRenU::GetWorkBufferSize, "GetWorkBufferSize"},
433 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
434 {3, nullptr, "OpenAudioRendererForManualExecution"},
435 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
436 };
437 // clang-format on
438
439 RegisterHandlers(functions);
440}
441
442AudRenU::~AudRenU() = default;
443
444void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx};
446
447 AudioCore::AudioRendererParameterInternal params;
448 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
449 rp.Skip(1, false);
450 auto transfer_memory_size = rp.Pop<u64>();
451 auto applet_resource_user_id = rp.Pop<u64>();
452 auto transfer_memory_handle = ctx.GetCopyHandle(0);
453 auto process_handle = ctx.GetCopyHandle(1);
454
455 if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
456 LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
457 IPC::ResponseBuilder rb{ctx, 2};
458 rb.Push(Audio::ResultOutOfSessions);
459 return;
460 }
461
462 auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()};
463 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
464
465 const auto session_id{impl->GetSessionId()};
466 if (session_id == -1) {
467 LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
468 IPC::ResponseBuilder rb{ctx, 2};
469 rb.Push(Audio::ResultOutOfSessions);
470 return;
471 }
472
473 LOG_DEBUG(Service_Audio, "Opened new AudioRenderer session {} sessions open {}", session_id,
474 impl->GetSessionCount());
475
476 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
477 rb.Push(ResultSuccess);
478 rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(),
479 transfer_memory_size, process_handle, *process,
480 applet_resource_user_id, session_id);
481}
482
483void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
484 AudioCore::AudioRendererParameterInternal params;
485
486 IPC::RequestParser rp{ctx};
487 rp.PopRaw<AudioCore::AudioRendererParameterInternal>(params);
488
489 u64 size{0};
490 auto result = impl->GetWorkBufferSize(params, size);
491
492 std::string output_info{};
493 output_info += fmt::format("\tRevision {}", AudioCore::GetRevisionNum(params.revision));
494 output_info +=
495 fmt::format("\n\tSample Rate {}, Sample Count {}", params.sample_rate, params.sample_count);
496 output_info += fmt::format("\n\tExecution Mode {}, Voice Drop Enabled {}",
497 static_cast<u32>(params.execution_mode), params.voice_drop_enabled);
498 output_info += fmt::format(
499 "\n\tSizes: Effects {:04X}, Mixes {:04X}, Sinks {:04X}, Submixes {:04X}, Splitter Infos "
500 "{:04X}, Splitter Destinations {:04X}, Voices {:04X}, Performance Frames {:04X} External "
501 "Context {:04X}",
502 params.effects, params.mixes, params.sinks, params.sub_mixes, params.splitter_infos,
503 params.splitter_destinations, params.voices, params.perf_frames,
504 params.external_context_size);
505
506 LOG_DEBUG(Service_Audio, "called.\nInput params:\n{}\nOutput params:\n\tWorkbuffer size {:08X}",
507 output_info, size);
508
509 IPC::ResponseBuilder rb{ctx, 4};
510 rb.Push(result);
511 rb.Push<u64>(size);
512}
513
514void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
515 IPC::RequestParser rp{ctx};
516
517 const auto applet_resource_user_id = rp.Pop<u64>();
518
519 LOG_DEBUG(Service_Audio, "called. Applet resource id {}", applet_resource_user_id);
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522
523 rb.Push(ResultSuccess);
524 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id,
525 ::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
526}
527
528void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
529 LOG_ERROR(Service_Audio, "called. Implement me!");
530}
531
532void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
533 struct Parameters {
534 u32 revision;
535 u64 applet_resource_user_id;
536 };
537
538 IPC::RequestParser rp{ctx};
539
540 const auto [revision, applet_resource_user_id] = rp.PopRaw<Parameters>();
541
542 LOG_DEBUG(Service_Audio, "called. Revision {} Applet resource id {}",
543 AudioCore::GetRevisionNum(revision), applet_resource_user_id);
544
545 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
546
547 rb.Push(ResultSuccess);
548 rb.PushIpcInterface<IAudioDevice>(system, applet_resource_user_id, revision,
549 num_audio_devices++);
550}
551
552} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
deleted file mode 100644
index 3d7993a16..000000000
--- a/src/core/hle/service/audio/audren_u.h
+++ /dev/null
@@ -1,35 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/audio_render_manager.h"
7#include "common/scratch_buffer.h"
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::Audio {
16class IAudioRenderer;
17
18class AudRenU final : public ServiceFramework<AudRenU> {
19public:
20 explicit AudRenU(Core::System& system_);
21 ~AudRenU() override;
22
23private:
24 void OpenAudioRenderer(HLERequestContext& ctx);
25 void GetWorkBufferSize(HLERequestContext& ctx);
26 void GetAudioDeviceService(HLERequestContext& ctx);
27 void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
28 void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
29
30 KernelHelpers::ServiceContext service_context;
31 std::unique_ptr<AudioCore::Renderer::Manager> impl;
32 u32 num_audio_devices{0};
33};
34
35} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/final_output_recorder_manager.cpp
index bc55cec17..f70a0e62d 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager.cpp
@@ -1,7 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_u.h" 4#include "core/hle/service/audio/final_output_recorder_manager.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
@@ -30,13 +30,14 @@ public:
30 } 30 }
31}; 31};
32 32
33AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} { 33IFinalOutputRecorderManager::IFinalOutputRecorderManager(Core::System& system_)
34 : ServiceFramework{system_, "audrec:u"} {
34 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
35 {0, nullptr, "OpenFinalOutputRecorder"}, 36 {0, nullptr, "OpenFinalOutputRecorder"},
36 }; 37 };
37 RegisterHandlers(functions); 38 RegisterHandlers(functions);
38} 39}
39 40
40AudRecU::~AudRecU() = default; 41IFinalOutputRecorderManager::~IFinalOutputRecorderManager() = default;
41 42
42} // namespace Service::Audio 43} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/final_output_recorder_manager.h
index 9edf89f6c..0663b894e 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager.h
@@ -11,10 +11,10 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecA final : public ServiceFramework<AudRecA> { 14class IFinalOutputRecorderManager final : public ServiceFramework<IFinalOutputRecorderManager> {
15public: 15public:
16 explicit AudRecA(Core::System& system_); 16 explicit IFinalOutputRecorderManager(Core::System& system_);
17 ~AudRecA() override; 17 ~IFinalOutputRecorderManager() override;
18}; 18};
19 19
20} // namespace Service::Audio 20} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
index fa82e9ac7..7e2e42bbe 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.cpp
@@ -1,11 +1,12 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/audio/audrec_a.h" 4#include "core/hle/service/audio/final_output_recorder_manager_for_applet.h"
5 5
6namespace Service::Audio { 6namespace Service::Audio {
7 7
8AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} { 8IFinalOutputRecorderManagerForApplet::IFinalOutputRecorderManagerForApplet(Core::System& system_)
9 : ServiceFramework{system_, "audrec:a"} {
9 // clang-format off 10 // clang-format off
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, nullptr, "RequestSuspend"}, 12 {0, nullptr, "RequestSuspend"},
@@ -16,6 +17,6 @@ AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"}
16 RegisterHandlers(functions); 17 RegisterHandlers(functions);
17} 18}
18 19
19AudRecA::~AudRecA() = default; 20IFinalOutputRecorderManagerForApplet::~IFinalOutputRecorderManagerForApplet() = default;
20 21
21} // namespace Service::Audio 22} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
index 8b4817884..27940f7e0 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/final_output_recorder_manager_for_applet.h
@@ -11,10 +11,11 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14class AudRecU final : public ServiceFramework<AudRecU> { 14class IFinalOutputRecorderManagerForApplet final
15 : public ServiceFramework<IFinalOutputRecorderManagerForApplet> {
15public: 16public:
16 explicit AudRecU(Core::System& system_); 17 explicit IFinalOutputRecorderManagerForApplet(Core::System& system_);
17 ~AudRecU() override; 18 ~IFinalOutputRecorderManagerForApplet() override;
18}; 19};
19 20
20} // namespace Service::Audio 21} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.cpp b/src/core/hle/service/audio/hardware_opus_decoder.cpp
new file mode 100644
index 000000000..03d3374c1
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.cpp
@@ -0,0 +1,145 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/cmif_serialization.h"
6
7namespace Service::Audio {
8
9using namespace AudioCore::OpusDecoder;
10
11IHardwareOpusDecoder::IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
12 : ServiceFramework{system_, "IHardwareOpusDecoder"},
13 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoder::DecodeInterleavedOld>, "DecodeInterleavedOld"},
17 {1, D<&IHardwareOpusDecoder::SetContext>, "SetContext"},
18 {2, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld>, "DecodeInterleavedForMultiStreamOld"},
19 {3, D<&IHardwareOpusDecoder::SetContextForMultiStream>, "SetContextForMultiStream"},
20 {4, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfOld>, "DecodeInterleavedWithPerfOld"},
21 {5, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld>, "DecodeInterleavedForMultiStreamWithPerfOld"},
22 {6, D<&IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld>, "DecodeInterleavedWithPerfAndResetOld"},
23 {7, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld>, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
24 {8, D<&IHardwareOpusDecoder::DecodeInterleaved>, "DecodeInterleaved"},
25 {9, D<&IHardwareOpusDecoder::DecodeInterleavedForMultiStream>, "DecodeInterleavedForMultiStream"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IHardwareOpusDecoder::~IHardwareOpusDecoder() = default;
33
34Result IHardwareOpusDecoder::Initialize(const OpusParametersEx& params,
35 Kernel::KTransferMemory* transfer_memory,
36 u64 transfer_memory_size) {
37 return impl->Initialize(params, transfer_memory, transfer_memory_size);
38}
39
40Result IHardwareOpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
41 Kernel::KTransferMemory* transfer_memory,
42 u64 transfer_memory_size) {
43 return impl->Initialize(params, transfer_memory, transfer_memory_size);
44}
45
46Result IHardwareOpusDecoder::DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
47 Out<u32> out_data_size, Out<u32> out_sample_count,
48 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
49 R_TRY(impl->DecodeInterleaved(out_data_size, nullptr, out_sample_count, opus_data, out_pcm_data,
50 false));
51 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
52 *out_sample_count);
53 R_SUCCEED();
54}
55
56Result IHardwareOpusDecoder::SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
57 LOG_DEBUG(Service_Audio, "called");
58 R_RETURN(impl->SetContext(decoder_context));
59}
60
61Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld(
62 OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data, Out<u32> out_data_size,
63 Out<u32> out_sample_count, InBuffer<BufferAttr_HipcMapAlias> opus_data) {
64 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, nullptr, out_sample_count, opus_data,
65 out_pcm_data, false));
66 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {}", *out_data_size,
67 *out_sample_count);
68 R_SUCCEED();
69}
70
71Result IHardwareOpusDecoder::SetContextForMultiStream(
72 InBuffer<BufferAttr_HipcMapAlias> decoder_context) {
73 LOG_DEBUG(Service_Audio, "called");
74 R_RETURN(impl->SetContext(decoder_context));
75}
76
77Result IHardwareOpusDecoder::DecodeInterleavedWithPerfOld(
78 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
79 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
80 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
81 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
82 out_pcm_data, false));
83 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
84 *out_sample_count, *out_time_taken);
85 R_SUCCEED();
86}
87
88Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld(
89 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
90 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
91 InBuffer<BufferAttr_HipcMapAlias> opus_data) {
92 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
93 opus_data, out_pcm_data, false));
94 LOG_DEBUG(Service_Audio, "bytes read {:#x} samples generated {} time taken {}", *out_data_size,
95 *out_sample_count, *out_time_taken);
96 R_SUCCEED();
97}
98
99Result IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld(
100 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
101 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
102 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
103 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
104 out_pcm_data, reset));
105 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
106 *out_data_size, *out_sample_count, *out_time_taken);
107 R_SUCCEED();
108}
109
110Result IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld(
111 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
112 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
113 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset) {
114 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
115 opus_data, out_pcm_data, reset));
116 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
117 *out_data_size, *out_sample_count, *out_time_taken);
118 R_SUCCEED();
119}
120
121Result IHardwareOpusDecoder::DecodeInterleaved(
122 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
123 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
124 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
125 bool reset) {
126 R_TRY(impl->DecodeInterleaved(out_data_size, out_time_taken, out_sample_count, opus_data,
127 out_pcm_data, reset));
128 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
129 *out_data_size, *out_sample_count, *out_time_taken);
130 R_SUCCEED();
131}
132
133Result IHardwareOpusDecoder::DecodeInterleavedForMultiStream(
134 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
135 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
136 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
137 bool reset) {
138 R_TRY(impl->DecodeInterleavedForMultiStream(out_data_size, out_time_taken, out_sample_count,
139 opus_data, out_pcm_data, reset));
140 LOG_DEBUG(Service_Audio, "reset {} bytes read {:#x} samples generated {} time taken {}", reset,
141 *out_data_size, *out_sample_count, *out_time_taken);
142 R_SUCCEED();
143}
144
145} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder.h b/src/core/hle/service/audio/hardware_opus_decoder.h
new file mode 100644
index 000000000..511bf46bd
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder.h
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
13public:
14 explicit IHardwareOpusDecoder(Core::System& system_,
15 AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
16 ~IHardwareOpusDecoder() override;
17
18 Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
19 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
20 Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
21 Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
22
23private:
24 Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
25 Out<u32> out_data_size, Out<u32> out_sample_count,
26 InBuffer<BufferAttr_HipcMapAlias> opus_data);
27 Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
28 Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
29 Out<u32> out_data_size, Out<u32> out_sample_count,
30 InBuffer<BufferAttr_HipcMapAlias> opus_data);
31 Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
32 Result DecodeInterleavedWithPerfOld(
33 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
34 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
35 InBuffer<BufferAttr_HipcMapAlias> opus_data);
36 Result DecodeInterleavedForMultiStreamWithPerfOld(
37 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
38 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
39 InBuffer<BufferAttr_HipcMapAlias> opus_data);
40 Result DecodeInterleavedWithPerfAndResetOld(
41 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
42 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
43 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
44 Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
45 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
46 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
47 InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
48 Result DecodeInterleaved(
49 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
50 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
51 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
52 bool reset);
53 Result DecodeInterleavedForMultiStream(
54 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
55 Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
56 InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
57 bool reset);
58
59 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
60 Common::ScratchBuffer<u8> output_data;
61};
62
63} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
new file mode 100644
index 000000000..9de72e30f
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.cpp
@@ -0,0 +1,156 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/audio/hardware_opus_decoder.h"
5#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
6#include "core/hle/service/cmif_serialization.h"
7
8namespace Service::Audio {
9
10using namespace AudioCore::OpusDecoder;
11
12IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
13 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
17 {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
18 {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
19 {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
20 {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
21 {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
22 {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
23 {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
24 {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
25 {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
26 };
27 // clang-format on
28 RegisterHandlers(functions);
29}
30
31IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;
32
33Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
34 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
35 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
36 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
37 params.sample_rate, params.channel_count, tmem_size);
38
39 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
40 OpusParametersEx ex{
41 .sample_rate = params.sample_rate,
42 .channel_count = params.channel_count,
43 .use_large_frame_size = false,
44 };
45 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
46
47 *out_decoder = decoder;
48 R_SUCCEED();
49}
50
51Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
52 R_TRY(impl.GetWorkBufferSize(params, *out_size));
53 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
54 params.sample_rate, params.channel_count, *out_size);
55 R_SUCCEED();
56}
57
58Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
59 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
60 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
61 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
62 LOG_DEBUG(Service_Audio,
63 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
64 "transfer_memory_size {:#x}",
65 params->sample_rate, params->channel_count, params->total_stream_count,
66 params->stereo_stream_count, tmem_size);
67
68 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
69
70 OpusMultiStreamParametersEx ex{
71 .sample_rate = params->sample_rate,
72 .channel_count = params->channel_count,
73 .total_stream_count = params->total_stream_count,
74 .stereo_stream_count = params->stereo_stream_count,
75 .use_large_frame_size = false,
76 .mappings{},
77 };
78 std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
79 R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));
80
81 *out_decoder = decoder;
82 R_SUCCEED();
83}
84
85Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
86 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
87 R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
88 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
89 R_SUCCEED();
90}
91
92Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
93 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
94 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
95 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
96 params.sample_rate, params.channel_count, tmem_size);
97
98 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
99 R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));
100
101 *out_decoder = decoder;
102 R_SUCCEED();
103}
104
105Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
106 OpusParametersEx params) {
107 R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
108 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
109 R_SUCCEED();
110}
111
112Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
113 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
114 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
115 InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
116 LOG_DEBUG(Service_Audio,
117 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
118 "use_large_frame_size {}"
119 "transfer_memory_size {:#x}",
120 params->sample_rate, params->channel_count, params->total_stream_count,
121 params->stereo_stream_count, params->use_large_frame_size, tmem_size);
122
123 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
124
125 R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));
126
127 *out_decoder = decoder;
128 R_SUCCEED();
129}
130
131Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
132 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
133 R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
134 LOG_DEBUG(Service_Audio,
135 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
136 "use_large_frame_size {} -- returned size {:#x}",
137 params->sample_rate, params->channel_count, params->total_stream_count,
138 params->stereo_stream_count, params->use_large_frame_size, *out_size);
139 R_SUCCEED();
140}
141
142Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
143 OpusParametersEx params) {
144 R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
145 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
146 R_SUCCEED();
147}
148
149Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
150 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
151 R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
152 LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
153 R_SUCCEED();
154}
155
156} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hardware_opus_decoder_manager.h b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
new file mode 100644
index 000000000..4f869c517
--- /dev/null
+++ b/src/core/hle/service/audio/hardware_opus_decoder_manager.h
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::Audio {
11
12class IHardwareOpusDecoder;
13
14using AudioCore::OpusDecoder::OpusMultiStreamParameters;
15using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
16using AudioCore::OpusDecoder::OpusParameters;
17using AudioCore::OpusDecoder::OpusParametersEx;
18
19class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
20public:
21 explicit IHardwareOpusDecoderManager(Core::System& system_);
22 ~IHardwareOpusDecoderManager() override;
23
24private:
25 Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
26 OpusParameters params, u32 tmem_size,
27 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
28 Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
29 Result OpenHardwareOpusDecoderForMultiStream(
30 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
31 InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
32 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
33 Result GetWorkBufferSizeForMultiStream(
34 Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
35 Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
36 OpusParametersEx params, u32 tmem_size,
37 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
38 Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
39 Result OpenHardwareOpusDecoderForMultiStreamEx(
40 Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
41 InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
42 InCopyHandle<Kernel::KTransferMemory> tmem_handle);
43 Result GetWorkBufferSizeForMultiStreamEx(
44 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
45 Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
46 Result GetWorkBufferSizeForMultiStreamExEx(
47 Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
48
49 Core::System& system;
50 AudioCore::OpusDecoder::OpusDecoderManager impl;
51};
52
53} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
deleted file mode 100644
index 91f33aabd..000000000
--- a/src/core/hle/service/audio/hwopus.cpp
+++ /dev/null
@@ -1,502 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5#include <vector>
6
7#include "audio_core/opus/decoder.h"
8#include "audio_core/opus/parameters.h"
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/scratch_buffer.h"
12#include "core/core.h"
13#include "core/hle/service/audio/hwopus.h"
14#include "core/hle/service/ipc_helpers.h"
15
16namespace Service::Audio {
17using namespace AudioCore::OpusDecoder;
18
19class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
20public:
21 explicit IHardwareOpusDecoder(Core::System& system_, HardwareOpus& hardware_opus)
22 : ServiceFramework{system_, "IHardwareOpusDecoder"},
23 impl{std::make_unique<AudioCore::OpusDecoder::OpusDecoder>(system_, hardware_opus)} {
24 // clang-format off
25 static const FunctionInfo functions[] = {
26 {0, &IHardwareOpusDecoder::DecodeInterleavedOld, "DecodeInterleavedOld"},
27 {1, &IHardwareOpusDecoder::SetContext, "SetContext"},
28 {2, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamOld, "DecodeInterleavedForMultiStreamOld"},
29 {3, &IHardwareOpusDecoder::SetContextForMultiStream, "SetContextForMultiStream"},
30 {4, &IHardwareOpusDecoder::DecodeInterleavedWithPerfOld, "DecodeInterleavedWithPerfOld"},
31 {5, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfOld, "DecodeInterleavedForMultiStreamWithPerfOld"},
32 {6, &IHardwareOpusDecoder::DecodeInterleavedWithPerfAndResetOld, "DecodeInterleavedWithPerfAndResetOld"},
33 {7, &IHardwareOpusDecoder::DecodeInterleavedForMultiStreamWithPerfAndResetOld, "DecodeInterleavedForMultiStreamWithPerfAndResetOld"},
34 {8, &IHardwareOpusDecoder::DecodeInterleaved, "DecodeInterleaved"},
35 {9, &IHardwareOpusDecoder::DecodeInterleavedForMultiStream, "DecodeInterleavedForMultiStream"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40 }
41
42 Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
43 u64 transfer_memory_size) {
44 return impl->Initialize(params, transfer_memory, transfer_memory_size);
45 }
46
47 Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
48 u64 transfer_memory_size) {
49 return impl->Initialize(params, transfer_memory, transfer_memory_size);
50 }
51
52private:
53 void DecodeInterleavedOld(HLERequestContext& ctx) {
54 IPC::RequestParser rp{ctx};
55
56 auto input_data{ctx.ReadBuffer(0)};
57 output_data.resize_destructive(ctx.GetWriteBufferSize());
58
59 u32 size{};
60 u32 sample_count{};
61 auto result =
62 impl->DecodeInterleaved(&size, nullptr, &sample_count, input_data, output_data, false);
63
64 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
65
66 ctx.WriteBuffer(output_data);
67
68 IPC::ResponseBuilder rb{ctx, 4};
69 rb.Push(result);
70 rb.Push(size);
71 rb.Push(sample_count);
72 }
73
74 void SetContext(HLERequestContext& ctx) {
75 IPC::RequestParser rp{ctx};
76
77 LOG_DEBUG(Service_Audio, "called");
78
79 auto input_data{ctx.ReadBuffer(0)};
80 auto result = impl->SetContext(input_data);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(result);
84 }
85
86 void DecodeInterleavedForMultiStreamOld(HLERequestContext& ctx) {
87 IPC::RequestParser rp{ctx};
88
89 auto input_data{ctx.ReadBuffer(0)};
90 output_data.resize_destructive(ctx.GetWriteBufferSize());
91
92 u32 size{};
93 u32 sample_count{};
94 auto result = impl->DecodeInterleavedForMultiStream(&size, nullptr, &sample_count,
95 input_data, output_data, false);
96
97 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {}", size, sample_count);
98
99 ctx.WriteBuffer(output_data);
100
101 IPC::ResponseBuilder rb{ctx, 4};
102 rb.Push(result);
103 rb.Push(size);
104 rb.Push(sample_count);
105 }
106
107 void SetContextForMultiStream(HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx};
109
110 LOG_DEBUG(Service_Audio, "called");
111
112 auto input_data{ctx.ReadBuffer(0)};
113 auto result = impl->SetContext(input_data);
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(result);
117 }
118
119 void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
120 IPC::RequestParser rp{ctx};
121
122 auto input_data{ctx.ReadBuffer(0)};
123 output_data.resize_destructive(ctx.GetWriteBufferSize());
124
125 u32 size{};
126 u32 sample_count{};
127 u64 time_taken{};
128 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
129 output_data, false);
130
131 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
132 sample_count, time_taken);
133
134 ctx.WriteBuffer(output_data);
135
136 IPC::ResponseBuilder rb{ctx, 6};
137 rb.Push(result);
138 rb.Push(size);
139 rb.Push(sample_count);
140 rb.Push(time_taken);
141 }
142
143 void DecodeInterleavedForMultiStreamWithPerfOld(HLERequestContext& ctx) {
144 IPC::RequestParser rp{ctx};
145
146 auto input_data{ctx.ReadBuffer(0)};
147 output_data.resize_destructive(ctx.GetWriteBufferSize());
148
149 u32 size{};
150 u32 sample_count{};
151 u64 time_taken{};
152 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
153 input_data, output_data, false);
154
155 LOG_DEBUG(Service_Audio, "bytes read 0x{:X} samples generated {} time taken {}", size,
156 sample_count, time_taken);
157
158 ctx.WriteBuffer(output_data);
159
160 IPC::ResponseBuilder rb{ctx, 6};
161 rb.Push(result);
162 rb.Push(size);
163 rb.Push(sample_count);
164 rb.Push(time_taken);
165 }
166
167 void DecodeInterleavedWithPerfAndResetOld(HLERequestContext& ctx) {
168 IPC::RequestParser rp{ctx};
169
170 auto reset{rp.Pop<bool>()};
171
172 auto input_data{ctx.ReadBuffer(0)};
173 output_data.resize_destructive(ctx.GetWriteBufferSize());
174
175 u32 size{};
176 u32 sample_count{};
177 u64 time_taken{};
178 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
179 output_data, reset);
180
181 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
182 reset, size, sample_count, time_taken);
183
184 ctx.WriteBuffer(output_data);
185
186 IPC::ResponseBuilder rb{ctx, 6};
187 rb.Push(result);
188 rb.Push(size);
189 rb.Push(sample_count);
190 rb.Push(time_taken);
191 }
192
193 void DecodeInterleavedForMultiStreamWithPerfAndResetOld(HLERequestContext& ctx) {
194 IPC::RequestParser rp{ctx};
195
196 auto reset{rp.Pop<bool>()};
197
198 auto input_data{ctx.ReadBuffer(0)};
199 output_data.resize_destructive(ctx.GetWriteBufferSize());
200
201 u32 size{};
202 u32 sample_count{};
203 u64 time_taken{};
204 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
205 input_data, output_data, reset);
206
207 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
208 reset, size, sample_count, time_taken);
209
210 ctx.WriteBuffer(output_data);
211
212 IPC::ResponseBuilder rb{ctx, 6};
213 rb.Push(result);
214 rb.Push(size);
215 rb.Push(sample_count);
216 rb.Push(time_taken);
217 }
218
219 void DecodeInterleaved(HLERequestContext& ctx) {
220 IPC::RequestParser rp{ctx};
221
222 auto reset{rp.Pop<bool>()};
223
224 auto input_data{ctx.ReadBuffer(0)};
225 output_data.resize_destructive(ctx.GetWriteBufferSize());
226
227 u32 size{};
228 u32 sample_count{};
229 u64 time_taken{};
230 auto result = impl->DecodeInterleaved(&size, &time_taken, &sample_count, input_data,
231 output_data, reset);
232
233 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
234 reset, size, sample_count, time_taken);
235
236 ctx.WriteBuffer(output_data);
237
238 IPC::ResponseBuilder rb{ctx, 6};
239 rb.Push(result);
240 rb.Push(size);
241 rb.Push(sample_count);
242 rb.Push(time_taken);
243 }
244
245 void DecodeInterleavedForMultiStream(HLERequestContext& ctx) {
246 IPC::RequestParser rp{ctx};
247
248 auto reset{rp.Pop<bool>()};
249
250 auto input_data{ctx.ReadBuffer(0)};
251 output_data.resize_destructive(ctx.GetWriteBufferSize());
252
253 u32 size{};
254 u32 sample_count{};
255 u64 time_taken{};
256 auto result = impl->DecodeInterleavedForMultiStream(&size, &time_taken, &sample_count,
257 input_data, output_data, reset);
258
259 LOG_DEBUG(Service_Audio, "reset {} bytes read 0x{:X} samples generated {} time taken {}",
260 reset, size, sample_count, time_taken);
261
262 ctx.WriteBuffer(output_data);
263
264 IPC::ResponseBuilder rb{ctx, 6};
265 rb.Push(result);
266 rb.Push(size);
267 rb.Push(sample_count);
268 rb.Push(time_taken);
269 }
270
271 std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
272 Common::ScratchBuffer<u8> output_data;
273};
274
275void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx};
277
278 auto params = rp.PopRaw<OpusParameters>();
279 auto transfer_memory_size{rp.Pop<u32>()};
280 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
281 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
282
283 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
284 params.sample_rate, params.channel_count, transfer_memory_size);
285
286 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
287
288 OpusParametersEx ex{
289 .sample_rate = params.sample_rate,
290 .channel_count = params.channel_count,
291 .use_large_frame_size = false,
292 };
293 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
294
295 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
296 rb.Push(result);
297 rb.PushIpcInterface(decoder);
298}
299
300void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
301 IPC::RequestParser rp{ctx};
302 auto params = rp.PopRaw<OpusParameters>();
303
304 u64 size{};
305 auto result = impl.GetWorkBufferSize(params, size);
306
307 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size 0x{:X}",
308 params.sample_rate, params.channel_count, size);
309
310 IPC::ResponseBuilder rb{ctx, 4};
311 rb.Push(result);
312 rb.Push(size);
313}
314
315void HwOpus::OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx) {
316 IPC::RequestParser rp{ctx};
317
318 auto input{ctx.ReadBuffer()};
319 OpusMultiStreamParameters params;
320 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
321
322 auto transfer_memory_size{rp.Pop<u32>()};
323 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
324 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
325
326 LOG_DEBUG(Service_Audio,
327 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
328 "transfer_memory_size 0x{:X}",
329 params.sample_rate, params.channel_count, params.total_stream_count,
330 params.stereo_stream_count, transfer_memory_size);
331
332 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
333
334 OpusMultiStreamParametersEx ex{
335 .sample_rate = params.sample_rate,
336 .channel_count = params.channel_count,
337 .total_stream_count = params.total_stream_count,
338 .stereo_stream_count = params.stereo_stream_count,
339 .use_large_frame_size = false,
340 .mappings{},
341 };
342 std::memcpy(ex.mappings.data(), params.mappings.data(), sizeof(params.mappings));
343 auto result = decoder->Initialize(ex, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
344
345 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
346 rb.Push(result);
347 rb.PushIpcInterface(decoder);
348}
349
350void HwOpus::GetWorkBufferSizeForMultiStream(HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352
353 auto input{ctx.ReadBuffer()};
354 OpusMultiStreamParameters params;
355 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParameters));
356
357 u64 size{};
358 auto result = impl.GetWorkBufferSizeForMultiStream(params, size);
359
360 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
361
362 IPC::ResponseBuilder rb{ctx, 4};
363 rb.Push(result);
364 rb.Push(size);
365}
366
367void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
368 IPC::RequestParser rp{ctx};
369
370 auto params = rp.PopRaw<OpusParametersEx>();
371 auto transfer_memory_size{rp.Pop<u32>()};
372 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
373 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
374
375 LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size 0x{:X}",
376 params.sample_rate, params.channel_count, transfer_memory_size);
377
378 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
379
380 auto result =
381 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
382
383 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
384 rb.Push(result);
385 rb.PushIpcInterface(decoder);
386}
387
388void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx};
390 auto params = rp.PopRaw<OpusParametersEx>();
391
392 u64 size{};
393 auto result = impl.GetWorkBufferSizeEx(params, size);
394
395 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
396
397 IPC::ResponseBuilder rb{ctx, 4};
398 rb.Push(result);
399 rb.Push(size);
400}
401
402void HwOpus::OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx) {
403 IPC::RequestParser rp{ctx};
404
405 auto input{ctx.ReadBuffer()};
406 OpusMultiStreamParametersEx params;
407 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
408
409 auto transfer_memory_size{rp.Pop<u32>()};
410 auto transfer_memory_handle{ctx.GetCopyHandle(0)};
411 auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)};
412
413 LOG_DEBUG(Service_Audio,
414 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
415 "use_large_frame_size {}"
416 "transfer_memory_size 0x{:X}",
417 params.sample_rate, params.channel_count, params.total_stream_count,
418 params.stereo_stream_count, params.use_large_frame_size, transfer_memory_size);
419
420 auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
421
422 auto result =
423 decoder->Initialize(params, transfer_memory.GetPointerUnsafe(), transfer_memory_size);
424
425 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
426 rb.Push(result);
427 rb.PushIpcInterface(decoder);
428}
429
430void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
431 IPC::RequestParser rp{ctx};
432
433 auto input{ctx.ReadBuffer()};
434 OpusMultiStreamParametersEx params;
435 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
436
437 u64 size{};
438 auto result = impl.GetWorkBufferSizeForMultiStreamEx(params, size);
439
440 LOG_DEBUG(Service_Audio,
441 "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
442 "use_large_frame_size {} -- returned size 0x{:X}",
443 params.sample_rate, params.channel_count, params.total_stream_count,
444 params.stereo_stream_count, params.use_large_frame_size, size);
445
446 IPC::ResponseBuilder rb{ctx, 4};
447 rb.Push(result);
448 rb.Push(size);
449}
450
451void HwOpus::GetWorkBufferSizeExEx(HLERequestContext& ctx) {
452 IPC::RequestParser rp{ctx};
453 auto params = rp.PopRaw<OpusParametersEx>();
454
455 u64 size{};
456 auto result = impl.GetWorkBufferSizeExEx(params, size);
457
458 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
459
460 IPC::ResponseBuilder rb{ctx, 4};
461 rb.Push(result);
462 rb.Push(size);
463}
464
465void HwOpus::GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx) {
466 IPC::RequestParser rp{ctx};
467
468 auto input{ctx.ReadBuffer()};
469 OpusMultiStreamParametersEx params;
470 std::memcpy(&params, input.data(), sizeof(OpusMultiStreamParametersEx));
471
472 u64 size{};
473 auto result = impl.GetWorkBufferSizeForMultiStreamExEx(params, size);
474
475 LOG_DEBUG(Service_Audio, "size 0x{:X}", size);
476
477 IPC::ResponseBuilder rb{ctx, 4};
478 rb.Push(result);
479 rb.Push(size);
480}
481
482HwOpus::HwOpus(Core::System& system_)
483 : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
484 static const FunctionInfo functions[] = {
485 {0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
486 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
487 {2, &HwOpus::OpenHardwareOpusDecoderForMultiStream, "OpenOpusDecoderForMultiStream"},
488 {3, &HwOpus::GetWorkBufferSizeForMultiStream, "GetWorkBufferSizeForMultiStream"},
489 {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
490 {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
491 {6, &HwOpus::OpenHardwareOpusDecoderForMultiStreamEx,
492 "OpenHardwareOpusDecoderForMultiStreamEx"},
493 {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
494 {8, &HwOpus::GetWorkBufferSizeExEx, "GetWorkBufferSizeExEx"},
495 {9, &HwOpus::GetWorkBufferSizeForMultiStreamExEx, "GetWorkBufferSizeForMultiStreamExEx"},
496 };
497 RegisterHandlers(functions);
498}
499
500HwOpus::~HwOpus() = default;
501
502} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
deleted file mode 100644
index d3960065e..000000000
--- a/src/core/hle/service/audio/hwopus.h
+++ /dev/null
@@ -1,36 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/opus/decoder_manager.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::Audio {
14
15class HwOpus final : public ServiceFramework<HwOpus> {
16public:
17 explicit HwOpus(Core::System& system_);
18 ~HwOpus() override;
19
20private:
21 void OpenHardwareOpusDecoder(HLERequestContext& ctx);
22 void GetWorkBufferSize(HLERequestContext& ctx);
23 void OpenHardwareOpusDecoderForMultiStream(HLERequestContext& ctx);
24 void GetWorkBufferSizeForMultiStream(HLERequestContext& ctx);
25 void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
26 void GetWorkBufferSizeEx(HLERequestContext& ctx);
27 void OpenHardwareOpusDecoderForMultiStreamEx(HLERequestContext& ctx);
28 void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
29 void GetWorkBufferSizeExEx(HLERequestContext& ctx);
30 void GetWorkBufferSizeForMultiStreamExEx(HLERequestContext& ctx);
31
32 Core::System& system;
33 AudioCore::OpusDecoder::OpusDecoderManager impl;
34};
35
36} // namespace Service::Audio
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 38cdd57ad..83618a956 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/btdrv/btdrv.h" 7#include "core/hle/service/btdrv/btdrv.h"
8#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/ipc_helpers.h" 9#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/server_manager.h" 11#include "core/hle/service/server_manager.h"
@@ -13,9 +14,9 @@
13 14
14namespace Service::BtDrv { 15namespace Service::BtDrv {
15 16
16class Bt final : public ServiceFramework<Bt> { 17class IBluetoothUser final : public ServiceFramework<IBluetoothUser> {
17public: 18public:
18 explicit Bt(Core::System& system_) 19 explicit IBluetoothUser(Core::System& system_)
19 : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} { 20 : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} {
20 // clang-format off 21 // clang-format off
21 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
@@ -28,7 +29,7 @@ public:
28 {6, nullptr, "SetLeResponse"}, 29 {6, nullptr, "SetLeResponse"},
29 {7, nullptr, "LeSendIndication"}, 30 {7, nullptr, "LeSendIndication"},
30 {8, nullptr, "GetLeEventInfo"}, 31 {8, nullptr, "GetLeEventInfo"},
31 {9, &Bt::RegisterBleEvent, "RegisterBleEvent"}, 32 {9, C<&IBluetoothUser::RegisterBleEvent>, "RegisterBleEvent"},
32 }; 33 };
33 // clang-format on 34 // clang-format on
34 RegisterHandlers(functions); 35 RegisterHandlers(functions);
@@ -36,17 +37,16 @@ public:
36 register_event = service_context.CreateEvent("BT:RegisterEvent"); 37 register_event = service_context.CreateEvent("BT:RegisterEvent");
37 } 38 }
38 39
39 ~Bt() override { 40 ~IBluetoothUser() override {
40 service_context.CloseEvent(register_event); 41 service_context.CloseEvent(register_event);
41 } 42 }
42 43
43private: 44private:
44 void RegisterBleEvent(HLERequestContext& ctx) { 45 Result RegisterBleEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
45 LOG_WARNING(Service_BTM, "(STUBBED) called"); 46 LOG_WARNING(Service_BTM, "(STUBBED) called");
46 47
47 IPC::ResponseBuilder rb{ctx, 2, 1}; 48 *out_event = &register_event->GetReadableEvent();
48 rb.Push(ResultSuccess); 49 R_SUCCEED();
49 rb.PushCopyObjects(register_event->GetReadableEvent());
50 } 50 }
51 51
52 KernelHelpers::ServiceContext service_context; 52 KernelHelpers::ServiceContext service_context;
@@ -54,9 +54,9 @@ private:
54 Kernel::KEvent* register_event; 54 Kernel::KEvent* register_event;
55}; 55};
56 56
57class BtDrv final : public ServiceFramework<BtDrv> { 57class IBluetoothDriver final : public ServiceFramework<IBluetoothDriver> {
58public: 58public:
59 explicit BtDrv(Core::System& system_) : ServiceFramework{system_, "btdrv"} { 59 explicit IBluetoothDriver(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
60 // clang-format off 60 // clang-format off
61 static const FunctionInfo functions[] = { 61 static const FunctionInfo functions[] = {
62 {0, nullptr, "InitializeBluetoothDriver"}, 62 {0, nullptr, "InitializeBluetoothDriver"},
@@ -93,7 +93,7 @@ public:
93 {31, nullptr, "EnableMcMode"}, 93 {31, nullptr, "EnableMcMode"},
94 {32, nullptr, "EnableLlrScan"}, 94 {32, nullptr, "EnableLlrScan"},
95 {33, nullptr, "DisableLlrScan"}, 95 {33, nullptr, "DisableLlrScan"},
96 {34, nullptr, "EnableRadio"}, 96 {34, C<&IBluetoothDriver::EnableRadio>, "EnableRadio"},
97 {35, nullptr, "SetVisibility"}, 97 {35, nullptr, "SetVisibility"},
98 {36, nullptr, "EnableTbfcScan"}, 98 {36, nullptr, "EnableTbfcScan"},
99 {37, nullptr, "RegisterHidReportEvent"}, 99 {37, nullptr, "RegisterHidReportEvent"},
@@ -195,13 +195,19 @@ public:
195 195
196 RegisterHandlers(functions); 196 RegisterHandlers(functions);
197 } 197 }
198
199private:
200 Result EnableRadio() {
201 LOG_WARNING(Service_BTDRV, "(STUBBED) called");
202 R_SUCCEED();
203 }
198}; 204};
199 205
200void LoopProcess(Core::System& system) { 206void LoopProcess(Core::System& system) {
201 auto server_manager = std::make_unique<ServerManager>(system); 207 auto server_manager = std::make_unique<ServerManager>(system);
202 208
203 server_manager->RegisterNamedService("btdrv", std::make_shared<BtDrv>(system)); 209 server_manager->RegisterNamedService("btdrv", std::make_shared<IBluetoothDriver>(system));
204 server_manager->RegisterNamedService("bt", std::make_shared<Bt>(system)); 210 server_manager->RegisterNamedService("bt", std::make_shared<IBluetoothUser>(system));
205 ServerManager::RunServer(std::move(server_manager)); 211 ServerManager::RunServer(std::move(server_manager));
206} 212}
207 213
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 2dc23e674..d120dade8 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -3,141 +3,18 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm.h" 6#include "core/hle/service/btm/btm.h"
10#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/btm/btm_debug.h"
11#include "core/hle/service/kernel_helpers.h" 8#include "core/hle/service/btm/btm_system.h"
9#include "core/hle/service/btm/btm_user.h"
12#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
13#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
14 12
15namespace Service::BTM { 13namespace Service::BTM {
16 14
17class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 15class IBtm final : public ServiceFramework<IBtm> {
18public: 16public:
19 explicit IBtmUserCore(Core::System& system_) 17 explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} {
20 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
24 {1, nullptr, "GetBleScanFilterParameter"},
25 {2, nullptr, "GetBleScanFilterParameter2"},
26 {3, nullptr, "StartBleScanForGeneral"},
27 {4, nullptr, "StopBleScanForGeneral"},
28 {5, nullptr, "GetBleScanResultsForGeneral"},
29 {6, nullptr, "StartBleScanForPaired"},
30 {7, nullptr, "StopBleScanForPaired"},
31 {8, nullptr, "StartBleScanForSmartDevice"},
32 {9, nullptr, "StopBleScanForSmartDevice"},
33 {10, nullptr, "GetBleScanResultsForSmartDevice"},
34 {17, &IBtmUserCore::AcquireBleConnectionEvent, "AcquireBleConnectionEvent"},
35 {18, nullptr, "BleConnect"},
36 {19, nullptr, "BleDisconnect"},
37 {20, nullptr, "BleGetConnectionState"},
38 {21, nullptr, "AcquireBlePairingEvent"},
39 {22, nullptr, "BlePairDevice"},
40 {23, nullptr, "BleUnPairDevice"},
41 {24, nullptr, "BleUnPairDevice2"},
42 {25, nullptr, "BleGetPairedDevices"},
43 {26, &IBtmUserCore::AcquireBleServiceDiscoveryEvent, "AcquireBleServiceDiscoveryEvent"},
44 {27, nullptr, "GetGattServices"},
45 {28, nullptr, "GetGattService"},
46 {29, nullptr, "GetGattIncludedServices"},
47 {30, nullptr, "GetBelongingGattService"},
48 {31, nullptr, "GetGattCharacteristics"},
49 {32, nullptr, "GetGattDescriptors"},
50 {33, &IBtmUserCore::AcquireBleMtuConfigEvent, "AcquireBleMtuConfigEvent"},
51 {34, nullptr, "ConfigureBleMtu"},
52 {35, nullptr, "GetBleMtu"},
53 {36, nullptr, "RegisterBleGattDataPath"},
54 {37, nullptr, "UnregisterBleGattDataPath"},
55 };
56 // clang-format on
57 RegisterHandlers(functions);
58
59 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
60 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
61 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
62 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
63 }
64
65 ~IBtmUserCore() override {
66 service_context.CloseEvent(scan_event);
67 service_context.CloseEvent(connection_event);
68 service_context.CloseEvent(service_discovery_event);
69 service_context.CloseEvent(config_event);
70 }
71
72private:
73 void AcquireBleScanEvent(HLERequestContext& ctx) {
74 LOG_WARNING(Service_BTM, "(STUBBED) called");
75
76 IPC::ResponseBuilder rb{ctx, 3, 1};
77 rb.Push(ResultSuccess);
78 rb.Push(true);
79 rb.PushCopyObjects(scan_event->GetReadableEvent());
80 }
81
82 void AcquireBleConnectionEvent(HLERequestContext& ctx) {
83 LOG_WARNING(Service_BTM, "(STUBBED) called");
84
85 IPC::ResponseBuilder rb{ctx, 3, 1};
86 rb.Push(ResultSuccess);
87 rb.Push(true);
88 rb.PushCopyObjects(connection_event->GetReadableEvent());
89 }
90
91 void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) {
92 LOG_WARNING(Service_BTM, "(STUBBED) called");
93
94 IPC::ResponseBuilder rb{ctx, 3, 1};
95 rb.Push(ResultSuccess);
96 rb.Push(true);
97 rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
98 }
99
100 void AcquireBleMtuConfigEvent(HLERequestContext& ctx) {
101 LOG_WARNING(Service_BTM, "(STUBBED) called");
102
103 IPC::ResponseBuilder rb{ctx, 3, 1};
104 rb.Push(ResultSuccess);
105 rb.Push(true);
106 rb.PushCopyObjects(config_event->GetReadableEvent());
107 }
108
109 KernelHelpers::ServiceContext service_context;
110
111 Kernel::KEvent* scan_event;
112 Kernel::KEvent* connection_event;
113 Kernel::KEvent* service_discovery_event;
114 Kernel::KEvent* config_event;
115};
116
117class BTM_USR final : public ServiceFramework<BTM_USR> {
118public:
119 explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
120 // clang-format off
121 static const FunctionInfo functions[] = {
122 {0, &BTM_USR::GetCore, "GetCore"},
123 };
124 // clang-format on
125 RegisterHandlers(functions);
126 }
127
128private:
129 void GetCore(HLERequestContext& ctx) {
130 LOG_WARNING(Service_BTM, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<IBtmUserCore>(system);
135 }
136};
137
138class BTM final : public ServiceFramework<BTM> {
139public:
140 explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} {
141 // clang-format off 18 // clang-format off
142 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
143 {0, nullptr, "GetState"}, 20 {0, nullptr, "GetState"},
@@ -232,144 +109,13 @@ public:
232 } 109 }
233}; 110};
234 111
235class BTM_DBG final : public ServiceFramework<BTM_DBG> {
236public:
237 explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
238 // clang-format off
239 static const FunctionInfo functions[] = {
240 {0, nullptr, "AcquireDiscoveryEvent"},
241 {1, nullptr, "StartDiscovery"},
242 {2, nullptr, "CancelDiscovery"},
243 {3, nullptr, "GetDeviceProperty"},
244 {4, nullptr, "CreateBond"},
245 {5, nullptr, "CancelBond"},
246 {6, nullptr, "SetTsiMode"},
247 {7, nullptr, "GeneralTest"},
248 {8, nullptr, "HidConnect"},
249 {9, nullptr, "GeneralGet"},
250 {10, nullptr, "GetGattClientDisconnectionReason"},
251 {11, nullptr, "GetBleConnectionParameter"},
252 {12, nullptr, "GetBleConnectionParameterRequest"},
253 {13, nullptr, "Unknown13"},
254 };
255 // clang-format on
256
257 RegisterHandlers(functions);
258 }
259};
260
261class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
262public:
263 explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
264 // clang-format off
265 static const FunctionInfo functions[] = {
266 {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
267 {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
268 {2, nullptr, "ClearGamepadPairingDatabase"},
269 {3, nullptr, "GetPairedGamepadCount"},
270 {4, nullptr, "EnableRadio"},
271 {5, nullptr, "DisableRadio"},
272 {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
273 {7, nullptr, "AcquireRadioEvent"},
274 {8, nullptr, "AcquireGamepadPairingEvent"},
275 {9, nullptr, "IsGamepadPairingStarted"},
276 {10, nullptr, "StartAudioDeviceDiscovery"},
277 {11, nullptr, "StopAudioDeviceDiscovery"},
278 {12, nullptr, "IsDiscoveryingAudioDevice"},
279 {13, nullptr, "GetDiscoveredAudioDevice"},
280 {14, nullptr, "AcquireAudioDeviceConnectionEvent"},
281 {15, nullptr, "ConnectAudioDevice"},
282 {16, nullptr, "IsConnectingAudioDevice"},
283 {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
284 {18, nullptr, "DisconnectAudioDevice"},
285 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
286 {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"},
287 {21, nullptr, "RemoveAudioDevicePairing"},
288 {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
289 {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
290 };
291 // clang-format on
292
293 RegisterHandlers(functions);
294 }
295
296private:
297 void IsRadioEnabled(HLERequestContext& ctx) {
298 LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
299
300 IPC::ResponseBuilder rb{ctx, 3};
301 rb.Push(ResultSuccess);
302 rb.Push(true);
303 }
304
305 void StartGamepadPairing(HLERequestContext& ctx) {
306 LOG_WARNING(Service_BTM, "(STUBBED) called");
307 IPC::ResponseBuilder rb{ctx, 2};
308 rb.Push(ResultSuccess);
309 }
310
311 void CancelGamepadPairing(HLERequestContext& ctx) {
312 LOG_WARNING(Service_BTM, "(STUBBED) called");
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(ResultSuccess);
315 }
316
317 void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
318 LOG_WARNING(Service_BTM, "(STUBBED) called");
319 IPC::ResponseBuilder rb{ctx, 2};
320 rb.Push(ResultSuccess);
321 }
322
323 void GetConnectedAudioDevices(HLERequestContext& ctx) {
324 LOG_WARNING(Service_BTM, "(STUBBED) called");
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(ResultSuccess);
327 rb.Push<u32>(0);
328 }
329
330 void GetPairedAudioDevices(HLERequestContext& ctx) {
331 LOG_WARNING(Service_BTM, "(STUBBED) called");
332 IPC::ResponseBuilder rb{ctx, 3};
333 rb.Push(ResultSuccess);
334 rb.Push<u32>(0);
335 }
336
337 void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
338 LOG_WARNING(Service_BTM, "(STUBBED) called");
339 IPC::ResponseBuilder rb{ctx, 2};
340 rb.Push(ResultSuccess);
341 }
342};
343
344class BTM_SYS final : public ServiceFramework<BTM_SYS> {
345public:
346 explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
347 // clang-format off
348 static const FunctionInfo functions[] = {
349 {0, &BTM_SYS::GetCore, "GetCore"},
350 };
351 // clang-format on
352
353 RegisterHandlers(functions);
354 }
355
356private:
357 void GetCore(HLERequestContext& ctx) {
358 LOG_WARNING(Service_BTM, "called");
359
360 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
361 rb.Push(ResultSuccess);
362 rb.PushIpcInterface<IBtmSystemCore>(system);
363 }
364};
365
366void LoopProcess(Core::System& system) { 112void LoopProcess(Core::System& system) {
367 auto server_manager = std::make_unique<ServerManager>(system); 113 auto server_manager = std::make_unique<ServerManager>(system);
368 114
369 server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system)); 115 server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system));
370 server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system)); 116 server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system));
371 server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system)); 117 server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system));
372 server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system)); 118 server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system));
373 ServerManager::RunServer(std::move(server_manager)); 119 ServerManager::RunServer(std::move(server_manager));
374} 120}
375 121
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
index a99b34364..0bf77d053 100644
--- a/src/core/hle/service/btm/btm.h
+++ b/src/core/hle/service/btm/btm.h
@@ -3,10 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6namespace Service::SM {
7class ServiceManager;
8}
9
10namespace Core { 6namespace Core {
11class System; 7class System;
12}; 8};
diff --git a/src/core/hle/service/btm/btm_debug.cpp b/src/core/hle/service/btm/btm_debug.cpp
new file mode 100644
index 000000000..4d61d2641
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/btm/btm_debug.h"
5
6namespace Service::BTM {
7
8IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AcquireDiscoveryEvent"},
12 {1, nullptr, "StartDiscovery"},
13 {2, nullptr, "CancelDiscovery"},
14 {3, nullptr, "GetDeviceProperty"},
15 {4, nullptr, "CreateBond"},
16 {5, nullptr, "CancelBond"},
17 {6, nullptr, "SetTsiMode"},
18 {7, nullptr, "GeneralTest"},
19 {8, nullptr, "HidConnect"},
20 {9, nullptr, "GeneralGet"},
21 {10, nullptr, "GetGattClientDisconnectionReason"},
22 {11, nullptr, "GetBleConnectionParameter"},
23 {12, nullptr, "GetBleConnectionParameterRequest"},
24 {13, nullptr, "Unknown13"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29}
30
31IBtmDebug::~IBtmDebug() = default;
32
33} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_debug.h b/src/core/hle/service/btm/btm_debug.h
new file mode 100644
index 000000000..bf4f7e14f
--- /dev/null
+++ b/src/core/hle/service/btm/btm_debug.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14
15class IBtmDebug final : public ServiceFramework<IBtmDebug> {
16public:
17 explicit IBtmDebug(Core::System& system_);
18 ~IBtmDebug() override;
19};
20
21} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.cpp b/src/core/hle/service/btm/btm_system.cpp
new file mode 100644
index 000000000..99718a7b0
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system.h"
6#include "core/hle/service/btm/btm_system_core.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/service.h"
9
10namespace Service::BTM {
11
12IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, C<&IBtmSystem::GetCore>, "GetCore"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IBtmSystem::~IBtmSystem() = default;
23
24Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) {
25 LOG_WARNING(Service_BTM, "called");
26
27 *out_interface = std::make_shared<IBtmSystemCore>(system);
28 R_SUCCEED();
29}
30
31} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system.h b/src/core/hle/service/btm/btm_system.h
new file mode 100644
index 000000000..fe1c6dbd7
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmSystemCore;
15
16class IBtmSystem final : public ServiceFramework<IBtmSystem> {
17public:
18 explicit IBtmSystem(Core::System& system_);
19 ~IBtmSystem() override;
20
21private:
22 Result GetCore(OutInterface<IBtmSystemCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.cpp b/src/core/hle/service/btm/btm_system_core.cpp
new file mode 100644
index 000000000..4bc8a9e8b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.cpp
@@ -0,0 +1,127 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_system_core.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/set/system_settings_server.h"
8#include "core/hle/service/sm/sm.h"
9
10namespace Service::BTM {
11
12IBtmSystemCore::IBtmSystemCore(Core::System& system_)
13 : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"},
17 {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"},
18 {2, nullptr, "ClearGamepadPairingDatabase"},
19 {3, nullptr, "GetPairedGamepadCount"},
20 {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"},
21 {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"},
22 {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"},
23 {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"},
24 {8, nullptr, "AcquireGamepadPairingEvent"},
25 {9, nullptr, "IsGamepadPairingStarted"},
26 {10, nullptr, "StartAudioDeviceDiscovery"},
27 {11, nullptr, "StopAudioDeviceDiscovery"},
28 {12, nullptr, "IsDiscoveryingAudioDevice"},
29 {13, nullptr, "GetDiscoveredAudioDevice"},
30 {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
31 {15, nullptr, "ConnectAudioDevice"},
32 {16, nullptr, "IsConnectingAudioDevice"},
33 {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"},
34 {18, nullptr, "DisconnectAudioDevice"},
35 {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
36 {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"},
37 {21, nullptr, "RemoveAudioDevicePairing"},
38 {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"},
39 {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"}
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44 radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent");
45 audio_device_connection_event =
46 service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent");
47
48 m_set_sys =
49 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
50}
51
52IBtmSystemCore::~IBtmSystemCore() {
53 service_context.CloseEvent(radio_event);
54 service_context.CloseEvent(audio_device_connection_event);
55}
56
57Result IBtmSystemCore::StartGamepadPairing() {
58 LOG_WARNING(Service_BTM, "(STUBBED) called");
59 R_SUCCEED();
60}
61
62Result IBtmSystemCore::CancelGamepadPairing() {
63 LOG_WARNING(Service_BTM, "(STUBBED) called");
64 R_SUCCEED();
65}
66
67Result IBtmSystemCore::EnableRadio() {
68 LOG_DEBUG(Service_BTM, "called");
69
70 R_RETURN(m_set_sys->SetBluetoothEnableFlag(true));
71}
72Result IBtmSystemCore::DisableRadio() {
73 LOG_DEBUG(Service_BTM, "called");
74
75 R_RETURN(m_set_sys->SetBluetoothEnableFlag(false));
76}
77
78Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) {
79 LOG_DEBUG(Service_BTM, "called");
80
81 R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled));
82}
83
84Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
85 OutCopyHandle<Kernel::KReadableEvent> out_event) {
86 LOG_WARNING(Service_BTM, "(STUBBED) called");
87
88 *out_is_valid = true;
89 *out_event = &radio_event->GetReadableEvent();
90 R_SUCCEED();
91}
92
93Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
94 OutCopyHandle<Kernel::KReadableEvent> out_event) {
95 LOG_WARNING(Service_BTM, "(STUBBED) called");
96
97 *out_event = &audio_device_connection_event->GetReadableEvent();
98 R_SUCCEED();
99}
100
101Result IBtmSystemCore::GetConnectedAudioDevices(
102 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
103 LOG_WARNING(Service_BTM, "(STUBBED) called");
104
105 *out_count = 0;
106 R_SUCCEED();
107}
108
109Result IBtmSystemCore::GetPairedAudioDevices(
110 Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
111 LOG_WARNING(Service_BTM, "(STUBBED) called");
112
113 *out_count = 0;
114 R_SUCCEED();
115}
116
117Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
118 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
119 R_SUCCEED();
120}
121
122Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
123 LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
124 R_SUCCEED();
125}
126
127} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_system_core.h b/src/core/hle/service/btm/btm_system_core.h
new file mode 100644
index 000000000..06498b21e
--- /dev/null
+++ b/src/core/hle/service/btm/btm_system_core.h
@@ -0,0 +1,60 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::Set {
20class ISystemSettingsServer;
21}
22
23namespace Service::BTM {
24
25class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
26public:
27 explicit IBtmSystemCore(Core::System& system_);
28 ~IBtmSystemCore() override;
29
30private:
31 Result StartGamepadPairing();
32 Result CancelGamepadPairing();
33 Result EnableRadio();
34 Result DisableRadio();
35 Result IsRadioEnabled(Out<bool> out_is_enabled);
36
37 Result AcquireRadioEvent(Out<bool> out_is_valid,
38 OutCopyHandle<Kernel::KReadableEvent> out_event);
39
40 Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
41
42 Result GetConnectedAudioDevices(
43 Out<s32> out_count,
44 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
45
46 Result GetPairedAudioDevices(
47 Out<s32> out_count,
48 OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);
49
50 Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
51 Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
52
53 KernelHelpers::ServiceContext service_context;
54
55 Kernel::KEvent* radio_event;
56 Kernel::KEvent* audio_device_connection_event;
57 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
58};
59
60} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.cpp b/src/core/hle/service/btm/btm_user.cpp
new file mode 100644
index 000000000..d2e228f8d
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/hle/service/btm/btm_user.h"
6#include "core/hle/service/btm/btm_user_core.h"
7#include "core/hle/service/cmif_serialization.h"
8
9namespace Service::BTM {
10
11IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&IBtmUser::GetCore>, "GetCore"},
15 };
16 // clang-format on
17
18 RegisterHandlers(functions);
19}
20
21IBtmUser::~IBtmUser() = default;
22
23Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) {
24 LOG_WARNING(Service_BTM, "called");
25
26 *out_interface = std::make_shared<IBtmUserCore>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user.h b/src/core/hle/service/btm/btm_user.h
new file mode 100644
index 000000000..d9ee5db45
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::BTM {
14class IBtmUserCore;
15
16class IBtmUser final : public ServiceFramework<IBtmUser> {
17public:
18 explicit IBtmUser(Core::System& system_);
19 ~IBtmUser() override;
20
21private:
22 Result GetCore(OutInterface<IBtmUserCore> out_interface);
23};
24
25} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.cpp b/src/core/hle/service/btm/btm_user_core.cpp
new file mode 100644
index 000000000..6f9fa589b
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.cpp
@@ -0,0 +1,103 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/hle/kernel/k_event.h"
9#include "core/hle/service/btm/btm_user_core.h"
10#include "core/hle/service/cmif_serialization.h"
11
12namespace Service::BTM {
13
14IBtmUserCore::IBtmUserCore(Core::System& system_)
15 : ServiceFramework{system_, "IBtmUserCore"}, service_context{system_, "IBtmUserCore"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, C<&IBtmUserCore::AcquireBleScanEvent>, "AcquireBleScanEvent"},
19 {1, nullptr, "GetBleScanFilterParameter"},
20 {2, nullptr, "GetBleScanFilterParameter2"},
21 {3, nullptr, "StartBleScanForGeneral"},
22 {4, nullptr, "StopBleScanForGeneral"},
23 {5, nullptr, "GetBleScanResultsForGeneral"},
24 {6, nullptr, "StartBleScanForPaired"},
25 {7, nullptr, "StopBleScanForPaired"},
26 {8, nullptr, "StartBleScanForSmartDevice"},
27 {9, nullptr, "StopBleScanForSmartDevice"},
28 {10, nullptr, "GetBleScanResultsForSmartDevice"},
29 {17, C<&IBtmUserCore::AcquireBleConnectionEvent>, "AcquireBleConnectionEvent"},
30 {18, nullptr, "BleConnect"},
31 {19, nullptr, "BleDisconnect"},
32 {20, nullptr, "BleGetConnectionState"},
33 {21, nullptr, "AcquireBlePairingEvent"},
34 {22, nullptr, "BlePairDevice"},
35 {23, nullptr, "BleUnPairDevice"},
36 {24, nullptr, "BleUnPairDevice2"},
37 {25, nullptr, "BleGetPairedDevices"},
38 {26, C<&IBtmUserCore::AcquireBleServiceDiscoveryEvent>, "AcquireBleServiceDiscoveryEvent"},
39 {27, nullptr, "GetGattServices"},
40 {28, nullptr, "GetGattService"},
41 {29, nullptr, "GetGattIncludedServices"},
42 {30, nullptr, "GetBelongingGattService"},
43 {31, nullptr, "GetGattCharacteristics"},
44 {32, nullptr, "GetGattDescriptors"},
45 {33, C<&IBtmUserCore::AcquireBleMtuConfigEvent>, "AcquireBleMtuConfigEvent"},
46 {34, nullptr, "ConfigureBleMtu"},
47 {35, nullptr, "GetBleMtu"},
48 {36, nullptr, "RegisterBleGattDataPath"},
49 {37, nullptr, "UnregisterBleGattDataPath"},
50 };
51 // clang-format on
52 RegisterHandlers(functions);
53
54 scan_event = service_context.CreateEvent("IBtmUserCore:ScanEvent");
55 connection_event = service_context.CreateEvent("IBtmUserCore:ConnectionEvent");
56 service_discovery_event = service_context.CreateEvent("IBtmUserCore:DiscoveryEvent");
57 config_event = service_context.CreateEvent("IBtmUserCore:ConfigEvent");
58}
59
60IBtmUserCore::~IBtmUserCore() {
61 service_context.CloseEvent(scan_event);
62 service_context.CloseEvent(connection_event);
63 service_context.CloseEvent(service_discovery_event);
64 service_context.CloseEvent(config_event);
65}
66
67Result IBtmUserCore::AcquireBleScanEvent(Out<bool> out_is_valid,
68 OutCopyHandle<Kernel::KReadableEvent> out_event) {
69 LOG_WARNING(Service_BTM, "(STUBBED) called");
70
71 *out_is_valid = true;
72 *out_event = &scan_event->GetReadableEvent();
73 R_SUCCEED();
74}
75
76Result IBtmUserCore::AcquireBleConnectionEvent(Out<bool> out_is_valid,
77 OutCopyHandle<Kernel::KReadableEvent> out_event) {
78 LOG_WARNING(Service_BTM, "(STUBBED) called");
79
80 *out_is_valid = true;
81 *out_event = &connection_event->GetReadableEvent();
82 R_SUCCEED();
83}
84
85Result IBtmUserCore::AcquireBleServiceDiscoveryEvent(
86 Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event) {
87 LOG_WARNING(Service_BTM, "(STUBBED) called");
88
89 *out_is_valid = true;
90 *out_event = &service_discovery_event->GetReadableEvent();
91 R_SUCCEED();
92}
93
94Result IBtmUserCore::AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
95 OutCopyHandle<Kernel::KReadableEvent> out_event) {
96 LOG_WARNING(Service_BTM, "(STUBBED) called");
97
98 *out_is_valid = true;
99 *out_event = &config_event->GetReadableEvent();
100 R_SUCCEED();
101}
102
103} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm_user_core.h b/src/core/hle/service/btm/btm_user_core.h
new file mode 100644
index 000000000..dc0a22e81
--- /dev/null
+++ b/src/core/hle/service/btm/btm_user_core.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/service.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Core {
16class System;
17}
18
19namespace Service::BTM {
20
21class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
22public:
23 explicit IBtmUserCore(Core::System& system_);
24 ~IBtmUserCore() override;
25
26private:
27 Result AcquireBleScanEvent(Out<bool> out_is_valid,
28 OutCopyHandle<Kernel::KReadableEvent> out_event);
29
30 Result AcquireBleConnectionEvent(Out<bool> out_is_valid,
31 OutCopyHandle<Kernel::KReadableEvent> out_event);
32
33 Result AcquireBleServiceDiscoveryEvent(Out<bool> out_is_valid,
34 OutCopyHandle<Kernel::KReadableEvent> out_event);
35
36 Result AcquireBleMtuConfigEvent(Out<bool> out_is_valid,
37 OutCopyHandle<Kernel::KReadableEvent> out_event);
38
39 KernelHelpers::ServiceContext service_context;
40
41 Kernel::KEvent* scan_event;
42 Kernel::KEvent* connection_event;
43 Kernel::KEvent* service_discovery_event;
44 Kernel::KEvent* config_event;
45};
46
47} // namespace Service::BTM
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index f24682c34..5a5f610f3 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -415,7 +415,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
415 auto& buffer = temp[OutBufferIndex]; 415 auto& buffer = temp[OutBufferIndex];
416 const size_t size = buffer.size(); 416 const size_t size = buffer.size();
417 417
418 if (ctx.CanWriteBuffer(OutBufferIndex)) { 418 if (size > 0 && ctx.CanWriteBuffer(OutBufferIndex)) {
419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 419 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); 420 ctx.WriteBuffer(buffer.data(), size, OutBufferIndex);
421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { 421 } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) {
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
index 39690018b..8483394d0 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -3,82 +3,34 @@
3 3
4#include "core/file_sys/fs_filesystem.h" 4#include "core/file_sys/fs_filesystem.h"
5#include "core/file_sys/savedata_factory.h" 5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
7#include "core/hle/service/ipc_helpers.h"
8 8
9namespace Service::FileSystem { 9namespace Service::FileSystem {
10 10
11template <typename T> 11IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
12static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
13 const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
14 entries.reserve(entries.size() + new_data.size());
15
16 for (const auto& new_entry : new_data) {
17 auto name = new_entry->GetName();
18
19 if (type == FileSys::DirectoryEntryType::File &&
20 name == FileSys::GetSaveDataSizeFileName()) {
21 continue;
22 }
23
24 entries.emplace_back(name, static_cast<s8>(type),
25 type == FileSys::DirectoryEntryType::Directory ? 0
26 : new_entry->GetSize());
27 }
28}
29
30IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
31 FileSys::OpenDirectoryMode mode) 12 FileSys::OpenDirectoryMode mode)
32 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { 13 : ServiceFramework{system_, "IDirectory"},
14 backend(std::make_unique<FileSys::Fsa::IDirectory>(directory_, mode)) {
33 static const FunctionInfo functions[] = { 15 static const FunctionInfo functions[] = {
34 {0, &IDirectory::Read, "Read"}, 16 {0, D<&IDirectory::Read>, "Read"},
35 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 17 {1, D<&IDirectory::GetEntryCount>, "GetEntryCount"},
36 }; 18 };
37 RegisterHandlers(functions); 19 RegisterHandlers(functions);
38
39 // TODO(DarkLordZach): Verify that this is the correct behavior.
40 // Build entry index now to save time later.
41 if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
42 BuildEntryIndex(entries, backend->GetSubdirectories(),
43 FileSys::DirectoryEntryType::Directory);
44 }
45 if (True(mode & FileSys::OpenDirectoryMode::File)) {
46 BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
47 }
48} 20}
49 21
50void IDirectory::Read(HLERequestContext& ctx) { 22Result IDirectory::Read(
23 Out<s64> out_count,
24 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries) {
51 LOG_DEBUG(Service_FS, "called."); 25 LOG_DEBUG(Service_FS, "called.");
52 26
53 // Calculate how many entries we can fit in the output buffer 27 R_RETURN(backend->Read(out_count, out_entries.data(), out_entries.size()));
54 const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
55
56 // Cap at total number of entries.
57 const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
58
59 // Determine data start and end
60 const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
61 const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
62 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
63
64 next_entry_index += actual_entries;
65
66 // Write the data to memory
67 ctx.WriteBuffer(begin, range_size);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(ResultSuccess);
71 rb.Push(actual_entries);
72} 28}
73 29
74void IDirectory::GetEntryCount(HLERequestContext& ctx) { 30Result IDirectory::GetEntryCount(Out<s64> out_count) {
75 LOG_DEBUG(Service_FS, "called"); 31 LOG_DEBUG(Service_FS, "called");
76 32
77 u64 count = entries.size() - next_entry_index; 33 R_RETURN(backend->GetEntryCount(out_count));
78
79 IPC::ResponseBuilder rb{ctx, 4};
80 rb.Push(ResultSuccess);
81 rb.Push(count);
82} 34}
83 35
84} // namespace Service::FileSystem 36} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
index 793ecfcd7..b6251f7fd 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_directory.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_directory.h"
6#include "core/file_sys/vfs/vfs.h" 7#include "core/file_sys/vfs/vfs.h"
8#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 9#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
9 11
@@ -15,16 +17,15 @@ namespace Service::FileSystem {
15 17
16class IDirectory final : public ServiceFramework<IDirectory> { 18class IDirectory final : public ServiceFramework<IDirectory> {
17public: 19public:
18 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, 20 explicit IDirectory(Core::System& system_, FileSys::VirtualDir directory_,
19 FileSys::OpenDirectoryMode mode); 21 FileSys::OpenDirectoryMode mode);
20 22
21private: 23private:
22 FileSys::VirtualDir backend; 24 std::unique_ptr<FileSys::Fsa::IDirectory> backend;
23 std::vector<FileSys::DirectoryEntry> entries;
24 u64 next_entry_index = 0;
25 25
26 void Read(HLERequestContext& ctx); 26 Result Read(Out<s64> out_count,
27 void GetEntryCount(HLERequestContext& ctx); 27 const OutArray<FileSys::DirectoryEntry, BufferAttr_HipcMapAlias> out_entries);
28 Result GetEntryCount(Out<s64> out_count);
28}; 29};
29 30
30} // namespace Service::FileSystem 31} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
index 9a18f6ec5..a355d46ae 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -2,126 +2,64 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_file.h" 6#include "core/hle/service/filesystem/fsp/fs_i_file.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) 10IFile::IFile(Core::System& system_, FileSys::VirtualFile file_)
11 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IFile"}, backend{std::make_unique<FileSys::Fsa::IFile>(file_)} {
12 // clang-format off
12 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
13 {0, &IFile::Read, "Read"}, 14 {0, D<&IFile::Read>, "Read"},
14 {1, &IFile::Write, "Write"}, 15 {1, D<&IFile::Write>, "Write"},
15 {2, &IFile::Flush, "Flush"}, 16 {2, D<&IFile::Flush>, "Flush"},
16 {3, &IFile::SetSize, "SetSize"}, 17 {3, D<&IFile::SetSize>, "SetSize"},
17 {4, &IFile::GetSize, "GetSize"}, 18 {4, D<&IFile::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 19 {5, nullptr, "OperateRange"},
19 {6, nullptr, "OperateRangeWithBuffer"}, 20 {6, nullptr, "OperateRangeWithBuffer"},
20 }; 21 };
22 // clang-format on
21 RegisterHandlers(functions); 23 RegisterHandlers(functions);
22} 24}
23 25
24void IFile::Read(HLERequestContext& ctx) { 26Result IFile::Read(
25 IPC::RequestParser rp{ctx}; 27 FileSys::ReadOption option, Out<s64> out_size, s64 offset,
26 const u64 option = rp.Pop<u64>(); 28 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_buffer,
27 const s64 offset = rp.Pop<s64>(); 29 s64 size) {
28 const s64 length = rp.Pop<s64>(); 30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
29 31 size);
30 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
31
32 // Error checking
33 if (length < 0) {
34 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
35 IPC::ResponseBuilder rb{ctx, 2};
36 rb.Push(FileSys::ResultInvalidSize);
37 return;
38 }
39 if (offset < 0) {
40 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
41 IPC::ResponseBuilder rb{ctx, 2};
42 rb.Push(FileSys::ResultInvalidOffset);
43 return;
44 }
45 32
46 // Read the data from the Storage backend 33 // Read the data from the Storage backend
47 std::vector<u8> output = backend->ReadBytes(length, offset); 34 R_RETURN(
48 35 backend->Read(reinterpret_cast<size_t*>(out_size.Get()), offset, out_buffer.data(), size));
49 // Write the data to memory
50 ctx.WriteBuffer(output);
51
52 IPC::ResponseBuilder rb{ctx, 4};
53 rb.Push(ResultSuccess);
54 rb.Push(static_cast<u64>(output.size()));
55} 36}
56 37
57void IFile::Write(HLERequestContext& ctx) { 38Result IFile::Write(
58 IPC::RequestParser rp{ctx}; 39 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
59 const u64 option = rp.Pop<u64>(); 40 FileSys::WriteOption option, s64 offset, s64 size) {
60 const s64 offset = rp.Pop<s64>(); 41 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option.value, offset,
61 const s64 length = rp.Pop<s64>(); 42 size);
62
63 LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
64
65 // Error checking
66 if (length < 0) {
67 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(FileSys::ResultInvalidSize);
70 return;
71 }
72 if (offset < 0) {
73 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(FileSys::ResultInvalidOffset);
76 return;
77 }
78
79 const auto data = ctx.ReadBuffer();
80 43
81 ASSERT_MSG(static_cast<s64>(data.size()) <= length, 44 R_RETURN(backend->Write(offset, buffer.data(), size, option));
82 "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
83 length, data.size());
84
85 // Write the data to the Storage backend
86 const auto write_size =
87 static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
88 const std::size_t written = backend->Write(data.data(), write_size, offset);
89
90 ASSERT_MSG(static_cast<s64>(written) == length,
91 "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
92 written);
93
94 IPC::ResponseBuilder rb{ctx, 2};
95 rb.Push(ResultSuccess);
96} 45}
97 46
98void IFile::Flush(HLERequestContext& ctx) { 47Result IFile::Flush() {
99 LOG_DEBUG(Service_FS, "called"); 48 LOG_DEBUG(Service_FS, "called");
100 49
101 // Exists for SDK compatibiltity -- No need to flush file. 50 R_RETURN(backend->Flush());
102
103 IPC::ResponseBuilder rb{ctx, 2};
104 rb.Push(ResultSuccess);
105} 51}
106 52
107void IFile::SetSize(HLERequestContext& ctx) { 53Result IFile::SetSize(s64 size) {
108 IPC::RequestParser rp{ctx};
109 const u64 size = rp.Pop<u64>();
110 LOG_DEBUG(Service_FS, "called, size={}", size); 54 LOG_DEBUG(Service_FS, "called, size={}", size);
111 55
112 backend->Resize(size); 56 R_RETURN(backend->SetSize(size));
113
114 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(ResultSuccess);
116} 57}
117 58
118void IFile::GetSize(HLERequestContext& ctx) { 59Result IFile::GetSize(Out<s64> out_size) {
119 const u64 size = backend->GetSize(); 60 LOG_DEBUG(Service_FS, "called");
120 LOG_DEBUG(Service_FS, "called, size={}", size);
121 61
122 IPC::ResponseBuilder rb{ctx, 4}; 62 R_RETURN(backend->GetSize(out_size));
123 rb.Push(ResultSuccess);
124 rb.Push<u64>(size);
125} 63}
126 64
127} // namespace Service::FileSystem 65} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
index 5e5430c67..e8599ee2f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_file.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/fsa/fs_i_file.h"
7#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
@@ -10,16 +12,21 @@ namespace Service::FileSystem {
10 12
11class IFile final : public ServiceFramework<IFile> { 13class IFile final : public ServiceFramework<IFile> {
12public: 14public:
13 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); 15 explicit IFile(Core::System& system_, FileSys::VirtualFile file_);
14 16
15private: 17private:
16 FileSys::VirtualFile backend; 18 std::unique_ptr<FileSys::Fsa::IFile> backend;
17 19
18 void Read(HLERequestContext& ctx); 20 Result Read(FileSys::ReadOption option, Out<s64> out_size, s64 offset,
19 void Write(HLERequestContext& ctx); 21 const OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure>
20 void Flush(HLERequestContext& ctx); 22 out_buffer,
21 void SetSize(HLERequestContext& ctx); 23 s64 size);
22 void GetSize(HLERequestContext& ctx); 24 Result Write(
25 const InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> buffer,
26 FileSys::WriteOption option, s64 offset, s64 size);
27 Result Flush();
28 Result SetSize(s64 size);
29 Result GetSize(Out<s64> out_size);
23}; 30};
24 31
25} // namespace Service::FileSystem 32} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
index efa394dd1..d881e144d 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -2,261 +2,172 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/string_util.h" 4#include "common/string_util.h"
5#include "core/file_sys/fssrv/fssrv_sf_path.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_directory.h" 7#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
6#include "core/hle/service/filesystem/fsp/fs_i_file.h" 8#include "core/hle/service/filesystem/fsp/fs_i_file.h"
7#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 9#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
8#include "core/hle/service/ipc_helpers.h"
9 10
10namespace Service::FileSystem { 11namespace Service::FileSystem {
11 12
12IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) 13IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_)
13 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( 14 : ServiceFramework{system_, "IFileSystem"}, backend{std::make_unique<FileSys::Fsa::IFileSystem>(
14 size_)} { 15 dir_)},
16 size_getter{std::move(size_getter_)} {
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, &IFileSystem::CreateFile, "CreateFile"}, 18 {0, D<&IFileSystem::CreateFile>, "CreateFile"},
17 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 19 {1, D<&IFileSystem::DeleteFile>, "DeleteFile"},
18 {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, 20 {2, D<&IFileSystem::CreateDirectory>, "CreateDirectory"},
19 {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, 21 {3, D<&IFileSystem::DeleteDirectory>, "DeleteDirectory"},
20 {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, 22 {4, D<&IFileSystem::DeleteDirectoryRecursively>, "DeleteDirectoryRecursively"},
21 {5, &IFileSystem::RenameFile, "RenameFile"}, 23 {5, D<&IFileSystem::RenameFile>, "RenameFile"},
22 {6, nullptr, "RenameDirectory"}, 24 {6, nullptr, "RenameDirectory"},
23 {7, &IFileSystem::GetEntryType, "GetEntryType"}, 25 {7, D<&IFileSystem::GetEntryType>, "GetEntryType"},
24 {8, &IFileSystem::OpenFile, "OpenFile"}, 26 {8, D<&IFileSystem::OpenFile>, "OpenFile"},
25 {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, 27 {9, D<&IFileSystem::OpenDirectory>, "OpenDirectory"},
26 {10, &IFileSystem::Commit, "Commit"}, 28 {10, D<&IFileSystem::Commit>, "Commit"},
27 {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, 29 {11, D<&IFileSystem::GetFreeSpaceSize>, "GetFreeSpaceSize"},
28 {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, 30 {12, D<&IFileSystem::GetTotalSpaceSize>, "GetTotalSpaceSize"},
29 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, 31 {13, D<&IFileSystem::CleanDirectoryRecursively>, "CleanDirectoryRecursively"},
30 {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, 32 {14, D<&IFileSystem::GetFileTimeStampRaw>, "GetFileTimeStampRaw"},
31 {15, nullptr, "QueryEntry"}, 33 {15, nullptr, "QueryEntry"},
32 {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, 34 {16, D<&IFileSystem::GetFileSystemAttribute>, "GetFileSystemAttribute"},
33 }; 35 };
34 RegisterHandlers(functions); 36 RegisterHandlers(functions);
35} 37}
36 38
37void IFileSystem::CreateFile(HLERequestContext& ctx) { 39Result IFileSystem::CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
38 IPC::RequestParser rp{ctx}; 40 s32 option, s64 size) {
41 LOG_DEBUG(Service_FS, "called. file={}, option=0x{:X}, size=0x{:08X}", path->str, option, size);
39 42
40 const auto file_buffer = ctx.ReadBuffer(); 43 R_RETURN(backend->CreateFile(FileSys::Path(path->str), size));
41 const std::string name = Common::StringFromBuffer(file_buffer);
42
43 const u64 file_mode = rp.Pop<u64>();
44 const u32 file_size = rp.Pop<u32>();
45
46 LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
47 file_size);
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(backend.CreateFile(name, file_size));
51} 44}
52 45
53void IFileSystem::DeleteFile(HLERequestContext& ctx) { 46Result IFileSystem::DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
54 const auto file_buffer = ctx.ReadBuffer(); 47 LOG_DEBUG(Service_FS, "called. file={}", path->str);
55 const std::string name = Common::StringFromBuffer(file_buffer);
56 48
57 LOG_DEBUG(Service_FS, "called. file={}", name); 49 R_RETURN(backend->DeleteFile(FileSys::Path(path->str)));
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(backend.DeleteFile(name));
61} 50}
62 51
63void IFileSystem::CreateDirectory(HLERequestContext& ctx) { 52Result IFileSystem::CreateDirectory(
64 const auto file_buffer = ctx.ReadBuffer(); 53 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
65 const std::string name = Common::StringFromBuffer(file_buffer); 54 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
66
67 LOG_DEBUG(Service_FS, "called. directory={}", name);
68 55
69 IPC::ResponseBuilder rb{ctx, 2}; 56 R_RETURN(backend->CreateDirectory(FileSys::Path(path->str)));
70 rb.Push(backend.CreateDirectory(name));
71} 57}
72 58
73void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { 59Result IFileSystem::DeleteDirectory(
74 const auto file_buffer = ctx.ReadBuffer(); 60 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
75 const std::string name = Common::StringFromBuffer(file_buffer); 61 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
76
77 LOG_DEBUG(Service_FS, "called. directory={}", name);
78 62
79 IPC::ResponseBuilder rb{ctx, 2}; 63 R_RETURN(backend->DeleteDirectory(FileSys::Path(path->str)));
80 rb.Push(backend.DeleteDirectory(name));
81} 64}
82 65
83void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { 66Result IFileSystem::DeleteDirectoryRecursively(
84 const auto file_buffer = ctx.ReadBuffer(); 67 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
85 const std::string name = Common::StringFromBuffer(file_buffer); 68 LOG_DEBUG(Service_FS, "called. directory={}", path->str);
86 69
87 LOG_DEBUG(Service_FS, "called. directory={}", name); 70 R_RETURN(backend->DeleteDirectoryRecursively(FileSys::Path(path->str)));
88
89 IPC::ResponseBuilder rb{ctx, 2};
90 rb.Push(backend.DeleteDirectoryRecursively(name));
91} 71}
92 72
93void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { 73Result IFileSystem::CleanDirectoryRecursively(
94 const auto file_buffer = ctx.ReadBuffer(); 74 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
95 const std::string name = Common::StringFromBuffer(file_buffer); 75 LOG_DEBUG(Service_FS, "called. Directory: {}", path->str);
96
97 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
98 76
99 IPC::ResponseBuilder rb{ctx, 2}; 77 R_RETURN(backend->CleanDirectoryRecursively(FileSys::Path(path->str)));
100 rb.Push(backend.CleanDirectoryRecursively(name));
101} 78}
102 79
103void IFileSystem::RenameFile(HLERequestContext& ctx) { 80Result IFileSystem::RenameFile(
104 const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); 81 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
105 const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); 82 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path) {
106 83 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", old_path->str, new_path->str);
107 LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
108 84
109 IPC::ResponseBuilder rb{ctx, 2}; 85 R_RETURN(backend->RenameFile(FileSys::Path(old_path->str), FileSys::Path(new_path->str)));
110 rb.Push(backend.RenameFile(src_name, dst_name));
111} 86}
112 87
113void IFileSystem::OpenFile(HLERequestContext& ctx) { 88Result IFileSystem::OpenFile(OutInterface<IFile> out_interface,
114 IPC::RequestParser rp{ctx}; 89 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
115 90 u32 mode) {
116 const auto file_buffer = ctx.ReadBuffer(); 91 LOG_DEBUG(Service_FS, "called. file={}, mode={}", path->str, mode);
117 const std::string name = Common::StringFromBuffer(file_buffer);
118
119 const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
120
121 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
122 92
123 FileSys::VirtualFile vfs_file{}; 93 FileSys::VirtualFile vfs_file{};
124 auto result = backend.OpenFile(&vfs_file, name, mode); 94 R_TRY(backend->OpenFile(&vfs_file, FileSys::Path(path->str),
125 if (result != ResultSuccess) { 95 static_cast<FileSys::OpenMode>(mode)));
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(result);
128 return;
129 }
130
131 auto file = std::make_shared<IFile>(system, vfs_file);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(ResultSuccess);
135 rb.PushIpcInterface<IFile>(std::move(file));
136}
137
138void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
139 IPC::RequestParser rp{ctx};
140 96
141 const auto file_buffer = ctx.ReadBuffer(); 97 *out_interface = std::make_shared<IFile>(system, vfs_file);
142 const std::string name = Common::StringFromBuffer(file_buffer); 98 R_SUCCEED();
143 const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); 99}
144 100
145 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); 101Result IFileSystem::OpenDirectory(OutInterface<IDirectory> out_interface,
102 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
103 u32 mode) {
104 LOG_DEBUG(Service_FS, "called. directory={}, mode={}", path->str, mode);
146 105
147 FileSys::VirtualDir vfs_dir{}; 106 FileSys::VirtualDir vfs_dir{};
148 auto result = backend.OpenDirectory(&vfs_dir, name); 107 R_TRY(backend->OpenDirectory(&vfs_dir, FileSys::Path(path->str),
149 if (result != ResultSuccess) { 108 static_cast<FileSys::OpenDirectoryMode>(mode)));
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(result);
152 return;
153 }
154
155 auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158 rb.Push(ResultSuccess);
159 rb.PushIpcInterface<IDirectory>(std::move(directory));
160}
161 109
162void IFileSystem::GetEntryType(HLERequestContext& ctx) { 110 *out_interface = std::make_shared<IDirectory>(system, vfs_dir,
163 const auto file_buffer = ctx.ReadBuffer(); 111 static_cast<FileSys::OpenDirectoryMode>(mode));
164 const std::string name = Common::StringFromBuffer(file_buffer); 112 R_SUCCEED();
113}
165 114
166 LOG_DEBUG(Service_FS, "called. file={}", name); 115Result IFileSystem::GetEntryType(
116 Out<u32> out_type, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
117 LOG_DEBUG(Service_FS, "called. file={}", path->str);
167 118
168 FileSys::DirectoryEntryType vfs_entry_type{}; 119 FileSys::DirectoryEntryType vfs_entry_type{};
169 auto result = backend.GetEntryType(&vfs_entry_type, name); 120 R_TRY(backend->GetEntryType(&vfs_entry_type, FileSys::Path(path->str)));
170 if (result != ResultSuccess) { 121
171 IPC::ResponseBuilder rb{ctx, 2}; 122 *out_type = static_cast<u32>(vfs_entry_type);
172 rb.Push(result); 123 R_SUCCEED();
173 return;
174 }
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push<u32>(static_cast<u32>(vfs_entry_type));
179} 124}
180 125
181void IFileSystem::Commit(HLERequestContext& ctx) { 126Result IFileSystem::Commit() {
182 LOG_WARNING(Service_FS, "(STUBBED) called"); 127 LOG_WARNING(Service_FS, "(STUBBED) called");
183 128
184 IPC::ResponseBuilder rb{ctx, 2}; 129 R_SUCCEED();
185 rb.Push(ResultSuccess);
186} 130}
187 131
188void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { 132Result IFileSystem::GetFreeSpaceSize(
133 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
189 LOG_DEBUG(Service_FS, "called"); 134 LOG_DEBUG(Service_FS, "called");
190 135
191 IPC::ResponseBuilder rb{ctx, 4}; 136 *out_size = size_getter.get_free_size();
192 rb.Push(ResultSuccess); 137 R_SUCCEED();
193 rb.Push(size.get_free_size());
194} 138}
195 139
196void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { 140Result IFileSystem::GetTotalSpaceSize(
141 Out<s64> out_size, const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
197 LOG_DEBUG(Service_FS, "called"); 142 LOG_DEBUG(Service_FS, "called");
198 143
199 IPC::ResponseBuilder rb{ctx, 4}; 144 *out_size = size_getter.get_total_size();
200 rb.Push(ResultSuccess); 145 R_SUCCEED();
201 rb.Push(size.get_total_size());
202} 146}
203 147
204void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { 148Result IFileSystem::GetFileTimeStampRaw(
205 const auto file_buffer = ctx.ReadBuffer(); 149 Out<FileSys::FileTimeStampRaw> out_timestamp,
206 const std::string name = Common::StringFromBuffer(file_buffer); 150 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path) {
207 151 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", path->str);
208 LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
209 152
210 FileSys::FileTimeStampRaw vfs_timestamp{}; 153 FileSys::FileTimeStampRaw vfs_timestamp{};
211 auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); 154 R_TRY(backend->GetFileTimeStampRaw(&vfs_timestamp, FileSys::Path(path->str)));
212 if (result != ResultSuccess) { 155
213 IPC::ResponseBuilder rb{ctx, 2}; 156 *out_timestamp = vfs_timestamp;
214 rb.Push(result); 157 R_SUCCEED();
215 return;
216 }
217
218 IPC::ResponseBuilder rb{ctx, 10};
219 rb.Push(ResultSuccess);
220 rb.PushRaw(vfs_timestamp);
221} 158}
222 159
223void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { 160Result IFileSystem::GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute) {
224 LOG_WARNING(Service_FS, "(STUBBED) called"); 161 LOG_WARNING(Service_FS, "(STUBBED) called");
225 162
226 struct FileSystemAttribute { 163 FileSys::FileSystemAttribute savedata_attribute{};
227 u8 dir_entry_name_length_max_defined;
228 u8 file_entry_name_length_max_defined;
229 u8 dir_path_name_length_max_defined;
230 u8 file_path_name_length_max_defined;
231 INSERT_PADDING_BYTES_NOINIT(0x5);
232 u8 utf16_dir_entry_name_length_max_defined;
233 u8 utf16_file_entry_name_length_max_defined;
234 u8 utf16_dir_path_name_length_max_defined;
235 u8 utf16_file_path_name_length_max_defined;
236 INSERT_PADDING_BYTES_NOINIT(0x18);
237 s32 dir_entry_name_length_max;
238 s32 file_entry_name_length_max;
239 s32 dir_path_name_length_max;
240 s32 file_path_name_length_max;
241 INSERT_PADDING_WORDS_NOINIT(0x5);
242 s32 utf16_dir_entry_name_length_max;
243 s32 utf16_file_entry_name_length_max;
244 s32 utf16_dir_path_name_length_max;
245 s32 utf16_file_path_name_length_max;
246 INSERT_PADDING_WORDS_NOINIT(0x18);
247 INSERT_PADDING_WORDS_NOINIT(0x1);
248 };
249 static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
250
251 FileSystemAttribute savedata_attribute{};
252 savedata_attribute.dir_entry_name_length_max_defined = true; 164 savedata_attribute.dir_entry_name_length_max_defined = true;
253 savedata_attribute.file_entry_name_length_max_defined = true; 165 savedata_attribute.file_entry_name_length_max_defined = true;
254 savedata_attribute.dir_entry_name_length_max = 0x40; 166 savedata_attribute.dir_entry_name_length_max = 0x40;
255 savedata_attribute.file_entry_name_length_max = 0x40; 167 savedata_attribute.file_entry_name_length_max = 0x40;
256 168
257 IPC::ResponseBuilder rb{ctx, 50}; 169 *out_attribute = savedata_attribute;
258 rb.Push(ResultSuccess); 170 R_SUCCEED();
259 rb.PushRaw(savedata_attribute);
260} 171}
261 172
262} // namespace Service::FileSystem 173} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
index b06b3ef0e..dd069f36f 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -3,36 +3,58 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h"
7#include "core/file_sys/fs_filesystem.h"
8#include "core/file_sys/fsa/fs_i_filesystem.h"
6#include "core/file_sys/vfs/vfs.h" 9#include "core/file_sys/vfs/vfs.h"
10#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 11#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/filesystem/fsp/fsp_util.h" 12#include "core/hle/service/filesystem/fsp/fsp_types.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
10 14
15namespace FileSys::Sf {
16struct Path;
17}
18
11namespace Service::FileSystem { 19namespace Service::FileSystem {
12 20
21class IFile;
22class IDirectory;
23
13class IFileSystem final : public ServiceFramework<IFileSystem> { 24class IFileSystem final : public ServiceFramework<IFileSystem> {
14public: 25public:
15 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); 26 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir dir_, SizeGetter size_getter_);
16 27
17 void CreateFile(HLERequestContext& ctx); 28 Result CreateFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, s32 option,
18 void DeleteFile(HLERequestContext& ctx); 29 s64 size);
19 void CreateDirectory(HLERequestContext& ctx); 30 Result DeleteFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
20 void DeleteDirectory(HLERequestContext& ctx); 31 Result CreateDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
21 void DeleteDirectoryRecursively(HLERequestContext& ctx); 32 Result DeleteDirectory(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
22 void CleanDirectoryRecursively(HLERequestContext& ctx); 33 Result DeleteDirectoryRecursively(
23 void RenameFile(HLERequestContext& ctx); 34 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
24 void OpenFile(HLERequestContext& ctx); 35 Result CleanDirectoryRecursively(
25 void OpenDirectory(HLERequestContext& ctx); 36 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
26 void GetEntryType(HLERequestContext& ctx); 37 Result RenameFile(const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> old_path,
27 void Commit(HLERequestContext& ctx); 38 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> new_path);
28 void GetFreeSpaceSize(HLERequestContext& ctx); 39 Result OpenFile(OutInterface<IFile> out_interface,
29 void GetTotalSpaceSize(HLERequestContext& ctx); 40 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path, u32 mode);
30 void GetFileTimeStampRaw(HLERequestContext& ctx); 41 Result OpenDirectory(OutInterface<IDirectory> out_interface,
31 void GetFileSystemAttribute(HLERequestContext& ctx); 42 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path,
43 u32 mode);
44 Result GetEntryType(Out<u32> out_type,
45 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
46 Result Commit();
47 Result GetFreeSpaceSize(Out<s64> out_size,
48 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
49 Result GetTotalSpaceSize(Out<s64> out_size,
50 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
51 Result GetFileTimeStampRaw(Out<FileSys::FileTimeStampRaw> out_timestamp,
52 const InLargeData<FileSys::Sf::Path, BufferAttr_HipcPointer> path);
53 Result GetFileSystemAttribute(Out<FileSys::FileSystemAttribute> out_attribute);
32 54
33private: 55private:
34 VfsDirectoryServiceWrapper backend; 56 std::unique_ptr<FileSys::Fsa::IFileSystem> backend;
35 SizeGetter size; 57 SizeGetter size_getter;
36}; 58};
37 59
38} // namespace Service::FileSystem 60} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
new file mode 100644
index 000000000..626328234
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
6#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
7
8namespace Service::FileSystem {
9
10IMultiCommitManager::IMultiCommitManager(Core::System& system_)
11 : ServiceFramework{system_, "IMultiCommitManager"} {
12 static const FunctionInfo functions[] = {
13 {1, D<&IMultiCommitManager::Add>, "Add"},
14 {2, D<&IMultiCommitManager::Commit>, "Commit"},
15 };
16 RegisterHandlers(functions);
17}
18
19IMultiCommitManager::~IMultiCommitManager() = default;
20
21Result IMultiCommitManager::Add(std::shared_ptr<IFileSystem> filesystem) {
22 LOG_WARNING(Service_FS, "(STUBBED) called");
23
24 R_SUCCEED();
25}
26
27Result IMultiCommitManager::Commit() {
28 LOG_WARNING(Service_FS, "(STUBBED) called");
29
30 R_SUCCEED();
31}
32
33} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
new file mode 100644
index 000000000..8ebf7c7d9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/service.h"
8
9namespace Service::FileSystem {
10
11class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
12public:
13 explicit IMultiCommitManager(Core::System& system_);
14 ~IMultiCommitManager() override;
15
16private:
17 Result Add(std::shared_ptr<IFileSystem> filesystem);
18 Result Commit();
19
20 FileSys::VirtualFile backend;
21};
22
23} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
new file mode 100644
index 000000000..ff823586b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
@@ -0,0 +1,161 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/hex_util.h"
5#include "core/file_sys/savedata_factory.h"
6#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
8#include "core/hle/service/filesystem/save_data_controller.h"
9
10namespace Service::FileSystem {
11
12ISaveDataInfoReader::ISaveDataInfoReader(Core::System& system_,
13 std::shared_ptr<SaveDataController> save_data_controller_,
14 FileSys::SaveDataSpaceId space)
15 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
16 save_data_controller_} {
17 static const FunctionInfo functions[] = {
18 {0, D<&ISaveDataInfoReader::ReadSaveDataInfo>, "ReadSaveDataInfo"},
19 };
20 RegisterHandlers(functions);
21
22 FindAllSaves(space);
23}
24
25ISaveDataInfoReader::~ISaveDataInfoReader() = default;
26
27static u64 stoull_be(std::string_view str) {
28 if (str.size() != 16) {
29 return 0;
30 }
31
32 const auto bytes = Common::HexStringToArray<0x8>(str);
33 u64 out{};
34 std::memcpy(&out, bytes.data(), sizeof(u64));
35
36 return Common::swap64(out);
37}
38
39Result ISaveDataInfoReader::ReadSaveDataInfo(
40 Out<u64> out_count, OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries) {
41 LOG_DEBUG(Service_FS, "called");
42
43 // Calculate how many entries we can fit in the output buffer
44 const u64 count_entries = out_entries.size();
45
46 // Cap at total number of entries.
47 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
48
49 // Determine data start and end
50 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
51 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
52 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
53
54 next_entry_index += actual_entries;
55
56 // Write the data to memory
57 std::memcpy(out_entries.data(), begin, range_size);
58 *out_count = actual_entries;
59
60 R_SUCCEED();
61}
62
63void ISaveDataInfoReader::FindAllSaves(FileSys::SaveDataSpaceId space) {
64 FileSys::VirtualDir save_root{};
65 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
66
67 if (result != ResultSuccess || save_root == nullptr) {
68 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
69 return;
70 }
71
72 for (const auto& type : save_root->GetSubdirectories()) {
73 if (type->GetName() == "save") {
74 FindNormalSaves(space, type);
75 } else if (space == FileSys::SaveDataSpaceId::Temporary) {
76 FindTemporaryStorageSaves(space, type);
77 }
78 }
79}
80
81void ISaveDataInfoReader::FindNormalSaves(FileSys::SaveDataSpaceId space,
82 const FileSys::VirtualDir& type) {
83 for (const auto& save_id : type->GetSubdirectories()) {
84 for (const auto& user_id : save_id->GetSubdirectories()) {
85 // Skip non user id subdirectories
86 if (user_id->GetName().size() != 0x20) {
87 continue;
88 }
89
90 const auto save_id_numeric = stoull_be(save_id->GetName());
91 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
92 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
93
94 if (save_id_numeric != 0) {
95 // System Save Data
96 info.emplace_back(SaveDataInfo{
97 0,
98 space,
99 FileSys::SaveDataType::System,
100 {},
101 user_id_numeric,
102 save_id_numeric,
103 0,
104 user_id->GetSize(),
105 {},
106 {},
107 });
108
109 continue;
110 }
111
112 for (const auto& title_id : user_id->GetSubdirectories()) {
113 const auto device = std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
114 [](u8 val) { return val == 0; });
115 info.emplace_back(SaveDataInfo{
116 0,
117 space,
118 device ? FileSys::SaveDataType::Device : FileSys::SaveDataType::Account,
119 {},
120 user_id_numeric,
121 save_id_numeric,
122 stoull_be(title_id->GetName()),
123 title_id->GetSize(),
124 {},
125 {},
126 });
127 }
128 }
129 }
130}
131
132void ISaveDataInfoReader::FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space,
133 const FileSys::VirtualDir& type) {
134 for (const auto& user_id : type->GetSubdirectories()) {
135 // Skip non user id subdirectories
136 if (user_id->GetName().size() != 0x20) {
137 continue;
138 }
139 for (const auto& title_id : user_id->GetSubdirectories()) {
140 if (!title_id->GetFiles().empty() || !title_id->GetSubdirectories().empty()) {
141 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
142 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
143
144 info.emplace_back(SaveDataInfo{
145 0,
146 space,
147 FileSys::SaveDataType::Temporary,
148 {},
149 user_id_numeric,
150 stoull_be(type->GetName()),
151 stoull_be(title_id->GetName()),
152 title_id->GetSize(),
153 {},
154 {},
155 });
156 }
157 }
158 }
159}
160
161} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
new file mode 100644
index 000000000..e45ad852b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <vector>
7#include "common/common_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/service.h"
10
11namespace Service::FileSystem {
12
13class SaveDataController;
14
15class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
16public:
17 explicit ISaveDataInfoReader(Core::System& system_,
18 std::shared_ptr<SaveDataController> save_data_controller_,
19 FileSys::SaveDataSpaceId space);
20 ~ISaveDataInfoReader() override;
21
22 struct SaveDataInfo {
23 u64_le save_id_unknown;
24 FileSys::SaveDataSpaceId space;
25 FileSys::SaveDataType type;
26 INSERT_PADDING_BYTES(0x6);
27 std::array<u8, 0x10> user_id;
28 u64_le save_id;
29 u64_le title_id;
30 u64_le save_image_size;
31 u16_le index;
32 FileSys::SaveDataRank rank;
33 INSERT_PADDING_BYTES(0x25);
34 };
35 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
36
37 Result ReadSaveDataInfo(Out<u64> out_count,
38 OutArray<SaveDataInfo, BufferAttr_HipcMapAlias> out_entries);
39
40private:
41 void FindAllSaves(FileSys::SaveDataSpaceId space);
42 void FindNormalSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
43 void FindTemporaryStorageSaves(FileSys::SaveDataSpaceId space, const FileSys::VirtualDir& type);
44
45 std::shared_ptr<SaveDataController> save_data_controller;
46 std::vector<SaveDataInfo> info;
47 u64 next_entry_index = 0;
48};
49
50} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
index 98223c1f9..213f19808 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -2,61 +2,44 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/file_sys/errors.h" 4#include "core/file_sys/errors.h"
5#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 6#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
6#include "core/hle/service/ipc_helpers.h"
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) 10IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { 11 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &IStorage::Read, "Read"}, 13 {0, D<&IStorage::Read>, "Read"},
14 {1, nullptr, "Write"}, 14 {1, nullptr, "Write"},
15 {2, nullptr, "Flush"}, 15 {2, nullptr, "Flush"},
16 {3, nullptr, "SetSize"}, 16 {3, nullptr, "SetSize"},
17 {4, &IStorage::GetSize, "GetSize"}, 17 {4, D<&IStorage::GetSize>, "GetSize"},
18 {5, nullptr, "OperateRange"}, 18 {5, nullptr, "OperateRange"},
19 }; 19 };
20 RegisterHandlers(functions); 20 RegisterHandlers(functions);
21} 21}
22 22
23void IStorage::Read(HLERequestContext& ctx) { 23Result IStorage::Read(
24 IPC::RequestParser rp{ctx}; 24 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
25 const s64 offset = rp.Pop<s64>(); 25 s64 offset, s64 length) {
26 const s64 length = rp.Pop<s64>();
27
28 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); 26 LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
29 27
30 // Error checking 28 R_UNLESS(length >= 0, FileSys::ResultInvalidSize);
31 if (length < 0) { 29 R_UNLESS(offset >= 0, FileSys::ResultInvalidOffset);
32 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
33 IPC::ResponseBuilder rb{ctx, 2};
34 rb.Push(FileSys::ResultInvalidSize);
35 return;
36 }
37 if (offset < 0) {
38 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(FileSys::ResultInvalidOffset);
41 return;
42 }
43 30
44 // Read the data from the Storage backend 31 // Read the data from the Storage backend
45 std::vector<u8> output = backend->ReadBytes(length, offset); 32 backend->Read(out_bytes.data(), length, offset);
46 // Write the data to memory
47 ctx.WriteBuffer(output);
48 33
49 IPC::ResponseBuilder rb{ctx, 2}; 34 R_SUCCEED();
50 rb.Push(ResultSuccess);
51} 35}
52 36
53void IStorage::GetSize(HLERequestContext& ctx) { 37Result IStorage::GetSize(Out<u64> out_size) {
54 const u64 size = backend->GetSize(); 38 *out_size = backend->GetSize();
55 LOG_DEBUG(Service_FS, "called, size={}", size); 39
40 LOG_DEBUG(Service_FS, "called, size={}", *out_size);
56 41
57 IPC::ResponseBuilder rb{ctx, 4}; 42 R_SUCCEED();
58 rb.Push(ResultSuccess);
59 rb.Push<u64>(size);
60} 43}
61 44
62} // namespace Service::FileSystem 45} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
index cb5bebcc9..74d879386 100644
--- a/src/core/hle/service/filesystem/fsp/fs_i_storage.h
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "core/file_sys/vfs/vfs.h" 6#include "core/file_sys/vfs/vfs.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/filesystem/filesystem.h" 8#include "core/hle/service/filesystem/filesystem.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
@@ -16,8 +17,10 @@ public:
16private: 17private:
17 FileSys::VirtualFile backend; 18 FileSys::VirtualFile backend;
18 19
19 void Read(HLERequestContext& ctx); 20 Result Read(
20 void GetSize(HLERequestContext& ctx); 21 OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_bytes,
22 s64 offset, s64 length);
23 Result GetSize(Out<u64> out_size);
21}; 24};
22 25
23} // namespace Service::FileSystem 26} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
index 2d49f30c8..223284255 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -27,10 +27,14 @@
27#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
28#include "core/file_sys/vfs/vfs.h" 28#include "core/file_sys/vfs/vfs.h"
29#include "core/hle/result.h" 29#include "core/hle/result.h"
30#include "core/hle/service/cmif_serialization.h"
30#include "core/hle/service/filesystem/filesystem.h" 31#include "core/hle/service/filesystem/filesystem.h"
31#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" 32#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
33#include "core/hle/service/filesystem/fsp/fs_i_multi_commit_manager.h"
34#include "core/hle/service/filesystem/fsp/fs_i_save_data_info_reader.h"
32#include "core/hle/service/filesystem/fsp/fs_i_storage.h" 35#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
33#include "core/hle/service/filesystem/fsp/fsp_srv.h" 36#include "core/hle/service/filesystem/fsp/fsp_srv.h"
37#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
34#include "core/hle/service/filesystem/romfs_controller.h" 38#include "core/hle/service/filesystem/romfs_controller.h"
35#include "core/hle/service/filesystem/save_data_controller.h" 39#include "core/hle/service/filesystem/save_data_controller.h"
36#include "core/hle/service/hle_ipc.h" 40#include "core/hle/service/hle_ipc.h"
@@ -39,182 +43,6 @@
39#include "core/reporter.h" 43#include "core/reporter.h"
40 44
41namespace Service::FileSystem { 45namespace Service::FileSystem {
42enum class FileSystemProxyType : u8 {
43 Code = 0,
44 Rom = 1,
45 Logo = 2,
46 Control = 3,
47 Manual = 4,
48 Meta = 5,
49 Data = 6,
50 Package = 7,
51 RegisteredUpdate = 8,
52};
53
54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
55public:
56 explicit ISaveDataInfoReader(Core::System& system_,
57 std::shared_ptr<SaveDataController> save_data_controller_,
58 FileSys::SaveDataSpaceId space)
59 : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
60 save_data_controller_} {
61 static const FunctionInfo functions[] = {
62 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
63 };
64 RegisterHandlers(functions);
65
66 FindAllSaves(space);
67 }
68
69 void ReadSaveDataInfo(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_FS, "called");
71
72 // Calculate how many entries we can fit in the output buffer
73 const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
74
75 // Cap at total number of entries.
76 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
77
78 // Determine data start and end
79 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
80 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
81 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
82
83 next_entry_index += actual_entries;
84
85 // Write the data to memory
86 ctx.WriteBuffer(begin, range_size);
87
88 IPC::ResponseBuilder rb{ctx, 4};
89 rb.Push(ResultSuccess);
90 rb.Push<u64>(actual_entries);
91 }
92
93private:
94 static u64 stoull_be(std::string_view str) {
95 if (str.size() != 16)
96 return 0;
97
98 const auto bytes = Common::HexStringToArray<0x8>(str);
99 u64 out{};
100 std::memcpy(&out, bytes.data(), sizeof(u64));
101
102 return Common::swap64(out);
103 }
104
105 void FindAllSaves(FileSys::SaveDataSpaceId space) {
106 FileSys::VirtualDir save_root{};
107 const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
108
109 if (result != ResultSuccess || save_root == nullptr) {
110 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
111 return;
112 }
113
114 for (const auto& type : save_root->GetSubdirectories()) {
115 if (type->GetName() == "save") {
116 for (const auto& save_id : type->GetSubdirectories()) {
117 for (const auto& user_id : save_id->GetSubdirectories()) {
118 // Skip non user id subdirectories
119 if (user_id->GetName().size() != 0x20) {
120 continue;
121 }
122
123 const auto save_id_numeric = stoull_be(save_id->GetName());
124 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
125 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
126
127 if (save_id_numeric != 0) {
128 // System Save Data
129 info.emplace_back(SaveDataInfo{
130 0,
131 space,
132 FileSys::SaveDataType::SystemSaveData,
133 {},
134 user_id_numeric,
135 save_id_numeric,
136 0,
137 user_id->GetSize(),
138 {},
139 {},
140 });
141
142 continue;
143 }
144
145 for (const auto& title_id : user_id->GetSubdirectories()) {
146 const auto device =
147 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
148 [](u8 val) { return val == 0; });
149 info.emplace_back(SaveDataInfo{
150 0,
151 space,
152 device ? FileSys::SaveDataType::DeviceSaveData
153 : FileSys::SaveDataType::SaveData,
154 {},
155 user_id_numeric,
156 save_id_numeric,
157 stoull_be(title_id->GetName()),
158 title_id->GetSize(),
159 {},
160 {},
161 });
162 }
163 }
164 }
165 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
166 // Temporary Storage
167 for (const auto& user_id : type->GetSubdirectories()) {
168 // Skip non user id subdirectories
169 if (user_id->GetName().size() != 0x20) {
170 continue;
171 }
172 for (const auto& title_id : user_id->GetSubdirectories()) {
173 if (!title_id->GetFiles().empty() ||
174 !title_id->GetSubdirectories().empty()) {
175 auto user_id_numeric =
176 Common::HexStringToArray<0x10>(user_id->GetName());
177 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
178
179 info.emplace_back(SaveDataInfo{
180 0,
181 space,
182 FileSys::SaveDataType::TemporaryStorage,
183 {},
184 user_id_numeric,
185 stoull_be(type->GetName()),
186 stoull_be(title_id->GetName()),
187 title_id->GetSize(),
188 {},
189 {},
190 });
191 }
192 }
193 }
194 }
195 }
196 }
197
198 struct SaveDataInfo {
199 u64_le save_id_unknown;
200 FileSys::SaveDataSpaceId space;
201 FileSys::SaveDataType type;
202 INSERT_PADDING_BYTES(0x6);
203 std::array<u8, 0x10> user_id;
204 u64_le save_id;
205 u64_le title_id;
206 u64_le save_image_size;
207 u16_le index;
208 FileSys::SaveDataRank rank;
209 INSERT_PADDING_BYTES(0x25);
210 };
211 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
212
213 ProcessId process_id = 0;
214 std::shared_ptr<SaveDataController> save_data_controller;
215 std::vector<SaveDataInfo> info;
216 u64 next_entry_index = 0;
217};
218 46
219FSP_SRV::FSP_SRV(Core::System& system_) 47FSP_SRV::FSP_SRV(Core::System& system_)
220 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, 48 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
@@ -222,20 +50,20 @@ FSP_SRV::FSP_SRV(Core::System& system_)
222 // clang-format off 50 // clang-format off
223 static const FunctionInfo functions[] = { 51 static const FunctionInfo functions[] = {
224 {0, nullptr, "OpenFileSystem"}, 52 {0, nullptr, "OpenFileSystem"},
225 {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, 53 {1, D<&FSP_SRV::SetCurrentProcess>, "SetCurrentProcess"},
226 {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, 54 {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
227 {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, 55 {7, D<&FSP_SRV::OpenFileSystemWithPatch>, "OpenFileSystemWithPatch"},
228 {8, nullptr, "OpenFileSystemWithId"}, 56 {8, nullptr, "OpenFileSystemWithId"},
229 {9, nullptr, "OpenDataFileSystemByApplicationId"}, 57 {9, nullptr, "OpenDataFileSystemByApplicationId"},
230 {11, nullptr, "OpenBisFileSystem"}, 58 {11, nullptr, "OpenBisFileSystem"},
231 {12, nullptr, "OpenBisStorage"}, 59 {12, nullptr, "OpenBisStorage"},
232 {13, nullptr, "InvalidateBisCache"}, 60 {13, nullptr, "InvalidateBisCache"},
233 {17, nullptr, "OpenHostFileSystem"}, 61 {17, nullptr, "OpenHostFileSystem"},
234 {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, 62 {18, D<&FSP_SRV::OpenSdCardFileSystem>, "OpenSdCardFileSystem"},
235 {19, nullptr, "FormatSdCardFileSystem"}, 63 {19, nullptr, "FormatSdCardFileSystem"},
236 {21, nullptr, "DeleteSaveDataFileSystem"}, 64 {21, nullptr, "DeleteSaveDataFileSystem"},
237 {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, 65 {22, D<&FSP_SRV::CreateSaveDataFileSystem>, "CreateSaveDataFileSystem"},
238 {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, 66 {23, D<&FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId>, "CreateSaveDataFileSystemBySystemSaveDataId"},
239 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, 67 {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
240 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, 68 {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
241 {26, nullptr, "FormatSdCardDryRun"}, 69 {26, nullptr, "FormatSdCardDryRun"},
@@ -245,30 +73,30 @@ FSP_SRV::FSP_SRV(Core::System& system_)
245 {31, nullptr, "OpenGameCardFileSystem"}, 73 {31, nullptr, "OpenGameCardFileSystem"},
246 {32, nullptr, "ExtendSaveDataFileSystem"}, 74 {32, nullptr, "ExtendSaveDataFileSystem"},
247 {33, nullptr, "DeleteCacheStorage"}, 75 {33, nullptr, "DeleteCacheStorage"},
248 {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, 76 {34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
249 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, 77 {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
250 {36, nullptr, "OpenHostFileSystemWithOption"}, 78 {36, nullptr, "OpenHostFileSystemWithOption"},
251 {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, 79 {51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
252 {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, 80 {52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
253 {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, 81 {53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
254 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, 82 {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
255 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 83 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
256 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 84 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
257 {60, nullptr, "OpenSaveDataInfoReader"}, 85 {60, nullptr, "OpenSaveDataInfoReader"},
258 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 86 {61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
259 {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, 87 {62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
260 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 88 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
261 {65, nullptr, "UpdateSaveDataMacForDebug"}, 89 {65, nullptr, "UpdateSaveDataMacForDebug"},
262 {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, 90 {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
263 {67, nullptr, "FindSaveDataWithFilter"}, 91 {67, D<&FSP_SRV::FindSaveDataWithFilter>, "FindSaveDataWithFilter"},
264 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, 92 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
265 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, 93 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
266 {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, 94 {70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
267 {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, 95 {71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
268 {80, nullptr, "OpenSaveDataMetaFile"}, 96 {80, nullptr, "OpenSaveDataMetaFile"},
269 {81, nullptr, "OpenSaveDataTransferManager"}, 97 {81, nullptr, "OpenSaveDataTransferManager"},
270 {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, 98 {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
271 {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"}, 99 {83, D<&FSP_SRV::OpenSaveDataTransferProhibiter>, "OpenSaveDataTransferProhibiter"},
272 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, 100 {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
273 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, 101 {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
274 {86, nullptr, "OpenSaveDataMover"}, 102 {86, nullptr, "OpenSaveDataMover"},
@@ -279,12 +107,12 @@ FSP_SRV::FSP_SRV(Core::System& system_)
279 {110, nullptr, "OpenContentStorageFileSystem"}, 107 {110, nullptr, "OpenContentStorageFileSystem"},
280 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, 108 {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
281 {130, nullptr, "OpenCustomStorageFileSystem"}, 109 {130, nullptr, "OpenCustomStorageFileSystem"},
282 {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, 110 {200, D<&FSP_SRV::OpenDataStorageByCurrentProcess>, "OpenDataStorageByCurrentProcess"},
283 {201, nullptr, "OpenDataStorageByProgramId"}, 111 {201, nullptr, "OpenDataStorageByProgramId"},
284 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, 112 {202, D<&FSP_SRV::OpenDataStorageByDataId>, "OpenDataStorageByDataId"},
285 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, 113 {203, D<&FSP_SRV::OpenPatchDataStorageByCurrentProcess>, "OpenPatchDataStorageByCurrentProcess"},
286 {204, nullptr, "OpenDataFileSystemByProgramIndex"}, 114 {204, nullptr, "OpenDataFileSystemByProgramIndex"},
287 {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, 115 {205, D<&FSP_SRV::OpenDataStorageWithProgramIndex>, "OpenDataStorageWithProgramIndex"},
288 {206, nullptr, "OpenDataStorageByPath"}, 116 {206, nullptr, "OpenDataStorageByPath"},
289 {400, nullptr, "OpenDeviceOperator"}, 117 {400, nullptr, "OpenDeviceOperator"},
290 {500, nullptr, "OpenSdCardDetectionEventNotifier"}, 118 {500, nullptr, "OpenSdCardDetectionEventNotifier"},
@@ -324,25 +152,25 @@ FSP_SRV::FSP_SRV(Core::System& system_)
324 {1000, nullptr, "SetBisRootForHost"}, 152 {1000, nullptr, "SetBisRootForHost"},
325 {1001, nullptr, "SetSaveDataSize"}, 153 {1001, nullptr, "SetSaveDataSize"},
326 {1002, nullptr, "SetSaveDataRootPath"}, 154 {1002, nullptr, "SetSaveDataRootPath"},
327 {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, 155 {1003, D<&FSP_SRV::DisableAutoSaveDataCreation>, "DisableAutoSaveDataCreation"},
328 {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, 156 {1004, D<&FSP_SRV::SetGlobalAccessLogMode>, "SetGlobalAccessLogMode"},
329 {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, 157 {1005, D<&FSP_SRV::GetGlobalAccessLogMode>, "GetGlobalAccessLogMode"},
330 {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, 158 {1006, D<&FSP_SRV::OutputAccessLogToSdCard>, "OutputAccessLogToSdCard"},
331 {1007, nullptr, "RegisterUpdatePartition"}, 159 {1007, nullptr, "RegisterUpdatePartition"},
332 {1008, nullptr, "OpenRegisteredUpdatePartition"}, 160 {1008, nullptr, "OpenRegisteredUpdatePartition"},
333 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 161 {1009, nullptr, "GetAndClearMemoryReportInfo"},
334 {1010, nullptr, "SetDataStorageRedirectTarget"}, 162 {1010, nullptr, "SetDataStorageRedirectTarget"},
335 {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, 163 {1011, D<&FSP_SRV::GetProgramIndexForAccessLog>, "GetProgramIndexForAccessLog"},
336 {1012, nullptr, "GetFsStackUsage"}, 164 {1012, nullptr, "GetFsStackUsage"},
337 {1013, nullptr, "UnsetSaveDataRootPath"}, 165 {1013, nullptr, "UnsetSaveDataRootPath"},
338 {1014, nullptr, "OutputMultiProgramTagAccessLog"}, 166 {1014, nullptr, "OutputMultiProgramTagAccessLog"},
339 {1016, &FSP_SRV::FlushAccessLogOnSdCard, "FlushAccessLogOnSdCard"}, 167 {1016, D<&FSP_SRV::FlushAccessLogOnSdCard>, "FlushAccessLogOnSdCard"},
340 {1017, nullptr, "OutputApplicationInfoAccessLog"}, 168 {1017, nullptr, "OutputApplicationInfoAccessLog"},
341 {1018, nullptr, "SetDebugOption"}, 169 {1018, nullptr, "SetDebugOption"},
342 {1019, nullptr, "UnsetDebugOption"}, 170 {1019, nullptr, "UnsetDebugOption"},
343 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 171 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
344 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, 172 {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
345 {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, 173 {1200, D<&FSP_SRV::OpenMultiCommitManager>, "OpenMultiCommitManager"},
346 {1300, nullptr, "OpenBisWiper"}, 174 {1300, nullptr, "OpenBisWiper"},
347 }; 175 };
348 // clang-format on 176 // clang-format on
@@ -355,234 +183,192 @@ FSP_SRV::FSP_SRV(Core::System& system_)
355 183
356FSP_SRV::~FSP_SRV() = default; 184FSP_SRV::~FSP_SRV() = default;
357 185
358void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { 186Result FSP_SRV::SetCurrentProcess(ClientProcessId pid) {
359 current_process_id = ctx.GetPID(); 187 current_process_id = *pid;
360 188
361 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); 189 LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
362 190
363 const auto res = 191 R_RETURN(
364 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); 192 fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id));
365
366 IPC::ResponseBuilder rb{ctx, 2};
367 rb.Push(res);
368} 193}
369 194
370void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 195Result FSP_SRV::OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
371 IPC::RequestParser rp{ctx}; 196 FileSystemProxyType type, u64 open_program_id) {
372 197 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", type,
373 struct InputParameters { 198 open_program_id);
374 FileSystemProxyType type;
375 u64 program_id;
376 };
377 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
378
379 const auto params = rp.PopRaw<InputParameters>();
380 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
381 params.program_id);
382 199
383 // FIXME: many issues with this 200 // FIXME: many issues with this
384 ASSERT(params.type == FileSystemProxyType::Manual); 201 ASSERT(type == FileSystemProxyType::Manual);
385 const auto manual_romfs = romfs_controller->OpenPatchedRomFS( 202 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
386 params.program_id, FileSys::ContentRecordType::HtmlDocument); 203 open_program_id, FileSys::ContentRecordType::HtmlDocument);
387 204
388 ASSERT(manual_romfs != nullptr); 205 ASSERT(manual_romfs != nullptr);
389 206
390 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs); 207 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
391 ASSERT(extracted_romfs != nullptr); 208 ASSERT(extracted_romfs != nullptr);
392 209
393 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 210 *out_interface = std::make_shared<IFileSystem>(
394 rb.Push(ResultSuccess); 211 system, extracted_romfs, SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
395 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs, 212
396 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser)); 213 R_SUCCEED();
397} 214}
398 215
399void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 216Result FSP_SRV::OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface) {
400 LOG_DEBUG(Service_FS, "called"); 217 LOG_DEBUG(Service_FS, "called");
401 218
402 FileSys::VirtualDir sdmc_dir{}; 219 FileSys::VirtualDir sdmc_dir{};
403 fsc.OpenSDMC(&sdmc_dir); 220 fsc.OpenSDMC(&sdmc_dir);
404 221
405 auto filesystem = std::make_shared<IFileSystem>( 222 *out_interface = std::make_shared<IFileSystem>(
406 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 223 system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
407 224
408 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 225 R_SUCCEED();
409 rb.Push(ResultSuccess);
410 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
411} 226}
412 227
413void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { 228Result FSP_SRV::CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
414 IPC::RequestParser rp{ctx}; 229 FileSys::SaveDataAttribute save_struct, u128 uid) {
415
416 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
417 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
418 u128 uid = rp.PopRaw<u128>();
419
420 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), 230 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
421 uid[1], uid[0]); 231 uid[1], uid[0]);
422 232
423 FileSys::VirtualDir save_data_dir{}; 233 FileSys::VirtualDir save_data_dir{};
424 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, 234 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::User,
425 save_struct); 235 save_struct));
426
427 IPC::ResponseBuilder rb{ctx, 2};
428 rb.Push(ResultSuccess);
429} 236}
430 237
431void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 238Result FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(
432 IPC::RequestParser rp{ctx}; 239 FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct) {
433
434 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
435 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
436
437 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); 240 LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
438 241
439 FileSys::VirtualDir save_data_dir{}; 242 FileSys::VirtualDir save_data_dir{};
440 save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, 243 R_RETURN(save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::System,
441 save_struct); 244 save_struct));
442
443 IPC::ResponseBuilder rb{ctx, 2};
444 rb.Push(ResultSuccess);
445} 245}
446 246
447void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { 247Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
448 IPC::RequestParser rp{ctx}; 248 FileSys::SaveDataSpaceId space_id,
449 249 FileSys::SaveDataAttribute attribute) {
450 struct Parameters {
451 FileSys::SaveDataSpaceId space_id;
452 FileSys::SaveDataAttribute attribute;
453 };
454
455 const auto parameters = rp.PopRaw<Parameters>();
456
457 LOG_INFO(Service_FS, "called."); 250 LOG_INFO(Service_FS, "called.");
458 251
459 FileSys::VirtualDir dir{}; 252 FileSys::VirtualDir dir{};
460 auto result = 253 R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
461 save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
462 if (result != ResultSuccess) {
463 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
464 rb.Push(FileSys::ResultTargetNotFound);
465 return;
466 }
467 254
468 FileSys::StorageId id{}; 255 FileSys::StorageId id{};
469 switch (parameters.space_id) { 256 switch (space_id) {
470 case FileSys::SaveDataSpaceId::NandUser: 257 case FileSys::SaveDataSpaceId::User:
471 id = FileSys::StorageId::NandUser; 258 id = FileSys::StorageId::NandUser;
472 break; 259 break;
473 case FileSys::SaveDataSpaceId::SdCardSystem: 260 case FileSys::SaveDataSpaceId::SdSystem:
474 case FileSys::SaveDataSpaceId::SdCardUser: 261 case FileSys::SaveDataSpaceId::SdUser:
475 id = FileSys::StorageId::SdCard; 262 id = FileSys::StorageId::SdCard;
476 break; 263 break;
477 case FileSys::SaveDataSpaceId::NandSystem: 264 case FileSys::SaveDataSpaceId::System:
478 id = FileSys::StorageId::NandSystem; 265 id = FileSys::StorageId::NandSystem;
479 break; 266 break;
480 case FileSys::SaveDataSpaceId::TemporaryStorage: 267 case FileSys::SaveDataSpaceId::Temporary:
481 case FileSys::SaveDataSpaceId::ProperSystem: 268 case FileSys::SaveDataSpaceId::ProperSystem:
482 case FileSys::SaveDataSpaceId::SafeMode: 269 case FileSys::SaveDataSpaceId::SafeMode:
483 ASSERT(false); 270 ASSERT(false);
484 } 271 }
485 272
486 auto filesystem = 273 *out_interface =
487 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); 274 std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
488 275
489 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 276 R_SUCCEED();
490 rb.Push(ResultSuccess);
491 rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
492} 277}
493 278
494void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { 279Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
280 FileSys::SaveDataSpaceId space_id,
281 FileSys::SaveDataAttribute attribute) {
495 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 282 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
496 OpenSaveDataFileSystem(ctx); 283 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
497} 284}
498 285
499void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { 286Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
287 FileSys::SaveDataSpaceId space_id,
288 FileSys::SaveDataAttribute attribute) {
500 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); 289 LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
501 OpenSaveDataFileSystem(ctx); 290 R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
502} 291}
503 292
504void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { 293Result FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(
505 IPC::RequestParser rp{ctx}; 294 OutInterface<ISaveDataInfoReader> out_interface, FileSys::SaveDataSpaceId space) {
506 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
507 LOG_INFO(Service_FS, "called, space={}", space); 295 LOG_INFO(Service_FS, "called, space={}", space);
508 296
509 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 297 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space);
510 rb.Push(ResultSuccess); 298
511 rb.PushIpcInterface<ISaveDataInfoReader>( 299 R_SUCCEED();
512 std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
513} 300}
514 301
515void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { 302Result FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(
303 OutInterface<ISaveDataInfoReader> out_interface) {
516 LOG_WARNING(Service_FS, "(STUBBED) called"); 304 LOG_WARNING(Service_FS, "(STUBBED) called");
517 305
518 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 306 *out_interface = std::make_shared<ISaveDataInfoReader>(system, save_data_controller,
519 rb.Push(ResultSuccess); 307 FileSys::SaveDataSpaceId::Temporary);
520 rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
521 FileSys::SaveDataSpaceId::TemporaryStorage);
522}
523 308
524void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { 309 R_SUCCEED();
525 LOG_WARNING(Service_FS, "(STUBBED) called."); 310}
526 311
527 IPC::ResponseBuilder rb{ctx, 2}; 312Result FSP_SRV::FindSaveDataWithFilter(Out<s64> out_count,
528 rb.Push(ResultSuccess); 313 OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
314 FileSys::SaveDataSpaceId space_id,
315 FileSys::SaveDataFilter filter) {
316 LOG_WARNING(Service_FS, "(STUBBED) called");
317 R_THROW(FileSys::ResultTargetNotFound);
529} 318}
530 319
531void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { 320Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
532 IPC::RequestParser rp{ctx}; 321 LOG_WARNING(Service_FS, "(STUBBED) called.");
533 322
534 struct Parameters { 323 R_SUCCEED();
535 FileSys::SaveDataSpaceId space_id; 324}
536 FileSys::SaveDataAttribute attribute;
537 };
538 325
539 const auto parameters = rp.PopRaw<Parameters>(); 326Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
327 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
328 InBuffer<BufferAttr_HipcMapAlias> mask_buffer, OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
540 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData 329 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
541 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); 330 // In an earlier version of the code, this was returned as an out argument, but this is not
331 // correct
332 [[maybe_unused]] constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
542 333
543 LOG_WARNING(Service_FS, 334 LOG_WARNING(Service_FS,
544 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" 335 "(STUBBED) called, flags={}, space_id={}, attribute.program_id={:016X}\n"
545 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" 336 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
546 "attribute.type={}, attribute.rank={}, attribute.index={}", 337 "attribute.type={}, attribute.rank={}, attribute.index={}",
547 flags, parameters.space_id, parameters.attribute.title_id, 338 flags, space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
548 parameters.attribute.user_id[1], parameters.attribute.user_id[0], 339 attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
549 parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, 340
550 parameters.attribute.index); 341 R_SUCCEED();
551
552 IPC::ResponseBuilder rb{ctx, 3};
553 rb.Push(ResultSuccess);
554 rb.Push(flags);
555} 342}
556 343
557void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { 344Result FSP_SRV::OpenSaveDataTransferProhibiter(
345 OutInterface<ISaveDataTransferProhibiter> out_prohibiter, u64 id) {
346 LOG_WARNING(Service_FS, "(STUBBED) called, id={:016X}", id);
347 *out_prohibiter = std::make_shared<ISaveDataTransferProhibiter>(system);
348 R_SUCCEED();
349}
350
351Result FSP_SRV::OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface) {
558 LOG_DEBUG(Service_FS, "called"); 352 LOG_DEBUG(Service_FS, "called");
559 353
560 if (!romfs) { 354 if (!romfs) {
561 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); 355 auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
562 if (!current_romfs) { 356 if (!current_romfs) {
563 // TODO (bunnei): Find the right error code to use here 357 // TODO (bunnei): Find the right error code to use here
564 LOG_CRITICAL(Service_FS, "no file system interface available!"); 358 LOG_CRITICAL(Service_FS, "No file system interface available!");
565 IPC::ResponseBuilder rb{ctx, 2}; 359 R_RETURN(ResultUnknown);
566 rb.Push(ResultUnknown);
567 return;
568 } 360 }
569 361
570 romfs = current_romfs; 362 romfs = current_romfs;
571 } 363 }
572 364
573 auto storage = std::make_shared<IStorage>(system, romfs); 365 *out_interface = std::make_shared<IStorage>(system, romfs);
574 366
575 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 367 R_SUCCEED();
576 rb.Push(ResultSuccess);
577 rb.PushIpcInterface<IStorage>(std::move(storage));
578} 368}
579 369
580void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { 370Result FSP_SRV::OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
581 IPC::RequestParser rp{ctx}; 371 FileSys::StorageId storage_id, u32 unknown, u64 title_id) {
582 const auto storage_id = rp.PopRaw<FileSys::StorageId>();
583 const auto unknown = rp.PopRaw<u32>();
584 const auto title_id = rp.PopRaw<u64>();
585
586 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 372 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
587 storage_id, unknown, title_id); 373 storage_id, unknown, title_id);
588 374
@@ -592,19 +378,15 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
592 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 378 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
593 379
594 if (archive != nullptr) { 380 if (archive != nullptr) {
595 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 381 *out_interface = std::make_shared<IStorage>(system, archive);
596 rb.Push(ResultSuccess); 382 R_SUCCEED();
597 rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
598 return;
599 } 383 }
600 384
601 // TODO(DarkLordZach): Find the right error code to use here 385 // TODO(DarkLordZach): Find the right error code to use here
602 LOG_ERROR(Service_FS, 386 LOG_ERROR(Service_FS,
603 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 387 "Could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
604 storage_id); 388 storage_id);
605 IPC::ResponseBuilder rb{ctx, 2}; 389 R_RETURN(ResultUnknown);
606 rb.Push(ResultUnknown);
607 return;
608 } 390 }
609 391
610 const FileSys::PatchManager pm{title_id, fsc, content_provider}; 392 const FileSys::PatchManager pm{title_id, fsc, content_provider};
@@ -614,28 +396,20 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
614 auto storage = std::make_shared<IStorage>( 396 auto storage = std::make_shared<IStorage>(
615 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); 397 system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
616 398
617 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 399 *out_interface = std::move(storage);
618 rb.Push(ResultSuccess); 400 R_SUCCEED();
619 rb.PushIpcInterface<IStorage>(std::move(storage));
620} 401}
621 402
622void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { 403Result FSP_SRV::OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
623 IPC::RequestParser rp{ctx}; 404 FileSys::StorageId storage_id, u64 title_id) {
624 405 LOG_WARNING(Service_FS, "(STUBBED) called with storage_id={:02X}, title_id={:016X}", storage_id,
625 const auto storage_id = rp.PopRaw<FileSys::StorageId>(); 406 title_id);
626 const auto title_id = rp.PopRaw<u64>();
627
628 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
629 407
630 IPC::ResponseBuilder rb{ctx, 2}; 408 R_RETURN(FileSys::ResultTargetNotFound);
631 rb.Push(FileSys::ResultTargetNotFound);
632} 409}
633 410
634void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { 411Result FSP_SRV::OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface,
635 IPC::RequestParser rp{ctx}; 412 u8 program_index) {
636
637 const auto program_index = rp.PopRaw<u8>();
638
639 LOG_DEBUG(Service_FS, "called, program_index={}", program_index); 413 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
640 414
641 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( 415 auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
@@ -643,123 +417,80 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
643 417
644 if (!patched_romfs) { 418 if (!patched_romfs) {
645 // TODO: Find the right error code to use here 419 // TODO: Find the right error code to use here
646 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); 420 LOG_ERROR(Service_FS, "Could not open storage with program_index={}", program_index);
647 421 R_RETURN(ResultUnknown);
648 IPC::ResponseBuilder rb{ctx, 2};
649 rb.Push(ResultUnknown);
650 return;
651 } 422 }
652 423
653 auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); 424 *out_interface = std::make_shared<IStorage>(system, std::move(patched_romfs));
654 425
655 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 426 R_SUCCEED();
656 rb.Push(ResultSuccess);
657 rb.PushIpcInterface<IStorage>(std::move(storage));
658} 427}
659 428
660void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { 429Result FSP_SRV::DisableAutoSaveDataCreation() {
661 LOG_DEBUG(Service_FS, "called"); 430 LOG_DEBUG(Service_FS, "called");
662 431
663 save_data_controller->SetAutoCreate(false); 432 save_data_controller->SetAutoCreate(false);
664 433
665 IPC::ResponseBuilder rb{ctx, 2}; 434 R_SUCCEED();
666 rb.Push(ResultSuccess);
667} 435}
668 436
669void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { 437Result FSP_SRV::SetGlobalAccessLogMode(AccessLogMode access_log_mode_) {
670 IPC::RequestParser rp{ctx}; 438 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode_);
671 access_log_mode = rp.PopEnum<AccessLogMode>();
672 439
673 LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); 440 access_log_mode = access_log_mode_;
674 441
675 IPC::ResponseBuilder rb{ctx, 2}; 442 R_SUCCEED();
676 rb.Push(ResultSuccess);
677} 443}
678 444
679void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { 445Result FSP_SRV::GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode) {
680 LOG_DEBUG(Service_FS, "called"); 446 LOG_DEBUG(Service_FS, "called");
681 447
682 IPC::ResponseBuilder rb{ctx, 3}; 448 *out_access_log_mode = access_log_mode;
683 rb.Push(ResultSuccess);
684 rb.PushEnum(access_log_mode);
685}
686 449
687void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { 450 R_SUCCEED();
688 const auto raw = ctx.ReadBufferCopy(); 451}
689 auto log = Common::StringFromFixedZeroTerminatedBuffer(
690 reinterpret_cast<const char*>(raw.data()), raw.size());
691 452
453Result FSP_SRV::OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer) {
692 LOG_DEBUG(Service_FS, "called"); 454 LOG_DEBUG(Service_FS, "called");
693 455
456 auto log = Common::StringFromFixedZeroTerminatedBuffer(
457 reinterpret_cast<const char*>(log_message_buffer.data()), log_message_buffer.size());
694 reporter.SaveFSAccessLog(log); 458 reporter.SaveFSAccessLog(log);
695 459
696 IPC::ResponseBuilder rb{ctx, 2}; 460 R_SUCCEED();
697 rb.Push(ResultSuccess);
698} 461}
699 462
700void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { 463Result FSP_SRV::GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
701 LOG_DEBUG(Service_FS, "called"); 464 Out<u32> out_access_log_program_index) {
465 LOG_DEBUG(Service_FS, "(STUBBED) called");
702 466
703 IPC::ResponseBuilder rb{ctx, 4}; 467 *out_access_log_version = AccessLogVersion::Latest;
704 rb.Push(ResultSuccess); 468 *out_access_log_program_index = access_log_program_index;
705 rb.PushEnum(AccessLogVersion::Latest); 469
706 rb.Push(access_log_program_index); 470 R_SUCCEED();
707} 471}
708 472
709void FSP_SRV::FlushAccessLogOnSdCard(HLERequestContext& ctx) { 473Result FSP_SRV::FlushAccessLogOnSdCard() {
710 LOG_DEBUG(Service_FS, "(STUBBED) called"); 474 LOG_DEBUG(Service_FS, "(STUBBED) called");
711 475
712 IPC::ResponseBuilder rb{ctx, 2}; 476 R_SUCCEED();
713 rb.Push(ResultSuccess);
714} 477}
715 478
716void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { 479Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
717 IPC::RequestParser rp{ctx};
718 const auto index{rp.Pop<s32>()};
719
720 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); 480 LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
721 481
722 IPC::ResponseBuilder rb{ctx, 6}; 482 *out_data_size = 0;
723 rb.Push(ResultSuccess); 483 *out_journal_size = 0;
724 rb.Push(s64{0});
725 rb.Push(s64{0});
726}
727
728class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
729public:
730 explicit IMultiCommitManager(Core::System& system_)
731 : ServiceFramework{system_, "IMultiCommitManager"} {
732 static const FunctionInfo functions[] = {
733 {1, &IMultiCommitManager::Add, "Add"},
734 {2, &IMultiCommitManager::Commit, "Commit"},
735 };
736 RegisterHandlers(functions);
737 }
738
739private:
740 FileSys::VirtualFile backend;
741
742 void Add(HLERequestContext& ctx) {
743 LOG_WARNING(Service_FS, "(STUBBED) called");
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(ResultSuccess);
747 }
748 484
749 void Commit(HLERequestContext& ctx) { 485 R_SUCCEED();
750 LOG_WARNING(Service_FS, "(STUBBED) called"); 486}
751
752 IPC::ResponseBuilder rb{ctx, 2};
753 rb.Push(ResultSuccess);
754 }
755};
756 487
757void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { 488Result FSP_SRV::OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface) {
758 LOG_DEBUG(Service_FS, "called"); 489 LOG_DEBUG(Service_FS, "called");
759 490
760 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 491 *out_interface = std::make_shared<IMultiCommitManager>(system);
761 rb.Push(ResultSuccess); 492
762 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); 493 R_SUCCEED();
763} 494}
764 495
765} // namespace Service::FileSystem 496} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
index 59406e6f9..83d9cb51c 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -4,6 +4,9 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include "core/file_sys/fs_save_data_types.h"
8#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/filesystem/fsp/fsp_types.h"
7#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
8 11
9namespace Core { 12namespace Core {
@@ -20,6 +23,12 @@ namespace Service::FileSystem {
20class RomFsController; 23class RomFsController;
21class SaveDataController; 24class SaveDataController;
22 25
26class IFileSystem;
27class ISaveDataInfoReader;
28class ISaveDataTransferProhibiter;
29class IStorage;
30class IMultiCommitManager;
31
23enum class AccessLogVersion : u32 { 32enum class AccessLogVersion : u32 {
24 V7_0_0 = 2, 33 V7_0_0 = 2,
25 34
@@ -38,30 +47,51 @@ public:
38 ~FSP_SRV() override; 47 ~FSP_SRV() override;
39 48
40private: 49private:
41 void SetCurrentProcess(HLERequestContext& ctx); 50 Result SetCurrentProcess(ClientProcessId pid);
42 void OpenFileSystemWithPatch(HLERequestContext& ctx); 51 Result OpenFileSystemWithPatch(OutInterface<IFileSystem> out_interface,
43 void OpenSdCardFileSystem(HLERequestContext& ctx); 52 FileSystemProxyType type, u64 open_program_id);
44 void CreateSaveDataFileSystem(HLERequestContext& ctx); 53 Result OpenSdCardFileSystem(OutInterface<IFileSystem> out_interface);
45 void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 54 Result CreateSaveDataFileSystem(FileSys::SaveDataCreationInfo save_create_struct,
46 void OpenSaveDataFileSystem(HLERequestContext& ctx); 55 FileSys::SaveDataAttribute save_struct, u128 uid);
47 void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); 56 Result CreateSaveDataFileSystemBySystemSaveDataId(
48 void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); 57 FileSys::SaveDataAttribute save_struct, FileSys::SaveDataCreationInfo save_create_struct);
49 void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); 58 Result OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
50 void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); 59 FileSys::SaveDataSpaceId space_id,
51 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); 60 FileSys::SaveDataAttribute attribute);
52 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); 61 Result OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
53 void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); 62 FileSys::SaveDataSpaceId space_id,
54 void OpenDataStorageByDataId(HLERequestContext& ctx); 63 FileSys::SaveDataAttribute attribute);
55 void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); 64 Result OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,
56 void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); 65 FileSys::SaveDataSpaceId space_id,
57 void DisableAutoSaveDataCreation(HLERequestContext& ctx); 66 FileSys::SaveDataAttribute attribute);
58 void SetGlobalAccessLogMode(HLERequestContext& ctx); 67 Result OpenSaveDataInfoReaderBySaveDataSpaceId(OutInterface<ISaveDataInfoReader> out_interface,
59 void GetGlobalAccessLogMode(HLERequestContext& ctx); 68 FileSys::SaveDataSpaceId space);
60 void OutputAccessLogToSdCard(HLERequestContext& ctx); 69 Result OpenSaveDataInfoReaderOnlyCacheStorage(OutInterface<ISaveDataInfoReader> out_interface);
61 void FlushAccessLogOnSdCard(HLERequestContext& ctx); 70 Result FindSaveDataWithFilter(Out<s64> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
62 void GetProgramIndexForAccessLog(HLERequestContext& ctx); 71 FileSys::SaveDataSpaceId space_id,
63 void OpenMultiCommitManager(HLERequestContext& ctx); 72 FileSys::SaveDataFilter filter);
64 void GetCacheStorageSize(HLERequestContext& ctx); 73 Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
74 Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
75 FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
76 InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
77 OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
78 Result OpenSaveDataTransferProhibiter(OutInterface<ISaveDataTransferProhibiter> out_prohibiter,
79 u64 id);
80 Result OpenDataStorageByCurrentProcess(OutInterface<IStorage> out_interface);
81 Result OpenDataStorageByDataId(OutInterface<IStorage> out_interface,
82 FileSys::StorageId storage_id, u32 unknown, u64 title_id);
83 Result OpenPatchDataStorageByCurrentProcess(OutInterface<IStorage> out_interface,
84 FileSys::StorageId storage_id, u64 title_id);
85 Result OpenDataStorageWithProgramIndex(OutInterface<IStorage> out_interface, u8 program_index);
86 Result DisableAutoSaveDataCreation();
87 Result SetGlobalAccessLogMode(AccessLogMode access_log_mode_);
88 Result GetGlobalAccessLogMode(Out<AccessLogMode> out_access_log_mode);
89 Result OutputAccessLogToSdCard(InBuffer<BufferAttr_HipcMapAlias> log_message_buffer);
90 Result FlushAccessLogOnSdCard();
91 Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
92 Out<u32> out_access_log_program_index);
93 Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
94 Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
65 95
66 FileSystemController& fsc; 96 FileSystemController& fsc;
67 const FileSys::ContentProvider& content_provider; 97 const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_types.h
index 253f866db..294da6a2d 100644
--- a/src/core/hle/service/filesystem/fsp/fsp_util.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_types.h
@@ -7,6 +7,18 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10enum class FileSystemProxyType : u8 {
11 Code = 0,
12 Rom = 1,
13 Logo = 2,
14 Control = 3,
15 Manual = 4,
16 Meta = 5,
17 Data = 6,
18 Package = 7,
19 RegisteredUpdate = 8,
20};
21
10struct SizeGetter { 22struct SizeGetter {
11 std::function<u64()> get_free_size; 23 std::function<u64()> get_free_size;
12 std::function<u64()> get_total_size; 24 std::function<u64()> get_total_size;
diff --git a/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
new file mode 100644
index 000000000..d8d6289fe
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
@@ -0,0 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h"
5
6namespace Service::FileSystem {
7
8ISaveDataTransferProhibiter::ISaveDataTransferProhibiter(Core::System& system_)
9 : ServiceFramework{system_, "ISaveDataTransferProhibiter"} {}
10
11ISaveDataTransferProhibiter::~ISaveDataTransferProhibiter() = default;
12
13} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
new file mode 100644
index 000000000..d206e1dea
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::FileSystem {
9
10class ISaveDataTransferProhibiter : public ServiceFramework<ISaveDataTransferProhibiter> {
11public:
12 explicit ISaveDataTransferProhibiter(Core::System& system_);
13 ~ISaveDataTransferProhibiter() override;
14};
15
16} // namespace Service::FileSystem
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index aeb849efa..38e62761b 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -42,13 +42,13 @@ public:
42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, 42 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
43 {10702, nullptr, "AddPlayHistory"}, 43 {10702, nullptr, "AddPlayHistory"},
44 {11000, nullptr, "GetProfileImageUrl"}, 44 {11000, nullptr, "GetProfileImageUrl"},
45 {20100, nullptr, "GetFriendCount"}, 45 {20100, &IFriendService::GetFriendCount, "GetFriendCount"},
46 {20101, nullptr, "GetNewlyFriendCount"}, 46 {20101, &IFriendService::GetNewlyFriendCount, "GetNewlyFriendCount"},
47 {20102, nullptr, "GetFriendDetailedInfo"}, 47 {20102, nullptr, "GetFriendDetailedInfo"},
48 {20103, nullptr, "SyncFriendList"}, 48 {20103, nullptr, "SyncFriendList"},
49 {20104, nullptr, "RequestSyncFriendList"}, 49 {20104, nullptr, "RequestSyncFriendList"},
50 {20110, nullptr, "LoadFriendSetting"}, 50 {20110, nullptr, "LoadFriendSetting"},
51 {20200, nullptr, "GetReceivedFriendRequestCount"}, 51 {20200, &IFriendService::GetReceivedFriendRequestCount, "GetReceivedFriendRequestCount"},
52 {20201, nullptr, "GetFriendRequestList"}, 52 {20201, nullptr, "GetFriendRequestList"},
53 {20300, nullptr, "GetFriendCandidateList"}, 53 {20300, nullptr, "GetFriendCandidateList"},
54 {20301, nullptr, "GetNintendoNetworkIdInfo"}, 54 {20301, nullptr, "GetNintendoNetworkIdInfo"},
@@ -61,14 +61,14 @@ public:
61 {20501, nullptr, "GetRelationship"}, 61 {20501, nullptr, "GetRelationship"},
62 {20600, nullptr, "GetUserPresenceView"}, 62 {20600, nullptr, "GetUserPresenceView"},
63 {20700, nullptr, "GetPlayHistoryList"}, 63 {20700, nullptr, "GetPlayHistoryList"},
64 {20701, nullptr, "GetPlayHistoryStatistics"}, 64 {20701, &IFriendService::GetPlayHistoryStatistics, "GetPlayHistoryStatistics"},
65 {20800, nullptr, "LoadUserSetting"}, 65 {20800, nullptr, "LoadUserSetting"},
66 {20801, nullptr, "SyncUserSetting"}, 66 {20801, nullptr, "SyncUserSetting"},
67 {20900, nullptr, "RequestListSummaryOverlayNotification"}, 67 {20900, nullptr, "RequestListSummaryOverlayNotification"},
68 {21000, nullptr, "GetExternalApplicationCatalog"}, 68 {21000, nullptr, "GetExternalApplicationCatalog"},
69 {22000, nullptr, "GetReceivedFriendInvitationList"}, 69 {22000, nullptr, "GetReceivedFriendInvitationList"},
70 {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"}, 70 {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"},
71 {22010, nullptr, "GetReceivedFriendInvitationCountCache"}, 71 {22010, &IFriendService::GetReceivedFriendInvitationCountCache, "GetReceivedFriendInvitationCountCache"},
72 {30100, nullptr, "DropFriendNewlyFlags"}, 72 {30100, nullptr, "DropFriendNewlyFlags"},
73 {30101, nullptr, "DeleteFriend"}, 73 {30101, nullptr, "DeleteFriend"},
74 {30110, nullptr, "DropFriendNewlyFlag"}, 74 {30110, nullptr, "DropFriendNewlyFlag"},
@@ -144,6 +144,33 @@ private:
144 rb.PushCopyObjects(completion_event->GetReadableEvent()); 144 rb.PushCopyObjects(completion_event->GetReadableEvent());
145 } 145 }
146 146
147 void GetFriendList(HLERequestContext& ctx) {
148 IPC::RequestParser rp{ctx};
149 const auto friend_offset = rp.Pop<u32>();
150 const auto uuid = rp.PopRaw<Common::UUID>();
151 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
152 const auto pid = rp.Pop<u64>();
153 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
154 uuid.RawString(), pid);
155
156 IPC::ResponseBuilder rb{ctx, 3};
157 rb.Push(ResultSuccess);
158
159 rb.Push<u32>(0); // Friend count
160 // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
161 }
162
163 void CheckFriendListAvailability(HLERequestContext& ctx) {
164 IPC::RequestParser rp{ctx};
165 const auto uuid{rp.PopRaw<Common::UUID>()};
166
167 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
168
169 IPC::ResponseBuilder rb{ctx, 3};
170 rb.Push(ResultSuccess);
171 rb.Push(true);
172 }
173
147 void GetBlockedUserListIds(HLERequestContext& ctx) { 174 void GetBlockedUserListIds(HLERequestContext& ctx) {
148 // This is safe to stub, as there should be no adverse consequences from reporting no 175 // This is safe to stub, as there should be no adverse consequences from reporting no
149 // blocked users. 176 // blocked users.
@@ -153,6 +180,17 @@ private:
153 rb.Push<u32>(0); // Indicates there are no blocked users 180 rb.Push<u32>(0); // Indicates there are no blocked users
154 } 181 }
155 182
183 void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
184 IPC::RequestParser rp{ctx};
185 const auto uuid{rp.PopRaw<Common::UUID>()};
186
187 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
188
189 IPC::ResponseBuilder rb{ctx, 3};
190 rb.Push(ResultSuccess);
191 rb.Push(true);
192 }
193
156 void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) { 194 void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) {
157 // Stub used by Splatoon 2 195 // Stub used by Splatoon 2
158 LOG_WARNING(Service_Friend, "(STUBBED) called"); 196 LOG_WARNING(Service_Friend, "(STUBBED) called");
@@ -179,42 +217,43 @@ private:
179 rb.Push(ResultSuccess); 217 rb.Push(ResultSuccess);
180 } 218 }
181 219
182 void GetFriendList(HLERequestContext& ctx) { 220 void GetFriendCount(HLERequestContext& ctx) {
183 IPC::RequestParser rp{ctx}; 221 LOG_DEBUG(Service_Friend, "(STUBBED) called");
184 const auto friend_offset = rp.Pop<u32>();
185 const auto uuid = rp.PopRaw<Common::UUID>();
186 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
187 const auto pid = rp.Pop<u64>();
188 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
189 uuid.RawString(), pid);
190 222
191 IPC::ResponseBuilder rb{ctx, 3}; 223 IPC::ResponseBuilder rb{ctx, 3};
192 rb.Push(ResultSuccess); 224 rb.Push(ResultSuccess);
193 225 rb.Push(0);
194 rb.Push<u32>(0); // Friend count
195 // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
196 } 226 }
197 227
198 void CheckFriendListAvailability(HLERequestContext& ctx) { 228 void GetNewlyFriendCount(HLERequestContext& ctx) {
199 IPC::RequestParser rp{ctx}; 229 LOG_DEBUG(Service_Friend, "(STUBBED) called");
200 const auto uuid{rp.PopRaw<Common::UUID>()};
201 230
202 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); 231 IPC::ResponseBuilder rb{ctx, 3};
232 rb.Push(ResultSuccess);
233 rb.Push(0);
234 }
235
236 void GetReceivedFriendRequestCount(HLERequestContext& ctx) {
237 LOG_DEBUG(Service_Friend, "(STUBBED) called");
203 238
204 IPC::ResponseBuilder rb{ctx, 3}; 239 IPC::ResponseBuilder rb{ctx, 3};
205 rb.Push(ResultSuccess); 240 rb.Push(ResultSuccess);
206 rb.Push(true); 241 rb.Push(0);
207 } 242 }
208 243
209 void CheckBlockedUserListAvailability(HLERequestContext& ctx) { 244 void GetPlayHistoryStatistics(HLERequestContext& ctx) {
210 IPC::RequestParser rp{ctx}; 245 LOG_ERROR(Service_Friend, "(STUBBED) called, check in out");
211 const auto uuid{rp.PopRaw<Common::UUID>()};
212 246
213 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); 247 IPC::ResponseBuilder rb{ctx, 2};
248 rb.Push(ResultSuccess);
249 }
250
251 void GetReceivedFriendInvitationCountCache(HLERequestContext& ctx) {
252 LOG_DEBUG(Service_Friend, "(STUBBED) called, check in out");
214 253
215 IPC::ResponseBuilder rb{ctx, 3}; 254 IPC::ResponseBuilder rb{ctx, 3};
216 rb.Push(ResultSuccess); 255 rb.Push(ResultSuccess);
217 rb.Push(true); 256 rb.Push(0);
218 } 257 }
219 258
220 KernelHelpers::ServiceContext service_context; 259 KernelHelpers::ServiceContext service_context;
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp
index ec9b0efb1..b801faef2 100644
--- a/src/core/hle/service/glue/time/static.cpp
+++ b/src/core/hle/service/glue/time/static.cpp
@@ -142,16 +142,18 @@ Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
142} 142}
143 143
144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) { 144Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
145 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 145 SCOPE_EXIT {
146 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
147 };
146 148
147 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value)); 149 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value));
148} 150}
149 151
150Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 152Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
151 Out<bool> out_automatic_correction) { 153 Out<bool> out_automatic_correction) {
152 SCOPE_EXIT({ 154 SCOPE_EXIT {
153 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction); 155 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction);
154 }); 156 };
155 157
156 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( 158 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
157 out_automatic_correction)); 159 out_automatic_correction));
@@ -166,21 +168,27 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
166} 168}
167 169
168Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) { 170Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
169 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); }); 171 SCOPE_EXIT {
172 LOG_DEBUG(Service_Time, "called. out_year={}", *out_year);
173 };
170 174
171 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time", 175 R_RETURN(m_set_sys->GetSettingsItemValueImpl<s32>(*out_year, "time",
172 "standard_user_clock_initial_year")); 176 "standard_user_clock_initial_year"));
173} 177}
174 178
175Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 179Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
176 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 180 SCOPE_EXIT {
181 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
182 };
177 183
178 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); 184 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
179} 185}
180 186
181Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 187Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
182 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 188 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 189 SCOPE_EXIT {
190 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
191 };
184 192
185 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 193 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
186 out_time_point)); 194 out_time_point));
@@ -188,15 +196,18 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
188 196
189Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 197Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
190 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) { 198 Out<s64> out_time, const Service::PSC::Time::SystemClockContext& context) {
191 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 199 SCOPE_EXIT {
200 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
201 };
192 202
193 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); 203 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
194} 204}
195 205
196Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, 206Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
197 Service::PSC::Time::TimeType type) { 207 Service::PSC::Time::TimeType type) {
198 SCOPE_EXIT( 208 SCOPE_EXIT {
199 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 209 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
210 };
200 211
201 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); 212 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
202} 213}
@@ -205,11 +216,11 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
205 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot, 216 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
206 const Service::PSC::Time::SystemClockContext& user_context, 217 const Service::PSC::Time::SystemClockContext& user_context,
207 const Service::PSC::Time::SystemClockContext& network_context) { 218 const Service::PSC::Time::SystemClockContext& network_context) {
208 SCOPE_EXIT({ 219 SCOPE_EXIT {
209 LOG_DEBUG(Service_Time, 220 LOG_DEBUG(Service_Time,
210 "called. type={} out_snapshot={} user_context={} network_context={}", type, 221 "called. type={} out_snapshot={} user_context={} network_context={}", type,
211 *out_snapshot, user_context, network_context); 222 *out_snapshot, user_context, network_context);
212 }); 223 };
213 224
214 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext( 225 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(
215 type, out_snapshot, user_context, network_context)); 226 type, out_snapshot, user_context, network_context));
@@ -218,14 +229,18 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
218Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time, 229Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time,
219 InClockSnapshot a, 230 InClockSnapshot a,
220 InClockSnapshot b) { 231 InClockSnapshot b) {
221 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 232 SCOPE_EXIT {
233 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
234 };
222 235
223 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); 236 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
224} 237}
225 238
226Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 239Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
227 InClockSnapshot b) { 240 InClockSnapshot b) {
228 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 241 SCOPE_EXIT {
242 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
243 };
229 244
230 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); 245 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
231} 246}
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
index 36f163419..f4d0c87d5 100644
--- a/src/core/hle/service/glue/time/time_zone.cpp
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -57,7 +57,9 @@ TimeZoneService::~TimeZoneService() = default;
57 57
58Result TimeZoneService::GetDeviceLocationName( 58Result TimeZoneService::GetDeviceLocationName(
59 Out<Service::PSC::Time::LocationName> out_location_name) { 59 Out<Service::PSC::Time::LocationName> out_location_name) {
60 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 60 SCOPE_EXIT {
61 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
62 };
61 63
62 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); 64 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
63} 65}
@@ -94,7 +96,9 @@ Result TimeZoneService::SetDeviceLocationName(
94} 96}
95 97
96Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 98Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
97 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 99 SCOPE_EXIT {
100 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
101 };
98 102
99 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); 103 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
100} 104}
@@ -102,10 +106,10 @@ Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
102Result TimeZoneService::LoadLocationNameList( 106Result TimeZoneService::LoadLocationNameList(
103 Out<u32> out_count, 107 Out<u32> out_count,
104 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) { 108 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
105 SCOPE_EXIT({ 109 SCOPE_EXIT {
106 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}", 110 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
107 index, *out_count, out_names[0], out_names[1]); 111 index, *out_count, out_names[0], out_names[1]);
108 }); 112 };
109 113
110 std::scoped_lock l{m_mutex}; 114 std::scoped_lock l{m_mutex};
111 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index)); 115 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
@@ -124,7 +128,9 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule,
124 128
125Result TimeZoneService::GetTimeZoneRuleVersion( 129Result TimeZoneService::GetTimeZoneRuleVersion(
126 Out<Service::PSC::Time::RuleVersion> out_rule_version) { 130 Out<Service::PSC::Time::RuleVersion> out_rule_version) {
127 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 131 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
133 };
128 134
129 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); 135 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
130} 136}
@@ -132,10 +138,10 @@ Result TimeZoneService::GetTimeZoneRuleVersion(
132Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 138Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
133 Out<Service::PSC::Time::LocationName> location_name, 139 Out<Service::PSC::Time::LocationName> location_name,
134 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) { 140 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
135 SCOPE_EXIT({ 141 SCOPE_EXIT {
136 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name, 142 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name,
137 *out_time_point); 143 *out_time_point);
138 }); 144 };
139 145
140 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point)); 146 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point));
141} 147}
@@ -178,10 +184,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
178Result TimeZoneService::ToCalendarTime( 184Result TimeZoneService::ToCalendarTime(
179 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 185 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
180 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) { 186 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) {
181 SCOPE_EXIT({ 187 SCOPE_EXIT {
182 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 188 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
183 *out_calendar_time, *out_additional_info); 189 *out_calendar_time, *out_additional_info);
184 }); 190 };
185 191
186 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); 192 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
187} 193}
@@ -189,10 +195,10 @@ Result TimeZoneService::ToCalendarTime(
189Result TimeZoneService::ToCalendarTimeWithMyRule( 195Result TimeZoneService::ToCalendarTimeWithMyRule(
190 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 196 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
191 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) { 197 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) {
192 SCOPE_EXIT({ 198 SCOPE_EXIT {
193 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 199 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
194 *out_calendar_time, *out_additional_info); 200 *out_calendar_time, *out_additional_info);
195 }); 201 };
196 202
197 R_RETURN( 203 R_RETURN(
198 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); 204 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
@@ -202,11 +208,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
202 OutArray<s64, BufferAttr_HipcPointer> out_times, 208 OutArray<s64, BufferAttr_HipcPointer> out_times,
203 const Service::PSC::Time::CalendarTime& calendar_time, 209 const Service::PSC::Time::CalendarTime& calendar_time,
204 InRule rule) { 210 InRule rule) {
205 SCOPE_EXIT({ 211 SCOPE_EXIT {
206 LOG_DEBUG(Service_Time, 212 LOG_DEBUG(Service_Time,
207 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 213 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
208 calendar_time, *out_count, out_times[0], out_times[1]); 214 calendar_time, *out_count, out_times[0], out_times[1]);
209 }); 215 };
210 216
211 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule)); 217 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
212} 218}
@@ -214,11 +220,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
214Result TimeZoneService::ToPosixTimeWithMyRule( 220Result TimeZoneService::ToPosixTimeWithMyRule(
215 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, 221 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
216 const Service::PSC::Time::CalendarTime& calendar_time) { 222 const Service::PSC::Time::CalendarTime& calendar_time) {
217 SCOPE_EXIT({ 223 SCOPE_EXIT {
218 LOG_DEBUG(Service_Time, 224 LOG_DEBUG(Service_Time,
219 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}", 225 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
220 calendar_time, *out_count, out_times[0], out_times[1]); 226 calendar_time, *out_count, out_times[0], out_times[1]);
221 }); 227 };
222 228
223 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time)); 229 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
224} 230}
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index 7126a1dcd..b0cd63d72 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -201,7 +201,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
201 {1269, nullptr, "DeleteButtonConfigStorageLeft"}, 201 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
202 {1270, nullptr, "DeleteButtonConfigStorageRight"}, 202 {1270, nullptr, "DeleteButtonConfigStorageRight"},
203 {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"}, 203 {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"},
204 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, 204 {1272, &IHidSystemServer::IsAnyCustomButtonConfigEnabled, "IsAnyCustomButtonConfigEnabled"},
205 {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, 205 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
206 {1274, nullptr, "SetDefaultButtonConfig"}, 206 {1274, nullptr, "SetDefaultButtonConfig"},
207 {1275, nullptr, "SetAllDefaultButtonConfig"}, 207 {1275, nullptr, "SetAllDefaultButtonConfig"},
@@ -926,6 +926,16 @@ void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
926 rb.Push(is_enabled); 926 rb.Push(is_enabled);
927} 927}
928 928
929void IHidSystemServer::IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx) {
930 const bool is_enabled = false;
931
932 LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
933
934 IPC::ResponseBuilder rb{ctx, 3};
935 rb.Push(ResultSuccess);
936 rb.Push(is_enabled);
937}
938
929std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { 939std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
930 resource_manager->Initialize(); 940 resource_manager->Initialize();
931 return resource_manager; 941 return resource_manager;
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 738313e08..1a4f244d7 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -77,6 +77,7 @@ private:
77 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); 77 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
78 void SetForceHandheldStyleVibration(HLERequestContext& ctx); 78 void SetForceHandheldStyleVibration(HLERequestContext& ctx);
79 void IsUsingCustomButtonConfig(HLERequestContext& ctx); 79 void IsUsingCustomButtonConfig(HLERequestContext& ctx);
80 void IsAnyCustomButtonConfigEnabled(HLERequestContext& ctx);
80 81
81 std::shared_ptr<ResourceManager> GetResourceManager(); 82 std::shared_ptr<ResourceManager> GetResourceManager();
82 83
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 98a79365d..c14b24142 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -18,8 +18,8 @@ public:
18 explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} { 18 explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "SaveCurrentSetting"}, 21 {0, &LBL::SaveCurrentSetting, "SaveCurrentSetting"},
22 {1, nullptr, "LoadCurrentSetting"}, 22 {1, &LBL::LoadCurrentSetting, "LoadCurrentSetting"},
23 {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"}, 23 {2, &LBL::SetCurrentBrightnessSetting, "SetCurrentBrightnessSetting"},
24 {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"}, 24 {3, &LBL::GetCurrentBrightnessSetting, "GetCurrentBrightnessSetting"},
25 {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"}, 25 {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
@@ -47,7 +47,7 @@ public:
47 {26, &LBL::EnableVrMode, "EnableVrMode"}, 47 {26, &LBL::EnableVrMode, "EnableVrMode"},
48 {27, &LBL::DisableVrMode, "DisableVrMode"}, 48 {27, &LBL::DisableVrMode, "DisableVrMode"},
49 {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, 49 {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
50 {29, nullptr, "IsAutoBrightnessControlSupported"}, 50 {29, &LBL::IsAutoBrightnessControlSupported, "IsAutoBrightnessControlSupported"},
51 }; 51 };
52 // clang-format on 52 // clang-format on
53 53
@@ -60,6 +60,20 @@ private:
60 On = 1, 60 On = 1,
61 }; 61 };
62 62
63 void SaveCurrentSetting(HLERequestContext& ctx) {
64 LOG_WARNING(Service_LBL, "(STUBBED) called");
65
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(ResultSuccess);
68 }
69
70 void LoadCurrentSetting(HLERequestContext& ctx) {
71 LOG_WARNING(Service_LBL, "(STUBBED) called");
72
73 IPC::ResponseBuilder rb{ctx, 2};
74 rb.Push(ResultSuccess);
75 }
76
63 void SetCurrentBrightnessSetting(HLERequestContext& ctx) { 77 void SetCurrentBrightnessSetting(HLERequestContext& ctx) {
64 IPC::RequestParser rp{ctx}; 78 IPC::RequestParser rp{ctx};
65 auto brightness = rp.Pop<float>(); 79 auto brightness = rp.Pop<float>();
@@ -310,6 +324,14 @@ private:
310 rb.Push(vr_mode_enabled); 324 rb.Push(vr_mode_enabled);
311 } 325 }
312 326
327 void IsAutoBrightnessControlSupported(HLERequestContext& ctx) {
328 LOG_DEBUG(Service_LBL, "called");
329
330 IPC::ResponseBuilder rb{ctx, 3};
331 rb.Push(ResultSuccess);
332 rb.Push<u8>(auto_brightness_supported);
333 }
334
313 bool vr_mode_enabled = false; 335 bool vr_mode_enabled = false;
314 float current_brightness = 1.0f; 336 float current_brightness = 1.0f;
315 float ambient_light_value = 0.0f; 337 float ambient_light_value = 0.0f;
@@ -317,7 +339,8 @@ private:
317 bool dimming = true; 339 bool dimming = true;
318 bool backlight_enabled = true; 340 bool backlight_enabled = true;
319 bool update_instantly = false; 341 bool update_instantly = false;
320 bool auto_brightness = false; // TODO(ogniK): Move to system settings 342 bool auto_brightness = false;
343 bool auto_brightness_supported = true; // TODO(ogniK): Move to system settings
321}; 344};
322 345
323void LoopProcess(Core::System& system) { 346void LoopProcess(Core::System& system) {
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index 94a8243b5..2dd3e9f89 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/psc/time/steady_clock.h" 14#include "core/hle/service/psc/time/steady_clock.h"
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "core/hle/service/set/system_settings_server.h"
16#include "core/hle/service/sm/sm.h" 17#include "core/hle/service/sm/sm.h"
17#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
18#include "hid_core/hid_util.h" 19#include "hid_core/hid_util.h"
@@ -32,6 +33,9 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
32 } 33 }
33 34
34 is_initialized = false; 35 is_initialized = false;
36
37 m_set_sys =
38 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
35} 39}
36 40
37DeviceManager ::~DeviceManager() { 41DeviceManager ::~DeviceManager() {
@@ -774,8 +778,8 @@ Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const
774} 778}
775 779
776Result DeviceManager::IsNfcEnabled() const { 780Result DeviceManager::IsNfcEnabled() const {
777 // TODO: This calls nn::settings::detail::GetNfcEnableFlag 781 bool is_enabled{};
778 const bool is_enabled = true; 782 R_TRY(m_set_sys->GetNfcEnableFlag(&is_enabled));
779 if (!is_enabled) { 783 if (!is_enabled) {
780 return ResultNfcDisabled; 784 return ResultNfcDisabled;
781 } 785 }
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
index c56a2fbda..6c0e6b255 100644
--- a/src/core/hle/service/nfc/common/device_manager.h
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -15,6 +15,10 @@
15#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
16#include "hid_core/hid_types.h" 16#include "hid_core/hid_types.h"
17 17
18namespace Service::Set {
19class ISystemSettingsServer;
20}
21
18namespace Service::NFC { 22namespace Service::NFC {
19class NfcDevice; 23class NfcDevice;
20 24
@@ -98,6 +102,7 @@ private:
98 Core::System& system; 102 Core::System& system;
99 KernelHelpers::ServiceContext service_context; 103 KernelHelpers::ServiceContext service_context;
100 Kernel::KEvent* availability_change_event; 104 Kernel::KEvent* availability_change_event;
105 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
101}; 106};
102 107
103} // namespace Service::NFC 108} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 30ae989b9..9d4808dbe 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -57,7 +57,7 @@ public:
57 {1, &NfcInterface::Finalize, "FinalizeOld"}, 57 {1, &NfcInterface::Finalize, "FinalizeOld"},
58 {2, &NfcInterface::GetState, "GetStateOld"}, 58 {2, &NfcInterface::GetState, "GetStateOld"},
59 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"}, 59 {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
60 {100, nullptr, "SetNfcEnabledOld"}, 60 {100, &NfcInterface::SetNfcEnabled, "SetNfcEnabledOld"},
61 {400, &NfcInterface::Initialize, "Initialize"}, 61 {400, &NfcInterface::Initialize, "Initialize"},
62 {401, &NfcInterface::Finalize, "Finalize"}, 62 {401, &NfcInterface::Finalize, "Finalize"},
63 {402, &NfcInterface::GetState, "GetState"}, 63 {402, &NfcInterface::GetState, "GetState"},
@@ -71,7 +71,7 @@ public:
71 {410, &NfcInterface::GetTagInfo, "GetTagInfo"}, 71 {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
72 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"}, 72 {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
73 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"}, 73 {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
74 {500, nullptr, "SetNfcEnabled"}, 74 {500, &NfcInterface::SetNfcEnabled, "SetNfcEnabled"},
75 {510, nullptr, "OutputTestWave"}, 75 {510, nullptr, "OutputTestWave"},
76 {1000, &NfcInterface::ReadMifare, "ReadMifare"}, 76 {1000, &NfcInterface::ReadMifare, "ReadMifare"},
77 {1001, &NfcInterface::WriteMifare, "WriteMifare"}, 77 {1001, &NfcInterface::WriteMifare, "WriteMifare"},
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
index 3e2c7deab..c28e55431 100644
--- a/src/core/hle/service/nfc/nfc_interface.cpp
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -13,13 +13,18 @@
13#include "core/hle/service/nfc/nfc_result.h" 13#include "core/hle/service/nfc/nfc_result.h"
14#include "core/hle/service/nfc/nfc_types.h" 14#include "core/hle/service/nfc/nfc_types.h"
15#include "core/hle/service/nfp/nfp_result.h" 15#include "core/hle/service/nfp/nfp_result.h"
16#include "core/hle/service/set/system_settings_server.h"
17#include "core/hle/service/sm/sm.h"
16#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
17 19
18namespace Service::NFC { 20namespace Service::NFC {
19 21
20NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend) 22NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
21 : ServiceFramework{system_, name}, service_context{system_, service_name}, 23 : ServiceFramework{system_, name}, service_context{system_, service_name},
22 backend_type{service_backend} {} 24 backend_type{service_backend} {
25 m_set_sys =
26 system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
27}
23 28
24NfcInterface ::~NfcInterface() = default; 29NfcInterface ::~NfcInterface() = default;
25 30
@@ -65,11 +70,11 @@ void NfcInterface::GetState(HLERequestContext& ctx) {
65void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) { 70void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
66 LOG_DEBUG(Service_NFC, "called"); 71 LOG_DEBUG(Service_NFC, "called");
67 72
68 // TODO: This calls nn::settings::detail::GetNfcEnableFlag 73 bool is_enabled{};
69 const bool is_enabled = true; 74 const auto result = m_set_sys->GetNfcEnableFlag(&is_enabled);
70 75
71 IPC::ResponseBuilder rb{ctx, 3}; 76 IPC::ResponseBuilder rb{ctx, 3};
72 rb.Push(ResultSuccess); 77 rb.Push(result);
73 rb.Push(is_enabled); 78 rb.Push(is_enabled);
74} 79}
75 80
@@ -212,6 +217,17 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
212 rb.PushCopyObjects(out_event); 217 rb.PushCopyObjects(out_event);
213} 218}
214 219
220void NfcInterface::SetNfcEnabled(HLERequestContext& ctx) {
221 IPC::RequestParser rp{ctx};
222 const auto is_enabled{rp.Pop<bool>()};
223 LOG_DEBUG(Service_NFC, "called, is_enabled={}", is_enabled);
224
225 const auto result = m_set_sys->SetNfcEnableFlag(is_enabled);
226
227 IPC::ResponseBuilder rb{ctx, 2};
228 rb.Push(result);
229}
230
215void NfcInterface::ReadMifare(HLERequestContext& ctx) { 231void NfcInterface::ReadMifare(HLERequestContext& ctx) {
216 IPC::RequestParser rp{ctx}; 232 IPC::RequestParser rp{ctx};
217 const auto device_handle{rp.Pop<u64>()}; 233 const auto device_handle{rp.Pop<u64>()};
diff --git a/src/core/hle/service/nfc/nfc_interface.h b/src/core/hle/service/nfc/nfc_interface.h
index 08be174d8..5cc0d8ec0 100644
--- a/src/core/hle/service/nfc/nfc_interface.h
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -7,6 +7,10 @@
7#include "core/hle/service/nfc/nfc_types.h" 7#include "core/hle/service/nfc/nfc_types.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Service::Set {
11class ISystemSettingsServer;
12}
13
10namespace Service::NFC { 14namespace Service::NFC {
11class DeviceManager; 15class DeviceManager;
12 16
@@ -29,6 +33,7 @@ public:
29 void AttachActivateEvent(HLERequestContext& ctx); 33 void AttachActivateEvent(HLERequestContext& ctx);
30 void AttachDeactivateEvent(HLERequestContext& ctx); 34 void AttachDeactivateEvent(HLERequestContext& ctx);
31 void ReadMifare(HLERequestContext& ctx); 35 void ReadMifare(HLERequestContext& ctx);
36 void SetNfcEnabled(HLERequestContext& ctx);
32 void WriteMifare(HLERequestContext& ctx); 37 void WriteMifare(HLERequestContext& ctx);
33 void SendCommandByPassThrough(HLERequestContext& ctx); 38 void SendCommandByPassThrough(HLERequestContext& ctx);
34 39
@@ -44,6 +49,7 @@ protected:
44 BackendType backend_type; 49 BackendType backend_type;
45 State state{State::NonInitialized}; 50 State state{State::NonInitialized};
46 std::shared_ptr<DeviceManager> device_manager = nullptr; 51 std::shared_ptr<DeviceManager> device_manager = nullptr;
52 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
47}; 53};
48 54
49} // namespace Service::NFC 55} // namespace Service::NFC
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index a162e5c54..e54827efe 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -3,22 +3,26 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/kernel_helpers.h"
6#include "core/hle/service/npns/npns.h" 9#include "core/hle/service/npns/npns.h"
7#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
8#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
9 12
10namespace Service::NPNS { 13namespace Service::NPNS {
11 14
12class NPNS_S final : public ServiceFramework<NPNS_S> { 15class INpnsSystem final : public ServiceFramework<INpnsSystem> {
13public: 16public:
14 explicit NPNS_S(Core::System& system_) : ServiceFramework{system_, "npns:s"} { 17 explicit INpnsSystem(Core::System& system_)
18 : ServiceFramework{system_, "npns:s"}, service_context{system, "npns:s"} {
15 // clang-format off 19 // clang-format off
16 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
17 {1, nullptr, "ListenAll"}, 21 {1, nullptr, "ListenAll"},
18 {2, nullptr, "ListenTo"}, 22 {2, C<&INpnsSystem::ListenTo>, "ListenTo"},
19 {3, nullptr, "Receive"}, 23 {3, nullptr, "Receive"},
20 {4, nullptr, "ReceiveRaw"}, 24 {4, nullptr, "ReceiveRaw"},
21 {5, nullptr, "GetReceiveEvent"}, 25 {5, C<&INpnsSystem::GetReceiveEvent>, "GetReceiveEvent"},
22 {6, nullptr, "ListenUndelivered"}, 26 {6, nullptr, "ListenUndelivered"},
23 {7, nullptr, "GetStateChangeEVent"}, 27 {7, nullptr, "GetStateChangeEVent"},
24 {11, nullptr, "SubscribeTopic"}, 28 {11, nullptr, "SubscribeTopic"},
@@ -59,12 +63,34 @@ public:
59 // clang-format on 63 // clang-format on
60 64
61 RegisterHandlers(functions); 65 RegisterHandlers(functions);
66
67 get_receive_event = service_context.CreateEvent("npns:s:GetReceiveEvent");
62 } 68 }
69
70 ~INpnsSystem() override {
71 service_context.CloseEvent(get_receive_event);
72 }
73
74private:
75 Result ListenTo(u32 program_id) {
76 LOG_WARNING(Service_AM, "(STUBBED) called, program_id={}", program_id);
77 R_SUCCEED();
78 }
79
80 Result GetReceiveEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
81 LOG_WARNING(Service_AM, "(STUBBED) called");
82
83 *out_event = &get_receive_event->GetReadableEvent();
84 R_SUCCEED();
85 }
86
87 KernelHelpers::ServiceContext service_context;
88 Kernel::KEvent* get_receive_event;
63}; 89};
64 90
65class NPNS_U final : public ServiceFramework<NPNS_U> { 91class INpnsUser final : public ServiceFramework<INpnsUser> {
66public: 92public:
67 explicit NPNS_U(Core::System& system_) : ServiceFramework{system_, "npns:u"} { 93 explicit INpnsUser(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
68 // clang-format off 94 // clang-format off
69 static const FunctionInfo functions[] = { 95 static const FunctionInfo functions[] = {
70 {1, nullptr, "ListenAll"}, 96 {1, nullptr, "ListenAll"},
@@ -97,8 +123,8 @@ public:
97void LoopProcess(Core::System& system) { 123void LoopProcess(Core::System& system) {
98 auto server_manager = std::make_unique<ServerManager>(system); 124 auto server_manager = std::make_unique<ServerManager>(system);
99 125
100 server_manager->RegisterNamedService("npns:s", std::make_shared<NPNS_S>(system)); 126 server_manager->RegisterNamedService("npns:s", std::make_shared<INpnsSystem>(system));
101 server_manager->RegisterNamedService("npns:u", std::make_shared<NPNS_U>(system)); 127 server_manager->RegisterNamedService("npns:u", std::make_shared<INpnsUser>(system));
102 ServerManager::RunServer(std::move(server_manager)); 128 ServerManager::RunServer(std::move(server_manager));
103} 129}
104 130
diff --git a/src/core/hle/service/ns/application_manager_interface.cpp b/src/core/hle/service/ns/application_manager_interface.cpp
index 2e3a44c0d..7a91727f9 100644
--- a/src/core/hle/service/ns/application_manager_interface.cpp
+++ b/src/core/hle/service/ns/application_manager_interface.cpp
@@ -436,14 +436,14 @@ Result IApplicationManagerInterface::GetApplicationViewWithPromotionInfo(
436 436
437Result IApplicationManagerInterface::GetApplicationRightsOnClient( 437Result IApplicationManagerInterface::GetApplicationRightsOnClient(
438 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, 438 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
439 Common::UUID account_id, u32 flags, u64 application_id) { 439 u32 flags, u64 application_id, Uid account_id) {
440 LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}", 440 LOG_WARNING(Service_NS, "(STUBBED) called, flags={}, application_id={:016X}, account_id={}",
441 flags, application_id, account_id.FormattedString()); 441 flags, application_id, account_id.uuid.FormattedString());
442 442
443 if (!out_rights.empty()) { 443 if (!out_rights.empty()) {
444 ApplicationRightsOnClient rights{}; 444 ApplicationRightsOnClient rights{};
445 rights.application_id = application_id; 445 rights.application_id = application_id;
446 rights.uid = account_id; 446 rights.uid = account_id.uuid;
447 rights.flags = 0; 447 rights.flags = 0;
448 rights.flags2 = 0; 448 rights.flags2 = 0;
449 449
diff --git a/src/core/hle/service/ns/application_manager_interface.h b/src/core/hle/service/ns/application_manager_interface.h
index 350ec37ce..f33d269b3 100644
--- a/src/core/hle/service/ns/application_manager_interface.h
+++ b/src/core/hle/service/ns/application_manager_interface.h
@@ -37,7 +37,7 @@ public:
37 InArray<u64, BufferAttr_HipcMapAlias> application_ids); 37 InArray<u64, BufferAttr_HipcMapAlias> application_ids);
38 Result GetApplicationRightsOnClient( 38 Result GetApplicationRightsOnClient(
39 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count, 39 OutArray<ApplicationRightsOnClient, BufferAttr_HipcMapAlias> out_rights, Out<u32> out_count,
40 Common::UUID account_id, u32 flags, u64 application_id); 40 u32 flags, u64 application_id, Uid account_id);
41 Result CheckSdCardMountStatus(); 41 Result CheckSdCardMountStatus();
42 Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); 42 Result GetSdCardMountStatusChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
43 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id); 43 Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
diff --git a/src/core/hle/service/ns/ns_types.h b/src/core/hle/service/ns/ns_types.h
index 38421b0f4..2dd664c4e 100644
--- a/src/core/hle/service/ns/ns_types.h
+++ b/src/core/hle/service/ns/ns_types.h
@@ -108,4 +108,9 @@ struct ContentPath {
108}; 108};
109static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size."); 109static_assert(sizeof(ContentPath) == 0x10, "ContentPath has incorrect size.");
110 110
111struct Uid {
112 alignas(8) Common::UUID uuid;
113};
114static_assert(sizeof(Uid) == 0x10, "Uid has incorrect size.");
115
111} // namespace Service::NS 116} // namespace Service::NS
diff --git a/src/core/hle/service/ns/query_service.cpp b/src/core/hle/service/ns/query_service.cpp
index 946b7fa23..138400541 100644
--- a/src/core/hle/service/ns/query_service.cpp
+++ b/src/core/hle/service/ns/query_service.cpp
@@ -41,8 +41,7 @@ IQueryService::IQueryService(Core::System& system_) : ServiceFramework{system_,
41IQueryService::~IQueryService() = default; 41IQueryService::~IQueryService() = default;
42 42
43Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId( 43Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
44 Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, 44 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id) {
45 u64 application_id) {
46 // TODO(German77): Read statistics of the game 45 // TODO(German77): Read statistics of the game
47 *out_play_statistics = { 46 *out_play_statistics = {
48 .application_id = application_id, 47 .application_id = application_id,
@@ -50,7 +49,7 @@ Result IQueryService::QueryPlayStatisticsByApplicationIdAndUserAccountId(
50 }; 49 };
51 50
52 LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}", 51 LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id={:016X}, account_id={}",
53 unknown, application_id, account_id.FormattedString()); 52 unknown, application_id, account_id.uuid.FormattedString());
54 R_SUCCEED(); 53 R_SUCCEED();
55} 54}
56 55
diff --git a/src/core/hle/service/ns/query_service.h b/src/core/hle/service/ns/query_service.h
index 6cdbfa277..c4c82b752 100644
--- a/src/core/hle/service/ns/query_service.h
+++ b/src/core/hle/service/ns/query_service.h
@@ -5,6 +5,7 @@
5 5
6#include "common/uuid.h" 6#include "common/uuid.h"
7#include "core/hle/service/cmif_types.h" 7#include "core/hle/service/cmif_types.h"
8#include "core/hle/service/ns/ns_types.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
10namespace Service::NS { 11namespace Service::NS {
@@ -29,8 +30,7 @@ public:
29 30
30private: 31private:
31 Result QueryPlayStatisticsByApplicationIdAndUserAccountId( 32 Result QueryPlayStatisticsByApplicationIdAndUserAccountId(
32 Out<PlayStatistics> out_play_statistics, bool unknown, Common::UUID account_id, 33 Out<PlayStatistics> out_play_statistics, bool unknown, u64 application_id, Uid account_id);
33 u64 application_id);
34}; 34};
35 35
36} // namespace Service::NS 36} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 250d01de3..0265d55f2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -92,11 +92,11 @@ NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_a
92 92
93 bool must_unmark_fail = !is_allocation; 93 bool must_unmark_fail = !is_allocation;
94 const u32 event_id = params.value.raw; 94 const u32 event_id = params.value.raw;
95 SCOPE_EXIT({ 95 SCOPE_EXIT {
96 if (must_unmark_fail) { 96 if (must_unmark_fail) {
97 events[event_id].fails = 0; 97 events[event_id].fails = 0;
98 } 98 }
99 }); 99 };
100 100
101 const u32 fence_id = static_cast<u32>(params.fence.id); 101 const u32 fence_id = static_cast<u32>(params.fence.id);
102 102
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 241006cc8..258970fd5 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -154,10 +154,10 @@ void NVDRV::Close(HLERequestContext& ctx) {
154void NVDRV::Initialize(HLERequestContext& ctx) { 154void NVDRV::Initialize(HLERequestContext& ctx) {
155 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 155 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
156 IPC::ResponseBuilder rb{ctx, 3}; 156 IPC::ResponseBuilder rb{ctx, 3};
157 SCOPE_EXIT({ 157 SCOPE_EXIT {
158 rb.Push(ResultSuccess); 158 rb.Push(ResultSuccess);
159 rb.PushEnum(NvResult::Success); 159 rb.PushEnum(NvResult::Success);
160 }); 160 };
161 161
162 if (is_initialized) { 162 if (is_initialized) {
163 // No need to initialize again 163 // No need to initialize again
diff --git a/src/core/hle/service/nvnflinger/display.h b/src/core/hle/service/nvnflinger/display.h
index f27cbf144..40aa59787 100644
--- a/src/core/hle/service/nvnflinger/display.h
+++ b/src/core/hle/service/nvnflinger/display.h
@@ -3,8 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <list>
7
8#include "core/hle/service/nvnflinger/buffer_item_consumer.h" 6#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
9#include "core/hle/service/nvnflinger/hwc_layer.h" 7#include "core/hle/service/nvnflinger/hwc_layer.h"
10 8
@@ -26,18 +24,12 @@ struct Layer {
26}; 24};
27 25
28struct LayerStack { 26struct LayerStack {
29 std::list<Layer> layers; 27 std::vector<std::shared_ptr<Layer>> layers;
30};
31
32struct Display {
33 explicit Display(u64 id_) {
34 id = id_;
35 }
36 28
37 Layer* FindLayer(s32 consumer_id) { 29 std::shared_ptr<Layer> FindLayer(s32 consumer_id) {
38 for (auto& layer : stack.layers) { 30 for (auto& layer : layers) {
39 if (layer.consumer_id == consumer_id) { 31 if (layer->consumer_id == consumer_id) {
40 return &layer; 32 return layer;
41 } 33 }
42 } 34 }
43 35
@@ -45,7 +37,13 @@ struct Display {
45 } 37 }
46 38
47 bool HasLayers() { 39 bool HasLayers() {
48 return !stack.layers.empty(); 40 return !layers.empty();
41 }
42};
43
44struct Display {
45 explicit Display(u64 id_) {
46 id = id_;
49 } 47 }
50 48
51 u64 id; 49 u64 id;
diff --git a/src/core/hle/service/nvnflinger/hardware_composer.cpp b/src/core/hle/service/nvnflinger/hardware_composer.cpp
index 02215a786..f2dfe85a9 100644
--- a/src/core/hle/service/nvnflinger/hardware_composer.cpp
+++ b/src/core/hle/service/nvnflinger/hardware_composer.cpp
@@ -55,10 +55,10 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
55 55
56 // Acquire all necessary framebuffers. 56 // Acquire all necessary framebuffers.
57 for (auto& layer : display.stack.layers) { 57 for (auto& layer : display.stack.layers) {
58 auto consumer_id = layer.consumer_id; 58 auto consumer_id = layer->consumer_id;
59 59
60 // Try to fetch the framebuffer (either new or stale). 60 // Try to fetch the framebuffer (either new or stale).
61 const auto result = this->CacheFramebufferLocked(layer, consumer_id); 61 const auto result = this->CacheFramebufferLocked(*layer, consumer_id);
62 62
63 // If we failed, skip this layer. 63 // If we failed, skip this layer.
64 if (result == CacheStatus::NoBufferAvailable) { 64 if (result == CacheStatus::NoBufferAvailable) {
@@ -75,7 +75,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
75 const auto& igbp_buffer = *item.graphic_buffer; 75 const auto& igbp_buffer = *item.graphic_buffer;
76 76
77 // TODO: get proper Z-index from layer 77 // TODO: get proper Z-index from layer
78 if (layer.visible) { 78 if (layer->visible) {
79 composition_stack.emplace_back(HwcLayer{ 79 composition_stack.emplace_back(HwcLayer{
80 .buffer_handle = igbp_buffer.BufferId(), 80 .buffer_handle = igbp_buffer.BufferId(),
81 .offset = igbp_buffer.Offset(), 81 .offset = igbp_buffer.Offset(),
@@ -84,7 +84,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
84 .height = igbp_buffer.Height(), 84 .height = igbp_buffer.Height(),
85 .stride = igbp_buffer.Stride(), 85 .stride = igbp_buffer.Stride(),
86 .z_index = 0, 86 .z_index = 0,
87 .blending = layer.blending, 87 .blending = layer->blending,
88 .transform = static_cast<android::BufferTransformFlags>(item.transform), 88 .transform = static_cast<android::BufferTransformFlags>(item.transform),
89 .crop_rect = item.crop, 89 .crop_rect = item.crop,
90 .acquire_fence = item.fence, 90 .acquire_fence = item.fence,
@@ -134,7 +134,7 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, Display& display,
134 continue; 134 continue;
135 } 135 }
136 136
137 if (auto* layer = display.FindLayer(layer_id); layer != nullptr) { 137 if (const auto layer = display.stack.FindLayer(layer_id); layer != nullptr) {
138 // TODO: support release fence 138 // TODO: support release fence
139 // This is needed to prevent screen tearing 139 // This is needed to prevent screen tearing
140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence()); 140 layer->buffer_item_consumer->ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
@@ -153,7 +153,7 @@ void HardwareComposer::RemoveLayerLocked(Display& display, ConsumerId consumer_i
153 } 153 }
154 154
155 // Try to release the buffer item. 155 // Try to release the buffer item.
156 auto* const layer = display.FindLayer(consumer_id); 156 const auto layer = display.stack.FindLayer(consumer_id);
157 if (layer && it->second.is_acquired) { 157 if (layer && it->second.is_acquired) {
158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence()); 158 layer->buffer_item_consumer->ReleaseBuffer(it->second.item, android::Fence::NoFence());
159 } 159 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.cpp b/src/core/hle/service/nvnflinger/surface_flinger.cpp
index 41a705717..8362b65e5 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.cpp
+++ b/src/core/hle/service/nvnflinger/surface_flinger.cpp
@@ -36,7 +36,7 @@ void SurfaceFlinger::RemoveDisplay(u64 display_id) {
36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 36bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
37 u64 display_id) { 37 u64 display_id) {
38 auto* const display = this->FindDisplay(display_id); 38 auto* const display = this->FindDisplay(display_id);
39 if (!display || !display->HasLayers()) { 39 if (!display || !display->stack.HasLayers()) {
40 return false; 40 return false;
41 } 41 }
42 42
@@ -46,19 +46,34 @@ bool SurfaceFlinger::ComposeDisplay(s32* out_swap_interval, f32* out_compose_spe
46 return true; 46 return true;
47} 47}
48 48
49void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) { 49void SurfaceFlinger::CreateLayer(s32 consumer_binder_id) {
50 auto* const display = this->FindDisplay(display_id);
51 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>( 50 auto binder = std::static_pointer_cast<android::BufferQueueConsumer>(
52 m_server.TryGetBinder(consumer_binder_id)); 51 m_server.TryGetBinder(consumer_binder_id));
53 52 if (!binder) {
54 if (!display || !binder) {
55 return; 53 return;
56 } 54 }
57 55
58 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder)); 56 auto buffer_item_consumer = std::make_shared<android::BufferItemConsumer>(std::move(binder));
59 buffer_item_consumer->Connect(false); 57 buffer_item_consumer->Connect(false);
60 58
61 display->stack.layers.emplace_back(std::move(buffer_item_consumer), consumer_binder_id); 59 m_layers.layers.emplace_back(
60 std::make_shared<Layer>(std::move(buffer_item_consumer), consumer_binder_id));
61}
62
63void SurfaceFlinger::DestroyLayer(s32 consumer_binder_id) {
64 std::erase_if(m_layers.layers,
65 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
66}
67
68void SurfaceFlinger::AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id) {
69 auto* const display = this->FindDisplay(display_id);
70 auto layer = this->FindLayer(consumer_binder_id);
71
72 if (!display || !layer) {
73 return;
74 }
75
76 display->stack.layers.emplace_back(std::move(layer));
62} 77}
63 78
64void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) { 79void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id) {
@@ -69,18 +84,18 @@ void SurfaceFlinger::RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_bi
69 84
70 m_composer.RemoveLayerLocked(*display, consumer_binder_id); 85 m_composer.RemoveLayerLocked(*display, consumer_binder_id);
71 std::erase_if(display->stack.layers, 86 std::erase_if(display->stack.layers,
72 [&](auto& layer) { return layer.consumer_id == consumer_binder_id; }); 87 [&](auto& layer) { return layer->consumer_id == consumer_binder_id; });
73} 88}
74 89
75void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) { 90void SurfaceFlinger::SetLayerVisibility(s32 consumer_binder_id, bool visible) {
76 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 91 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
77 layer->visible = visible; 92 layer->visible = visible;
78 return; 93 return;
79 } 94 }
80} 95}
81 96
82void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) { 97void SurfaceFlinger::SetLayerBlending(s32 consumer_binder_id, LayerBlending blending) {
83 if (auto* layer = this->FindLayer(consumer_binder_id); layer != nullptr) { 98 if (const auto layer = this->FindLayer(consumer_binder_id); layer != nullptr) {
84 layer->blending = blending; 99 layer->blending = blending;
85 return; 100 return;
86 } 101 }
@@ -96,9 +111,9 @@ Display* SurfaceFlinger::FindDisplay(u64 display_id) {
96 return nullptr; 111 return nullptr;
97} 112}
98 113
99Layer* SurfaceFlinger::FindLayer(s32 consumer_binder_id) { 114std::shared_ptr<Layer> SurfaceFlinger::FindLayer(s32 consumer_binder_id) {
100 for (auto& display : m_displays) { 115 for (auto& layer : m_layers.layers) {
101 if (auto* layer = display.FindLayer(consumer_binder_id); layer != nullptr) { 116 if (layer->consumer_id == consumer_binder_id) {
102 return layer; 117 return layer;
103 } 118 }
104 } 119 }
diff --git a/src/core/hle/service/nvnflinger/surface_flinger.h b/src/core/hle/service/nvnflinger/surface_flinger.h
index d8c53fbda..406281c83 100644
--- a/src/core/hle/service/nvnflinger/surface_flinger.h
+++ b/src/core/hle/service/nvnflinger/surface_flinger.h
@@ -36,6 +36,9 @@ public:
36 void RemoveDisplay(u64 display_id); 36 void RemoveDisplay(u64 display_id);
37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 37 bool ComposeDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
38 38
39 void CreateLayer(s32 consumer_binder_id);
40 void DestroyLayer(s32 consumer_binder_id);
41
39 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id); 42 void AddLayerToDisplayStack(u64 display_id, s32 consumer_binder_id);
40 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id); 43 void RemoveLayerFromDisplayStack(u64 display_id, s32 consumer_binder_id);
41 44
@@ -44,7 +47,7 @@ public:
44 47
45private: 48private:
46 Display* FindDisplay(u64 display_id); 49 Display* FindDisplay(u64 display_id);
47 Layer* FindLayer(s32 consumer_binder_id); 50 std::shared_ptr<Layer> FindLayer(s32 consumer_binder_id);
48 51
49public: 52public:
50 // TODO: these don't belong here 53 // TODO: these don't belong here
@@ -57,6 +60,7 @@ private:
57 KernelHelpers::ServiceContext m_context; 60 KernelHelpers::ServiceContext m_context;
58 61
59 std::vector<Display> m_displays; 62 std::vector<Display> m_displays;
63 LayerStack m_layers;
60 std::shared_ptr<Nvidia::Module> nvdrv; 64 std::shared_ptr<Nvidia::Module> nvdrv;
61 s32 disp_fd; 65 s32 disp_fd;
62 HardwareComposer m_composer; 66 HardwareComposer m_composer;
diff --git a/src/core/hle/service/olsc/daemon_controller.cpp b/src/core/hle/service/olsc/daemon_controller.cpp
new file mode 100644
index 000000000..7823780a8
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/daemon_controller.h"
6
7namespace Service::OLSC {
8
9IDaemonController::IDaemonController(Core::System& system_)
10 : ServiceFramework{system_, "IDaemonController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IDaemonController::GetAutoTransferEnabledForAccountAndApplication>, "GetAutoTransferEnabledForAccountAndApplication"},
14 {1, nullptr, "SetAutoTransferEnabledForAccountAndApplication"},
15 {2, nullptr, "GetGlobalUploadEnabledForAccount"},
16 {3, nullptr, "SetGlobalUploadEnabledForAccount"},
17 {4, nullptr, "TouchAccount"},
18 {5, nullptr, "GetGlobalDownloadEnabledForAccount"},
19 {6, nullptr, "SetGlobalDownloadEnabledForAccount"},
20 {10, nullptr, "GetForbiddenSaveDataIndication"},
21 {11, nullptr, "GetStopperObject"},
22 {12, nullptr, "GetState"},
23 };
24 // clang-format on
25
26 RegisterHandlers(functions);
27}
28
29IDaemonController::~IDaemonController() = default;
30
31Result IDaemonController::GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
32 Common::UUID user_id,
33 u64 application_id) {
34 LOG_WARNING(Service_OLSC, "(STUBBED) called, user_id={} application_id={:016X}",
35 user_id.FormattedString(), application_id);
36 *out_is_enabled = false;
37 R_SUCCEED();
38}
39
40} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/daemon_controller.h b/src/core/hle/service/olsc/daemon_controller.h
new file mode 100644
index 000000000..dfad7f52a
--- /dev/null
+++ b/src/core/hle/service/olsc/daemon_controller.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/uuid.h"
5#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/service.h"
7
8namespace Service::OLSC {
9
10class IDaemonController final : public ServiceFramework<IDaemonController> {
11public:
12 explicit IDaemonController(Core::System& system_);
13 ~IDaemonController() override;
14
15private:
16 Result GetAutoTransferEnabledForAccountAndApplication(Out<bool> out_is_enabled,
17 Common::UUID user_id, u64 application_id);
18};
19
20} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.cpp b/src/core/hle/service/olsc/native_handle_holder.cpp
new file mode 100644
index 000000000..3cb5d7b11
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/native_handle_holder.h"
6
7namespace Service::OLSC {
8
9INativeHandleHolder::INativeHandleHolder(Core::System& system_)
10 : ServiceFramework{system_, "INativeHandleHolder"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&INativeHandleHolder::GetNativeHandle>, "GetNativeHandle"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20INativeHandleHolder::~INativeHandleHolder() = default;
21
22Result INativeHandleHolder::GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
23 LOG_WARNING(Service_OLSC, "(STUBBED) called");
24 *out_event = nullptr;
25 R_SUCCEED();
26}
27
28} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/native_handle_holder.h b/src/core/hle/service/olsc/native_handle_holder.h
new file mode 100644
index 000000000..a44754c20
--- /dev/null
+++ b/src/core/hle/service/olsc/native_handle_holder.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Kernel {
8class KReadableEvent;
9}
10
11namespace Service::OLSC {
12
13class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
14public:
15 explicit INativeHandleHolder(Core::System& system_);
16 ~INativeHandleHolder() override;
17
18private:
19 Result GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
20};
21
22} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 889f27c31..18e5ad43f 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -1,226 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/ipc_helpers.h"
5#include "core/hle/service/olsc/olsc.h" 4#include "core/hle/service/olsc/olsc.h"
5#include "core/hle/service/olsc/olsc_service_for_application.h"
6#include "core/hle/service/olsc/olsc_service_for_system_service.h"
6#include "core/hle/service/server_manager.h" 7#include "core/hle/service/server_manager.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Service::OLSC { 10namespace Service::OLSC {
10 11
11class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
12public:
13 explicit IOlscServiceForApplication(Core::System& system_)
14 : ServiceFramework{system_, "olsc:u"} {
15 // clang-format off
16 static const FunctionInfo functions[] = {
17 {0, &IOlscServiceForApplication::Initialize, "Initialize"},
18 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
19 {13, &IOlscServiceForApplication::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
20 {14, &IOlscServiceForApplication::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
21 {15, nullptr, "SetCustomData"},
22 {16, nullptr, "DeleteSaveDataBackupSetting"},
23 {18, nullptr, "GetSaveDataBackupInfoCache"},
24 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
25 {22, nullptr, "DeleteSaveDataBackupAsync"},
26 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
27 {26, nullptr, "DownloadSaveDataBackupAsync"},
28 {27, nullptr, "UploadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
32 {9015, nullptr, "SetCustomDataForDebug"},
33 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
34 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
35 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
36 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
37 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
38 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43 }
44
45private:
46 void Initialize(HLERequestContext& ctx) {
47 LOG_WARNING(Service_OLSC, "(STUBBED) called");
48
49 initialized = true;
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53 }
54
55 void GetSaveDataBackupSetting(HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 // backup_setting is set to 0 since real value is unknown
59 constexpr u64 backup_setting = 0;
60
61 IPC::ResponseBuilder rb{ctx, 4};
62 rb.Push(ResultSuccess);
63 rb.Push(backup_setting);
64 }
65
66 void SetSaveDataBackupSettingEnabled(HLERequestContext& ctx) {
67 LOG_WARNING(Service_OLSC, "(STUBBED) called");
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(ResultSuccess);
71 }
72
73 bool initialized{};
74};
75
76class INativeHandleHolder final : public ServiceFramework<INativeHandleHolder> {
77public:
78 explicit INativeHandleHolder(Core::System& system_)
79 : ServiceFramework{system_, "INativeHandleHolder"} {
80 // clang-format off
81 static const FunctionInfo functions[] = {
82 {0, nullptr, "GetNativeHandle"},
83 };
84 // clang-format on
85
86 RegisterHandlers(functions);
87 }
88};
89
90class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
91public:
92 explicit ITransferTaskListController(Core::System& system_)
93 : ServiceFramework{system_, "ITransferTaskListController"} {
94 // clang-format off
95 static const FunctionInfo functions[] = {
96 {0, nullptr, "Unknown0"},
97 {1, nullptr, "Unknown1"},
98 {2, nullptr, "Unknown2"},
99 {3, nullptr, "Unknown3"},
100 {4, nullptr, "Unknown4"},
101 {5, &ITransferTaskListController::GetNativeHandleHolder , "GetNativeHandleHolder"},
102 {6, nullptr, "Unknown6"},
103 {7, nullptr, "Unknown7"},
104 {8, nullptr, "GetRemoteStorageController"},
105 {9, &ITransferTaskListController::GetNativeHandleHolder, "GetNativeHandleHolder2"},
106 {10, nullptr, "Unknown10"},
107 {11, nullptr, "Unknown11"},
108 {12, nullptr, "Unknown12"},
109 {13, nullptr, "Unknown13"},
110 {14, nullptr, "Unknown14"},
111 {15, nullptr, "Unknown15"},
112 {16, nullptr, "Unknown16"},
113 {17, nullptr, "Unknown17"},
114 {18, nullptr, "Unknown18"},
115 {19, nullptr, "Unknown19"},
116 {20, nullptr, "Unknown20"},
117 {21, nullptr, "Unknown21"},
118 {22, nullptr, "Unknown22"},
119 {23, nullptr, "Unknown23"},
120 {24, nullptr, "Unknown24"},
121 {25, nullptr, "Unknown25"},
122 };
123 // clang-format on
124
125 RegisterHandlers(functions);
126 }
127
128private:
129 void GetNativeHandleHolder(HLERequestContext& ctx) {
130 LOG_INFO(Service_OLSC, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<INativeHandleHolder>(system);
135 }
136};
137
138class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
139public:
140 explicit IOlscServiceForSystemService(Core::System& system_)
141 : ServiceFramework{system_, "olsc:s"} {
142 // clang-format off
143 static const FunctionInfo functions[] = {
144 {0, &IOlscServiceForSystemService::OpenTransferTaskListController, "OpenTransferTaskListController"},
145 {1, nullptr, "OpenRemoteStorageController"},
146 {2, nullptr, "OpenDaemonController"},
147 {10, nullptr, "Unknown10"},
148 {11, nullptr, "Unknown11"},
149 {12, nullptr, "Unknown12"},
150 {13, nullptr, "Unknown13"},
151 {100, nullptr, "ListLastTransferTaskErrorInfo"},
152 {101, nullptr, "GetLastErrorInfoCount"},
153 {102, nullptr, "RemoveLastErrorInfoOld"},
154 {103, nullptr, "GetLastErrorInfo"},
155 {104, nullptr, "GetLastErrorEventHolder"},
156 {105, nullptr, "GetLastTransferTaskErrorInfo"},
157 {200, nullptr, "GetDataTransferPolicyInfo"},
158 {201, nullptr, "RemoveDataTransferPolicyInfo"},
159 {202, nullptr, "UpdateDataTransferPolicyOld"},
160 {203, nullptr, "UpdateDataTransferPolicy"},
161 {204, nullptr, "CleanupDataTransferPolicyInfo"},
162 {205, nullptr, "RequestDataTransferPolicy"},
163 {300, nullptr, "GetAutoTransferSeriesInfo"},
164 {301, nullptr, "UpdateAutoTransferSeriesInfo"},
165 {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
166 {900, nullptr, "CleanupTransferTask"},
167 {902, nullptr, "CleanupSeriesInfoType0"},
168 {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
169 {904, nullptr, "CleanupApplicationAutoTransferSetting"},
170 {905, nullptr, "CleanupErrorHistory"},
171 {906, nullptr, "SetLastError"},
172 {907, nullptr, "AddSaveDataArchiveInfoType0"},
173 {908, nullptr, "RemoveSeriesInfoType0"},
174 {909, nullptr, "GetSeriesInfoType0"},
175 {910, nullptr, "RemoveLastErrorInfo"},
176 {911, nullptr, "CleanupSeriesInfoType1"},
177 {912, nullptr, "RemoveSeriesInfoType1"},
178 {913, nullptr, "GetSeriesInfoType1"},
179 {1000, nullptr, "UpdateIssueOld"},
180 {1010, nullptr, "Unknown1010"},
181 {1011, nullptr, "ListIssueInfoOld"},
182 {1012, nullptr, "GetIssueOld"},
183 {1013, nullptr, "GetIssue2Old"},
184 {1014, nullptr, "GetIssue3Old"},
185 {1020, nullptr, "RepairIssueOld"},
186 {1021, nullptr, "RepairIssueWithUserIdOld"},
187 {1022, nullptr, "RepairIssue2Old"},
188 {1023, nullptr, "RepairIssue3Old"},
189 {1024, nullptr, "Unknown1024"},
190 {1100, nullptr, "UpdateIssue"},
191 {1110, nullptr, "Unknown1110"},
192 {1111, nullptr, "ListIssueInfo"},
193 {1112, nullptr, "GetIssue"},
194 {1113, nullptr, "GetIssue2"},
195 {1114, nullptr, "GetIssue3"},
196 {1120, nullptr, "RepairIssue"},
197 {1121, nullptr, "RepairIssueWithUserId"},
198 {1122, nullptr, "RepairIssue2"},
199 {1123, nullptr, "RepairIssue3"},
200 {1124, nullptr, "Unknown1124"},
201 };
202 // clang-format on
203
204 RegisterHandlers(functions);
205 }
206
207private:
208 void OpenTransferTaskListController(HLERequestContext& ctx) {
209 LOG_INFO(Service_OLSC, "called");
210
211 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
212 rb.Push(ResultSuccess);
213 rb.PushIpcInterface<ITransferTaskListController>(system);
214 }
215};
216
217void LoopProcess(Core::System& system) { 12void LoopProcess(Core::System& system) {
218 auto server_manager = std::make_unique<ServerManager>(system); 13 auto server_manager = std::make_unique<ServerManager>(system);
219 14
220 server_manager->RegisterNamedService("olsc:u", 15 const auto OlscFactoryForApplication = [&] {
221 std::make_shared<IOlscServiceForApplication>(system)); 16 return std::make_shared<IOlscServiceForApplication>(system);
222 server_manager->RegisterNamedService("olsc:s", 17 };
223 std::make_shared<IOlscServiceForSystemService>(system)); 18
19 const auto OlscFactoryForSystemService = [&] {
20 return std::make_shared<IOlscServiceForSystemService>(system);
21 };
22
23 server_manager->RegisterNamedService("olsc:u", OlscFactoryForApplication);
24 server_manager->RegisterNamedService("olsc:s", OlscFactoryForSystemService);
224 25
225 ServerManager::RunServer(std::move(server_manager)); 26 ServerManager::RunServer(std::move(server_manager));
226} 27}
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.cpp b/src/core/hle/service/olsc/olsc_service_for_application.cpp
new file mode 100644
index 000000000..01360f5ef
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.cpp
@@ -0,0 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/olsc_service_for_application.h"
6
7namespace Service::OLSC {
8
9IOlscServiceForApplication::IOlscServiceForApplication(Core::System& system_)
10 : ServiceFramework{system_, "olsc:u"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IOlscServiceForApplication::Initialize>, "Initialize"},
14 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
15 {13, D<&IOlscServiceForApplication::GetSaveDataBackupSetting>, "GetSaveDataBackupSetting"},
16 {14, D<&IOlscServiceForApplication::SetSaveDataBackupSettingEnabled>, "SetSaveDataBackupSettingEnabled"},
17 {15, nullptr, "SetCustomData"},
18 {16, nullptr, "DeleteSaveDataBackupSetting"},
19 {18, nullptr, "GetSaveDataBackupInfoCache"},
20 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
21 {22, nullptr, "DeleteSaveDataBackupAsync"},
22 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
23 {26, nullptr, "DownloadSaveDataBackupAsync"},
24 {27, nullptr, "UploadSaveDataBackupAsync"},
25 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
26 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
27 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
28 {9015, nullptr, "SetCustomDataForDebug"},
29 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
30 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
31 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
32 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
33 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
34 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IOlscServiceForApplication::~IOlscServiceForApplication() = default;
42
43Result IOlscServiceForApplication::Initialize(ClientProcessId process_id) {
44 LOG_WARNING(Service_OLSC, "(STUBBED) called");
45 initialized = true;
46 R_SUCCEED();
47}
48
49Result IOlscServiceForApplication::GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting) {
50 LOG_WARNING(Service_OLSC, "(STUBBED) called");
51 // backup_setting is set to 0 since real value is unknown
52 *out_save_data_backup_setting = 0;
53 R_SUCCEED();
54}
55
56Result IOlscServiceForApplication::SetSaveDataBackupSettingEnabled(bool enabled,
57 NS::Uid account_id) {
58 LOG_WARNING(Service_OLSC, "(STUBBED) called, enabled={}, account_id={}", enabled,
59 account_id.uuid.FormattedString());
60 R_SUCCEED();
61}
62
63} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_application.h b/src/core/hle/service/olsc/olsc_service_for_application.h
new file mode 100644
index 000000000..3f9ac7536
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_application.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/ns/ns_types.h"
6#include "core/hle/service/service.h"
7
8namespace Service::OLSC {
9
10class IOlscServiceForApplication final : public ServiceFramework<IOlscServiceForApplication> {
11public:
12 explicit IOlscServiceForApplication(Core::System& system_);
13 ~IOlscServiceForApplication() override;
14
15private:
16 Result Initialize(ClientProcessId process_id);
17 Result GetSaveDataBackupSetting(Out<u8> out_save_data_backup_setting);
18 Result SetSaveDataBackupSettingEnabled(bool enabled, NS::Uid account_id);
19
20 bool initialized{};
21};
22
23} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.cpp b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
new file mode 100644
index 000000000..f027933c9
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.cpp
@@ -0,0 +1,117 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/daemon_controller.h"
6#include "core/hle/service/olsc/olsc_service_for_system_service.h"
7#include "core/hle/service/olsc/remote_storage_controller.h"
8#include "core/hle/service/olsc/transfer_task_list_controller.h"
9
10namespace Service::OLSC {
11
12IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_)
13 : ServiceFramework{system_, "olsc:s"} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
17 {1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
18 {2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
19 {10, nullptr, "Unknown10"},
20 {11, nullptr, "Unknown11"},
21 {12, nullptr, "Unknown12"},
22 {13, nullptr, "Unknown13"},
23 {100, nullptr, "ListLastTransferTaskErrorInfo"},
24 {101, nullptr, "GetLastErrorInfoCount"},
25 {102, nullptr, "RemoveLastErrorInfoOld"},
26 {103, nullptr, "GetLastErrorInfo"},
27 {104, nullptr, "GetLastErrorEventHolder"},
28 {105, nullptr, "GetLastTransferTaskErrorInfo"},
29 {200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
30 {201, nullptr, "RemoveDataTransferPolicyInfo"},
31 {202, nullptr, "UpdateDataTransferPolicyOld"},
32 {203, nullptr, "UpdateDataTransferPolicy"},
33 {204, nullptr, "CleanupDataTransferPolicyInfo"},
34 {205, nullptr, "RequestDataTransferPolicy"},
35 {300, nullptr, "GetAutoTransferSeriesInfo"},
36 {301, nullptr, "UpdateAutoTransferSeriesInfo"},
37 {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
38 {900, nullptr, "CleanupTransferTask"},
39 {902, nullptr, "CleanupSeriesInfoType0"},
40 {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
41 {904, nullptr, "CleanupApplicationAutoTransferSetting"},
42 {905, nullptr, "CleanupErrorHistory"},
43 {906, nullptr, "SetLastError"},
44 {907, nullptr, "AddSaveDataArchiveInfoType0"},
45 {908, nullptr, "RemoveSeriesInfoType0"},
46 {909, nullptr, "GetSeriesInfoType0"},
47 {910, nullptr, "RemoveLastErrorInfo"},
48 {911, nullptr, "CleanupSeriesInfoType1"},
49 {912, nullptr, "RemoveSeriesInfoType1"},
50 {913, nullptr, "GetSeriesInfoType1"},
51 {1000, nullptr, "UpdateIssueOld"},
52 {1010, nullptr, "Unknown1010"},
53 {1011, nullptr, "ListIssueInfoOld"},
54 {1012, nullptr, "GetIssueOld"},
55 {1013, nullptr, "GetIssue2Old"},
56 {1014, nullptr, "GetIssue3Old"},
57 {1020, nullptr, "RepairIssueOld"},
58 {1021, nullptr, "RepairIssueWithUserIdOld"},
59 {1022, nullptr, "RepairIssue2Old"},
60 {1023, nullptr, "RepairIssue3Old"},
61 {1024, nullptr, "Unknown1024"},
62 {1100, nullptr, "UpdateIssue"},
63 {1110, nullptr, "Unknown1110"},
64 {1111, nullptr, "ListIssueInfo"},
65 {1112, nullptr, "GetIssue"},
66 {1113, nullptr, "GetIssue2"},
67 {1114, nullptr, "GetIssue3"},
68 {1120, nullptr, "RepairIssue"},
69 {1121, nullptr, "RepairIssueWithUserId"},
70 {1122, nullptr, "RepairIssue2"},
71 {1123, nullptr, "RepairIssue3"},
72 {1124, nullptr, "Unknown1124"},
73 {10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
74 };
75 // clang-format on
76
77 RegisterHandlers(functions);
78}
79
80IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
81
82Result IOlscServiceForSystemService::OpenTransferTaskListController(
83 Out<SharedPointer<ITransferTaskListController>> out_interface) {
84 LOG_INFO(Service_OLSC, "called");
85 *out_interface = std::make_shared<ITransferTaskListController>(system);
86 R_SUCCEED();
87}
88
89Result IOlscServiceForSystemService::OpenRemoteStorageController(
90 Out<SharedPointer<IRemoteStorageController>> out_interface) {
91 LOG_INFO(Service_OLSC, "called");
92 *out_interface = std::make_shared<IRemoteStorageController>(system);
93 R_SUCCEED();
94}
95
96Result IOlscServiceForSystemService::OpenDaemonController(
97 Out<SharedPointer<IDaemonController>> out_interface) {
98 LOG_INFO(Service_OLSC, "called");
99 *out_interface = std::make_shared<IDaemonController>(system);
100 R_SUCCEED();
101}
102
103Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(Out<u16> out_policy_info,
104 u64 application_id) {
105 LOG_WARNING(Service_OLSC, "(STUBBED) called");
106 *out_policy_info = 0;
107 R_SUCCEED();
108}
109
110Result IOlscServiceForSystemService::CloneService(
111 Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
112 LOG_INFO(Service_OLSC, "called");
113 *out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
114 R_SUCCEED();
115}
116
117} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc_service_for_system_service.h b/src/core/hle/service/olsc/olsc_service_for_system_service.h
new file mode 100644
index 000000000..13026272a
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc_service_for_system_service.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class IDaemonController;
10class IRemoteStorageController;
11class ITransferTaskListController;
12
13class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
14public:
15 explicit IOlscServiceForSystemService(Core::System& system_);
16 ~IOlscServiceForSystemService() override;
17
18private:
19 Result OpenTransferTaskListController(
20 Out<SharedPointer<ITransferTaskListController>> out_interface);
21 Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
22 Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
23 Result GetDataTransferPolicyInfo(Out<u16> out_policy_info, u64 application_id);
24 Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
25};
26
27} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.cpp b/src/core/hle/service/olsc/remote_storage_controller.cpp
new file mode 100644
index 000000000..81d9c96ab
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.cpp
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/remote_storage_controller.h"
6
7namespace Service::OLSC {
8
9IRemoteStorageController::IRemoteStorageController(Core::System& system_)
10 : ServiceFramework{system_, "IRemoteStorageController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "GetSaveDataArchiveInfoBySaveDataId"},
14 {1, nullptr, "GetSaveDataArchiveInfoByApplicationId"},
15 {3, nullptr, "GetSaveDataArchiveCount"},
16 {6, nullptr, "CleanupSaveDataArchives"},
17 {7, nullptr, "CreateSaveDataArchiveCacheUpdationTask"},
18 {8, nullptr, "CreateSaveDataArchiveCacheUpdationForSpecifiedApplicationTask"},
19 {9, nullptr, "Delete"},
20 {10, nullptr, "GetSeriesInfo"},
21 {11, nullptr, "CreateDeleteDataTask"},
22 {12, nullptr, "DeleteSeriesInfo"},
23 {13, nullptr, "CreateRegisterNotificationTokenTask"},
24 {14, nullptr, "UpdateSeriesInfo"},
25 {15, nullptr, "RegisterUploadSaveDataTransferTaskForAutonomyRegistration"},
26 {16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
27 {17, nullptr, "ListDataInfo"},
28 {18, nullptr, "GetDataInfo"},
29 {19, nullptr, "Unknown19"},
30 {20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
31 {21, nullptr, "ListSecondarySaves"},
32 {22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
33 {23, nullptr, "TouchSecondarySave"},
34 {24, nullptr, "GetSecondarySaveDataInfo"},
35 {25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
36 {900, nullptr, "Unknown900"},
37 };
38 // clang-format on
39
40 RegisterHandlers(functions);
41}
42
43IRemoteStorageController::~IRemoteStorageController() = default;
44
45Result IRemoteStorageController::GetSecondarySave(Out<bool> out_has_secondary_save,
46 Out<std::array<u64, 3>> out_unknown,
47 u64 application_id) {
48 LOG_ERROR(Service_OLSC, "(STUBBED) called, application_id={:016X}", application_id);
49 *out_has_secondary_save = false;
50 *out_unknown = {};
51 R_SUCCEED();
52}
53
54} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/remote_storage_controller.h b/src/core/hle/service/olsc/remote_storage_controller.h
new file mode 100644
index 000000000..e7a0b5244
--- /dev/null
+++ b/src/core/hle/service/olsc/remote_storage_controller.h
@@ -0,0 +1,19 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class IRemoteStorageController final : public ServiceFramework<IRemoteStorageController> {
10public:
11 explicit IRemoteStorageController(Core::System& system_);
12 ~IRemoteStorageController() override;
13
14private:
15 Result GetSecondarySave(Out<bool> out_has_secondary_save, Out<std::array<u64, 3>> out_unknown,
16 u64 application_id);
17};
18
19} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.cpp b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
new file mode 100644
index 000000000..8ea9a0f1e
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.cpp
@@ -0,0 +1,55 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/olsc/native_handle_holder.h"
6#include "core/hle/service/olsc/transfer_task_list_controller.h"
7
8namespace Service::OLSC {
9
10ITransferTaskListController::ITransferTaskListController(Core::System& system_)
11 : ServiceFramework{system_, "ITransferTaskListController"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, nullptr, "Unknown0"},
15 {1, nullptr, "Unknown1"},
16 {2, nullptr, "Unknown2"},
17 {3, nullptr, "Unknown3"},
18 {4, nullptr, "Unknown4"},
19 {5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
20 {6, nullptr, "Unknown6"},
21 {7, nullptr, "Unknown7"},
22 {8, nullptr, "GetRemoteStorageController"},
23 {9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
24 {10, nullptr, "Unknown10"},
25 {11, nullptr, "Unknown11"},
26 {12, nullptr, "Unknown12"},
27 {13, nullptr, "Unknown13"},
28 {14, nullptr, "Unknown14"},
29 {15, nullptr, "Unknown15"},
30 {16, nullptr, "Unknown16"},
31 {17, nullptr, "Unknown17"},
32 {18, nullptr, "Unknown18"},
33 {19, nullptr, "Unknown19"},
34 {20, nullptr, "Unknown20"},
35 {21, nullptr, "Unknown21"},
36 {22, nullptr, "Unknown22"},
37 {23, nullptr, "Unknown23"},
38 {24, nullptr, "Unknown24"},
39 {25, nullptr, "Unknown25"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ITransferTaskListController::~ITransferTaskListController() = default;
47
48Result ITransferTaskListController::GetNativeHandleHolder(
49 Out<SharedPointer<INativeHandleHolder>> out_holder) {
50 LOG_WARNING(Service_OLSC, "(STUBBED) called");
51 *out_holder = std::make_shared<INativeHandleHolder>(system);
52 R_SUCCEED();
53}
54
55} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/transfer_task_list_controller.h b/src/core/hle/service/olsc/transfer_task_list_controller.h
new file mode 100644
index 000000000..f10a71375
--- /dev/null
+++ b/src/core/hle/service/olsc/transfer_task_list_controller.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_types.h"
5#include "core/hle/service/service.h"
6
7namespace Service::OLSC {
8
9class INativeHandleHolder;
10
11class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
12public:
13 explicit ITransferTaskListController(Core::System& system_);
14 ~ITransferTaskListController() override;
15
16private:
17 Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
18};
19
20} // namespace Service::OLSC
diff --git a/src/core/hle/service/pctl/parental_control_service.cpp b/src/core/hle/service/pctl/parental_control_service.cpp
new file mode 100644
index 000000000..f57f2f157
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.cpp
@@ -0,0 +1,434 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/file_sys/control_metadata.h"
6#include "core/file_sys/patch_manager.h"
7#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/pctl/parental_control_service.h"
9#include "core/hle/service/pctl/pctl_results.h"
10
11namespace Service::PCTL {
12
13IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
14 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
15 service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
16 unlinked_event{service_context}, request_suspension_event{service_context} {
17 // clang-format off
18 static const FunctionInfo functions[] = {
19 {1, D<&IParentalControlService::Initialize>, "Initialize"},
20 {1001, D<&IParentalControlService::CheckFreeCommunicationPermission>, "CheckFreeCommunicationPermission"},
21 {1002, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
22 {1003, D<&IParentalControlService::ConfirmResumeApplicationPermission>, "ConfirmResumeApplicationPermission"},
23 {1004, D<&IParentalControlService::ConfirmSnsPostPermission>, "ConfirmSnsPostPermission"},
24 {1005, nullptr, "ConfirmSystemSettingsPermission"},
25 {1006, D<&IParentalControlService::IsRestrictionTemporaryUnlocked>, "IsRestrictionTemporaryUnlocked"},
26 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
27 {1008, nullptr, "EnterRestrictedSystemSettings"},
28 {1009, nullptr, "LeaveRestrictedSystemSettings"},
29 {1010, D<&IParentalControlService::IsRestrictedSystemSettingsEntered>, "IsRestrictedSystemSettingsEntered"},
30 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
31 {1012, nullptr, "GetRestrictedFeatures"},
32 {1013, D<&IParentalControlService::ConfirmStereoVisionPermission>, "ConfirmStereoVisionPermission"},
33 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
34 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
35 {1016, nullptr, "ConfirmShowNewsPermission"},
36 {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
37 {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
38 {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
39 {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
40 {1033, nullptr, "SetSafetyLevel"},
41 {1034, nullptr, "GetSafetyLevelSettings"},
42 {1035, D<&IParentalControlService::GetCurrentSettings>, "GetCurrentSettings"},
43 {1036, nullptr, "SetCustomSafetyLevelSettings"},
44 {1037, nullptr, "GetDefaultRatingOrganization"},
45 {1038, nullptr, "SetDefaultRatingOrganization"},
46 {1039, D<&IParentalControlService::GetFreeCommunicationApplicationListCount>, "GetFreeCommunicationApplicationListCount"},
47 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
48 {1043, nullptr, "DeleteSettings"},
49 {1044, nullptr, "GetFreeCommunicationApplicationList"},
50 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
51 {1046, nullptr, "DisableFeaturesForReset"},
52 {1047, nullptr, "NotifyApplicationDownloadStarted"},
53 {1048, nullptr, "NotifyNetworkProfileCreated"},
54 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
55 {1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
56 {1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
57 {1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
58 {1064, D<&IParentalControlService::ResetConfirmedStereoVisionPermission>, "ResetConfirmedStereoVisionPermission"},
59 {1065, D<&IParentalControlService::IsStereoVisionPermitted>, "IsStereoVisionPermitted"},
60 {1201, nullptr, "UnlockRestrictionTemporarily"},
61 {1202, nullptr, "UnlockSystemSettingsRestriction"},
62 {1203, nullptr, "SetPinCode"},
63 {1204, nullptr, "GenerateInquiryCode"},
64 {1205, nullptr, "CheckMasterKey"},
65 {1206, D<&IParentalControlService::GetPinCodeLength>, "GetPinCodeLength"},
66 {1207, nullptr, "GetPinCodeChangedEvent"},
67 {1208, nullptr, "GetPinCode"},
68 {1403, D<&IParentalControlService::IsPairingActive>, "IsPairingActive"},
69 {1406, nullptr, "GetSettingsLastUpdated"},
70 {1411, nullptr, "GetPairingAccountInfo"},
71 {1421, nullptr, "GetAccountNickname"},
72 {1424, nullptr, "GetAccountState"},
73 {1425, nullptr, "RequestPostEvents"},
74 {1426, nullptr, "GetPostEventInterval"},
75 {1427, nullptr, "SetPostEventInterval"},
76 {1432, D<&IParentalControlService::GetSynchronizationEvent>, "GetSynchronizationEvent"},
77 {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
78 {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
79 {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
80 {1454, nullptr, "GetPlayTimerRemainingTime"},
81 {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
82 {1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
83 {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
84 {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
85 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
86 {1472, nullptr, "CancelNetworkRequest"},
87 {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
88 {1474, nullptr, "ClearUnlinkedEvent"},
89 {1601, nullptr, "DisableAllFeatures"},
90 {1602, nullptr, "PostEnableAllFeatures"},
91 {1603, nullptr, "IsAllFeaturesDisabled"},
92 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
93 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
94 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
95 {1904, nullptr, "GetExemptApplicationListForDebug"},
96 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
97 {1906, nullptr, "AddToExemptApplicationListForDebug"},
98 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
99 {1908, nullptr, "ClearExemptApplicationListForDebug"},
100 {1941, nullptr, "DeletePairing"},
101 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
102 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
103 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
104 {2001, nullptr, "RequestPairingAsync"},
105 {2002, nullptr, "FinishRequestPairing"},
106 {2003, nullptr, "AuthorizePairingAsync"},
107 {2004, nullptr, "FinishAuthorizePairing"},
108 {2005, nullptr, "RetrievePairingInfoAsync"},
109 {2006, nullptr, "FinishRetrievePairingInfo"},
110 {2007, nullptr, "UnlinkPairingAsync"},
111 {2008, nullptr, "FinishUnlinkPairing"},
112 {2009, nullptr, "GetAccountMiiImageAsync"},
113 {2010, nullptr, "FinishGetAccountMiiImage"},
114 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
115 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
116 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
117 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
118 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
119 {2016, nullptr, "RequestUpdateExemptionListAsync"},
120 };
121 // clang-format on
122 RegisterHandlers(functions);
123}
124
125IParentalControlService::~IParentalControlService() = default;
126
127bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
128 if (states.temporary_unlocked) {
129 return true;
130 }
131 if ((states.application_info.parental_control_flag & 1) == 0) {
132 return true;
133 }
134 if (pin_code[0] == '\0') {
135 return true;
136 }
137 if (!settings.is_free_communication_default_on) {
138 return true;
139 }
140 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
141 // but as we don't have multiproceses support yet, we can just assume our application is
142 // valid for the time being
143 return true;
144}
145
146bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
147 if (states.temporary_unlocked) {
148 return true;
149 }
150 if (pin_code[0] == '\0') {
151 return true;
152 }
153 if (!settings.is_stero_vision_restricted) {
154 return false;
155 }
156 return true;
157}
158
159void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
160 if (settings.disabled) {
161 return;
162 }
163
164 if (pin_code[0] == '\0') {
165 return;
166 }
167 settings.is_stero_vision_restricted = is_restricted;
168}
169
170Result IParentalControlService::Initialize() {
171 LOG_DEBUG(Service_PCTL, "called");
172
173 if (False(capability & (Capability::Application | Capability::System))) {
174 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
175 R_THROW(PCTL::ResultNoCapability);
176 }
177
178 // TODO(ogniK): Recovery flag initialization for pctl:r
179
180 const auto program_id = system.GetApplicationProcessProgramID();
181 if (program_id != 0) {
182 const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
183 system.GetContentProvider()};
184 const auto control = pm.GetControlMetadata();
185 if (control.first) {
186 states.tid_from_event = 0;
187 states.launch_time_valid = false;
188 states.is_suspended = false;
189 states.free_communication = false;
190 states.stereo_vision = false;
191 states.application_info = ApplicationInfo{
192 .application_id = program_id,
193 .age_rating = control.first->GetRatingAge(),
194 .parental_control_flag = control.first->GetParentalControlFlag(),
195 .capability = capability,
196 };
197
198 if (False(capability & (Capability::System | Capability::Recovery))) {
199 // TODO(ogniK): Signal application launch event
200 }
201 }
202 }
203
204 R_SUCCEED();
205}
206
207Result IParentalControlService::CheckFreeCommunicationPermission() {
208 LOG_DEBUG(Service_PCTL, "called");
209
210 if (!CheckFreeCommunicationPermissionImpl()) {
211 R_THROW(PCTL::ResultNoFreeCommunication);
212 } else {
213 states.free_communication = true;
214 R_SUCCEED();
215 }
216}
217
218Result IParentalControlService::ConfirmLaunchApplicationPermission(
219 InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
220 LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
221 application_id);
222 R_SUCCEED();
223}
224
225Result IParentalControlService::ConfirmResumeApplicationPermission(
226 InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
227 LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
228 application_id);
229 R_SUCCEED();
230}
231
232Result IParentalControlService::ConfirmSnsPostPermission() {
233 LOG_WARNING(Service_PCTL, "(STUBBED) called");
234 R_THROW(PCTL::ResultNoFreeCommunication);
235}
236
237Result IParentalControlService::IsRestrictionTemporaryUnlocked(
238 Out<bool> out_is_temporary_unlocked) {
239 *out_is_temporary_unlocked = false;
240 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
241 *out_is_temporary_unlocked);
242 R_SUCCEED();
243}
244
245Result IParentalControlService::IsRestrictedSystemSettingsEntered(
246 Out<bool> out_is_restricted_system_settings_entered) {
247 *out_is_restricted_system_settings_entered = false;
248 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
249 *out_is_restricted_system_settings_entered);
250 R_SUCCEED();
251}
252
253Result IParentalControlService::ConfirmStereoVisionPermission() {
254 LOG_DEBUG(Service_PCTL, "called");
255 states.stereo_vision = true;
256 R_SUCCEED();
257}
258
259Result IParentalControlService::EndFreeCommunication() {
260 LOG_WARNING(Service_PCTL, "(STUBBED) called");
261 R_SUCCEED();
262}
263
264Result IParentalControlService::IsFreeCommunicationAvailable() {
265 LOG_WARNING(Service_PCTL, "(STUBBED) called");
266
267 if (!CheckFreeCommunicationPermissionImpl()) {
268 R_THROW(PCTL::ResultNoFreeCommunication);
269 } else {
270 R_SUCCEED();
271 }
272}
273
274Result IParentalControlService::IsRestrictionEnabled(Out<bool> out_restriction_enabled) {
275 LOG_DEBUG(Service_PCTL, "called");
276
277 if (False(capability & (Capability::Status | Capability::Recovery))) {
278 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
279 *out_restriction_enabled = false;
280 R_THROW(PCTL::ResultNoCapability);
281 }
282
283 *out_restriction_enabled = pin_code[0] != '\0';
284 R_SUCCEED();
285}
286
287Result IParentalControlService::GetSafetyLevel(Out<u32> out_safety_level) {
288 *out_safety_level = 0;
289 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", *out_safety_level);
290 R_SUCCEED();
291}
292
293Result IParentalControlService::GetCurrentSettings(Out<RestrictionSettings> out_settings) {
294 LOG_INFO(Service_PCTL, "called");
295 *out_settings = restriction_settings;
296 R_SUCCEED();
297}
298
299Result IParentalControlService::GetFreeCommunicationApplicationListCount(Out<s32> out_count) {
300 *out_count = 4;
301 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", *out_count);
302 R_SUCCEED();
303}
304
305Result IParentalControlService::ConfirmStereoVisionRestrictionConfigurable() {
306 LOG_DEBUG(Service_PCTL, "called");
307
308 if (False(capability & Capability::StereoVision)) {
309 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
310 R_THROW(PCTL::ResultNoCapability);
311 }
312
313 if (pin_code[0] == '\0') {
314 R_THROW(PCTL::ResultNoRestrictionEnabled);
315 }
316
317 R_SUCCEED();
318}
319
320Result IParentalControlService::IsStereoVisionPermitted(Out<bool> out_is_permitted) {
321 LOG_DEBUG(Service_PCTL, "called");
322
323 if (!ConfirmStereoVisionPermissionImpl()) {
324 *out_is_permitted = false;
325 R_THROW(PCTL::ResultStereoVisionRestricted);
326 } else {
327 *out_is_permitted = true;
328 R_SUCCEED();
329 }
330}
331
332Result IParentalControlService::GetPinCodeLength(Out<s32> out_length) {
333 *out_length = 0;
334 LOG_WARNING(Service_PCTL, "(STUBBED) called, length={}", *out_length);
335 R_SUCCEED();
336}
337
338Result IParentalControlService::IsPairingActive(Out<bool> out_is_pairing_active) {
339 *out_is_pairing_active = false;
340 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", *out_is_pairing_active);
341 R_SUCCEED();
342}
343
344Result IParentalControlService::GetSynchronizationEvent(
345 OutCopyHandle<Kernel::KReadableEvent> out_event) {
346 LOG_INFO(Service_PCTL, "called");
347 *out_event = synchronization_event.GetHandle();
348 R_SUCCEED();
349}
350
351Result IParentalControlService::StartPlayTimer() {
352 LOG_WARNING(Service_PCTL, "(STUBBED) called");
353 R_SUCCEED();
354}
355
356Result IParentalControlService::StopPlayTimer() {
357 LOG_WARNING(Service_PCTL, "(STUBBED) called");
358 R_SUCCEED();
359}
360
361Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled) {
362 *out_is_play_timer_enabled = false;
363 LOG_WARNING(Service_PCTL, "(STUBBED) called, enabled={}", *out_is_play_timer_enabled);
364 R_SUCCEED();
365}
366
367Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
368 *out_is_restricted_by_play_timer = false;
369 LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
370 R_SUCCEED();
371}
372
373Result IParentalControlService::GetPlayTimerSettings(
374 Out<PlayTimerSettings> out_play_timer_settings) {
375 LOG_WARNING(Service_PCTL, "(STUBBED) called");
376 *out_play_timer_settings = {};
377 R_SUCCEED();
378}
379
380Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
381 OutCopyHandle<Kernel::KReadableEvent> out_event) {
382 LOG_INFO(Service_PCTL, "called");
383 *out_event = request_suspension_event.GetHandle();
384 R_SUCCEED();
385}
386
387Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
388 *out_play_timer_alarm_disabled = false;
389 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
390 *out_play_timer_alarm_disabled);
391 R_SUCCEED();
392}
393
394Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
395 LOG_INFO(Service_PCTL, "called");
396 *out_event = unlinked_event.GetHandle();
397 R_SUCCEED();
398}
399
400Result IParentalControlService::GetStereoVisionRestriction(
401 Out<bool> out_stereo_vision_restriction) {
402 LOG_DEBUG(Service_PCTL, "called");
403
404 if (False(capability & Capability::StereoVision)) {
405 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
406 *out_stereo_vision_restriction = false;
407 R_THROW(PCTL::ResultNoCapability);
408 }
409
410 *out_stereo_vision_restriction = settings.is_stero_vision_restricted;
411 R_SUCCEED();
412}
413
414Result IParentalControlService::SetStereoVisionRestriction(bool stereo_vision_restriction) {
415 LOG_DEBUG(Service_PCTL, "called, can_use={}", stereo_vision_restriction);
416
417 if (False(capability & Capability::StereoVision)) {
418 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
419 R_THROW(PCTL::ResultNoCapability);
420 }
421
422 SetStereoVisionRestrictionImpl(stereo_vision_restriction);
423 R_SUCCEED();
424}
425
426Result IParentalControlService::ResetConfirmedStereoVisionPermission() {
427 LOG_DEBUG(Service_PCTL, "called");
428
429 states.stereo_vision = false;
430
431 R_SUCCEED();
432}
433
434} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service.h b/src/core/hle/service/pctl/parental_control_service.h
new file mode 100644
index 000000000..03dbaa2e5
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service.h
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/os/event.h"
9#include "core/hle/service/pctl/pctl_types.h"
10#include "core/hle/service/service.h"
11
12namespace Service::PCTL {
13
14class IParentalControlService final : public ServiceFramework<IParentalControlService> {
15public:
16 explicit IParentalControlService(Core::System& system_, Capability capability_);
17 ~IParentalControlService() override;
18
19private:
20 bool CheckFreeCommunicationPermissionImpl() const;
21 bool ConfirmStereoVisionPermissionImpl() const;
22 void SetStereoVisionRestrictionImpl(bool is_restricted);
23
24 Result Initialize();
25 Result CheckFreeCommunicationPermission();
26 Result ConfirmLaunchApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
27 u64 nacp_flag, u64 application_id);
28 Result ConfirmResumeApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
29 u64 nacp_flag, u64 application_id);
30 Result ConfirmSnsPostPermission();
31 Result IsRestrictionTemporaryUnlocked(Out<bool> out_is_temporary_unlocked);
32 Result IsRestrictedSystemSettingsEntered(Out<bool> out_is_restricted_system_settings_entered);
33 Result ConfirmStereoVisionPermission();
34 Result EndFreeCommunication();
35 Result IsFreeCommunicationAvailable();
36 Result IsRestrictionEnabled(Out<bool> out_restriction_enabled);
37 Result GetSafetyLevel(Out<u32> out_safety_level);
38 Result GetCurrentSettings(Out<RestrictionSettings> out_settings);
39 Result GetFreeCommunicationApplicationListCount(Out<s32> out_count);
40 Result ConfirmStereoVisionRestrictionConfigurable();
41 Result IsStereoVisionPermitted(Out<bool> out_is_permitted);
42 Result GetPinCodeLength(Out<s32> out_length);
43 Result IsPairingActive(Out<bool> out_is_pairing_active);
44 Result GetSynchronizationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
45 Result StartPlayTimer();
46 Result StopPlayTimer();
47 Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
48 Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
49 Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
50 Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
51 Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
52 Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
53 Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
54 Result SetStereoVisionRestriction(bool stereo_vision_restriction);
55 Result ResetConfirmedStereoVisionPermission();
56
57 struct States {
58 u64 current_tid{};
59 ApplicationInfo application_info{};
60 u64 tid_from_event{};
61 bool launch_time_valid{};
62 bool is_suspended{};
63 bool temporary_unlocked{};
64 bool free_communication{};
65 bool stereo_vision{};
66 };
67
68 struct ParentalControlSettings {
69 bool is_stero_vision_restricted{};
70 bool is_free_communication_default_on{};
71 bool disabled{};
72 };
73
74 States states{};
75 ParentalControlSettings settings{};
76 RestrictionSettings restriction_settings{};
77 std::array<char, 8> pin_code{};
78 Capability capability{};
79
80 KernelHelpers::ServiceContext service_context;
81 Event synchronization_event;
82 Event unlinked_event;
83 Event request_suspension_event;
84};
85
86} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.cpp b/src/core/hle/service/pctl/parental_control_service_factory.cpp
new file mode 100644
index 000000000..7d8f361e9
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/pctl/parental_control_service.h"
6#include "core/hle/service/pctl/parental_control_service_factory.h"
7
8namespace Service::PCTL {
9
10IParentalControlServiceFactory::IParentalControlServiceFactory(Core::System& system_,
11 const char* name_,
12 Capability capability_)
13 : ServiceFramework{system_, name_}, capability{capability_} {
14 static const FunctionInfo functions[] = {
15 {0, D<&IParentalControlServiceFactory::CreateService>, "CreateService"},
16 {1, D<&IParentalControlServiceFactory::CreateServiceWithoutInitialize>,
17 "CreateServiceWithoutInitialize"},
18 };
19 RegisterHandlers(functions);
20}
21
22IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;
23
24Result IParentalControlServiceFactory::CreateService(
25 Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
26 LOG_DEBUG(Service_PCTL, "called");
27 // TODO(ogniK): Get application id from process
28 *out_service = std::make_shared<IParentalControlService>(system, capability);
29 R_SUCCEED();
30}
31
32Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
33 Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
34 LOG_DEBUG(Service_PCTL, "called");
35 // TODO(ogniK): Get application id from process
36 *out_service = std::make_shared<IParentalControlService>(system, capability);
37 R_SUCCEED();
38}
39
40} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/parental_control_service_factory.h b/src/core/hle/service/pctl/parental_control_service_factory.h
new file mode 100644
index 000000000..362988add
--- /dev/null
+++ b/src/core/hle/service/pctl/parental_control_service_factory.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/pctl/pctl_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PCTL {
11
12class IParentalControlService;
13
14class IParentalControlServiceFactory : public ServiceFramework<IParentalControlServiceFactory> {
15public:
16 explicit IParentalControlServiceFactory(Core::System& system_, const char* name_,
17 Capability capability_);
18 ~IParentalControlServiceFactory() override;
19
20 Result CreateService(Out<SharedPointer<IParentalControlService>> out_service,
21 ClientProcessId process_id);
22 Result CreateServiceWithoutInitialize(Out<SharedPointer<IParentalControlService>> out_service,
23 ClientProcessId process_id);
24
25private:
26 Capability capability{};
27};
28
29void LoopProcess(Core::System& system);
30
31} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 3f47bf094..d92dbe216 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -1,19 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/pctl/parental_control_service_factory.h"
4#include "core/hle/service/pctl/pctl.h" 5#include "core/hle/service/pctl/pctl.h"
6#include "core/hle/service/server_manager.h"
5 7
6namespace Service::PCTL { 8namespace Service::PCTL {
7 9
8PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name, 10void LoopProcess(Core::System& system) {
9 Capability capability_) 11 auto server_manager = std::make_unique<ServerManager>(system);
10 : Interface{system_, std::move(module_), name, capability_} { 12
11 static const FunctionInfo functions[] = { 13 server_manager->RegisterNamedService("pctl",
12 {0, &PCTL::CreateService, "CreateService"}, 14 std::make_shared<IParentalControlServiceFactory>(
13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 15 system, "pctl",
14 }; 16 Capability::Application | Capability::SnsPost |
15 RegisterHandlers(functions); 17 Capability::Status | Capability::StereoVision));
18 // TODO(ogniK): Implement remaining capabilities
19 server_manager->RegisterNamedService("pctl:a", std::make_shared<IParentalControlServiceFactory>(
20 system, "pctl:a", Capability::None));
21 server_manager->RegisterNamedService("pctl:r", std::make_shared<IParentalControlServiceFactory>(
22 system, "pctl:r", Capability::None));
23 server_manager->RegisterNamedService("pctl:s", std::make_shared<IParentalControlServiceFactory>(
24 system, "pctl:s", Capability::None));
25 ServerManager::RunServer(std::move(server_manager));
16} 26}
17 27
18PCTL::~PCTL() = default;
19} // namespace Service::PCTL 28} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 87f93161e..5f9d03d4d 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -3,19 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/pctl/pctl_module.h"
7
8namespace Core { 6namespace Core {
9class System; 7class System;
10} 8}
11 9
12namespace Service::PCTL { 10namespace Service::PCTL {
13 11
14class PCTL final : public Module::Interface { 12void LoopProcess(Core::System& system);
15public:
16 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
17 Capability capability_);
18 ~PCTL() override;
19};
20 13
21} // namespace Service::PCTL 14} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
deleted file mode 100644
index 6a7fd72bc..000000000
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/pctl/pctl.h"
11#include "core/hle/service/pctl/pctl_module.h"
12#include "core/hle/service/server_manager.h"
13
14namespace Service::PCTL {
15
16namespace Error {
17
18constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
19constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
20constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
21constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
22
23} // namespace Error
24
25class IParentalControlService final : public ServiceFramework<IParentalControlService> {
26public:
27 explicit IParentalControlService(Core::System& system_, Capability capability_)
28 : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
29 service_context{system_, "IParentalControlService"} {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {1, &IParentalControlService::Initialize, "Initialize"},
33 {1001, &IParentalControlService::CheckFreeCommunicationPermission, "CheckFreeCommunicationPermission"},
34 {1002, nullptr, "ConfirmLaunchApplicationPermission"},
35 {1003, nullptr, "ConfirmResumeApplicationPermission"},
36 {1004, &IParentalControlService::ConfirmSnsPostPermission, "ConfirmSnsPostPermission"},
37 {1005, nullptr, "ConfirmSystemSettingsPermission"},
38 {1006, &IParentalControlService::IsRestrictionTemporaryUnlocked, "IsRestrictionTemporaryUnlocked"},
39 {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
40 {1008, nullptr, "EnterRestrictedSystemSettings"},
41 {1009, nullptr, "LeaveRestrictedSystemSettings"},
42 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
43 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
44 {1012, nullptr, "GetRestrictedFeatures"},
45 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
46 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
47 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
48 {1016, nullptr, "ConfirmShowNewsPermission"},
49 {1017, &IParentalControlService::EndFreeCommunication, "EndFreeCommunication"},
50 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
51 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
52 {1032, &IParentalControlService::GetSafetyLevel, "GetSafetyLevel"},
53 {1033, nullptr, "SetSafetyLevel"},
54 {1034, nullptr, "GetSafetyLevelSettings"},
55 {1035, &IParentalControlService::GetCurrentSettings, "GetCurrentSettings"},
56 {1036, nullptr, "SetCustomSafetyLevelSettings"},
57 {1037, nullptr, "GetDefaultRatingOrganization"},
58 {1038, nullptr, "SetDefaultRatingOrganization"},
59 {1039, &IParentalControlService::GetFreeCommunicationApplicationListCount, "GetFreeCommunicationApplicationListCount"},
60 {1042, nullptr, "AddToFreeCommunicationApplicationList"},
61 {1043, nullptr, "DeleteSettings"},
62 {1044, nullptr, "GetFreeCommunicationApplicationList"},
63 {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
64 {1046, nullptr, "DisableFeaturesForReset"},
65 {1047, nullptr, "NotifyApplicationDownloadStarted"},
66 {1048, nullptr, "NotifyNetworkProfileCreated"},
67 {1049, nullptr, "ResetFreeCommunicationApplicationList"},
68 {1061, &IParentalControlService::ConfirmStereoVisionRestrictionConfigurable, "ConfirmStereoVisionRestrictionConfigurable"},
69 {1062, &IParentalControlService::GetStereoVisionRestriction, "GetStereoVisionRestriction"},
70 {1063, &IParentalControlService::SetStereoVisionRestriction, "SetStereoVisionRestriction"},
71 {1064, &IParentalControlService::ResetConfirmedStereoVisionPermission, "ResetConfirmedStereoVisionPermission"},
72 {1065, &IParentalControlService::IsStereoVisionPermitted, "IsStereoVisionPermitted"},
73 {1201, nullptr, "UnlockRestrictionTemporarily"},
74 {1202, nullptr, "UnlockSystemSettingsRestriction"},
75 {1203, nullptr, "SetPinCode"},
76 {1204, nullptr, "GenerateInquiryCode"},
77 {1205, nullptr, "CheckMasterKey"},
78 {1206, nullptr, "GetPinCodeLength"},
79 {1207, nullptr, "GetPinCodeChangedEvent"},
80 {1208, nullptr, "GetPinCode"},
81 {1403, &IParentalControlService::IsPairingActive, "IsPairingActive"},
82 {1406, nullptr, "GetSettingsLastUpdated"},
83 {1411, nullptr, "GetPairingAccountInfo"},
84 {1421, nullptr, "GetAccountNickname"},
85 {1424, nullptr, "GetAccountState"},
86 {1425, nullptr, "RequestPostEvents"},
87 {1426, nullptr, "GetPostEventInterval"},
88 {1427, nullptr, "SetPostEventInterval"},
89 {1432, &IParentalControlService::GetSynchronizationEvent, "GetSynchronizationEvent"},
90 {1451, nullptr, "StartPlayTimer"},
91 {1452, nullptr, "StopPlayTimer"},
92 {1453, nullptr, "IsPlayTimerEnabled"},
93 {1454, nullptr, "GetPlayTimerRemainingTime"},
94 {1455, nullptr, "IsRestrictedByPlayTimer"},
95 {1456, &IParentalControlService::GetPlayTimerSettings, "GetPlayTimerSettings"},
96 {1457, &IParentalControlService::GetPlayTimerEventToRequestSuspension, "GetPlayTimerEventToRequestSuspension"},
97 {1458, &IParentalControlService::IsPlayTimerAlarmDisabled, "IsPlayTimerAlarmDisabled"},
98 {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
99 {1472, nullptr, "CancelNetworkRequest"},
100 {1473, &IParentalControlService::GetUnlinkedEvent, "GetUnlinkedEvent"},
101 {1474, nullptr, "ClearUnlinkedEvent"},
102 {1601, nullptr, "DisableAllFeatures"},
103 {1602, nullptr, "PostEnableAllFeatures"},
104 {1603, nullptr, "IsAllFeaturesDisabled"},
105 {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
106 {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
107 {1903, nullptr, "GetExemptApplicationListCountForDebug"},
108 {1904, nullptr, "GetExemptApplicationListForDebug"},
109 {1905, nullptr, "UpdateExemptApplicationListForDebug"},
110 {1906, nullptr, "AddToExemptApplicationListForDebug"},
111 {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
112 {1908, nullptr, "ClearExemptApplicationListForDebug"},
113 {1941, nullptr, "DeletePairing"},
114 {1951, nullptr, "SetPlayTimerSettingsForDebug"},
115 {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
116 {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
117 {2001, nullptr, "RequestPairingAsync"},
118 {2002, nullptr, "FinishRequestPairing"},
119 {2003, nullptr, "AuthorizePairingAsync"},
120 {2004, nullptr, "FinishAuthorizePairing"},
121 {2005, nullptr, "RetrievePairingInfoAsync"},
122 {2006, nullptr, "FinishRetrievePairingInfo"},
123 {2007, nullptr, "UnlinkPairingAsync"},
124 {2008, nullptr, "FinishUnlinkPairing"},
125 {2009, nullptr, "GetAccountMiiImageAsync"},
126 {2010, nullptr, "FinishGetAccountMiiImage"},
127 {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
128 {2012, nullptr, "FinishGetAccountMiiImageContentType"},
129 {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
130 {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
131 {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
132 {2016, nullptr, "RequestUpdateExemptionListAsync"},
133 };
134 // clang-format on
135 RegisterHandlers(functions);
136
137 synchronization_event =
138 service_context.CreateEvent("IParentalControlService::SynchronizationEvent");
139 unlinked_event = service_context.CreateEvent("IParentalControlService::UnlinkedEvent");
140 request_suspension_event =
141 service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent");
142 }
143
144 ~IParentalControlService() {
145 service_context.CloseEvent(synchronization_event);
146 service_context.CloseEvent(unlinked_event);
147 service_context.CloseEvent(request_suspension_event);
148 };
149
150private:
151 bool CheckFreeCommunicationPermissionImpl() const {
152 if (states.temporary_unlocked) {
153 return true;
154 }
155 if ((states.application_info.parental_control_flag & 1) == 0) {
156 return true;
157 }
158 if (pin_code[0] == '\0') {
159 return true;
160 }
161 if (!settings.is_free_communication_default_on) {
162 return true;
163 }
164 // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
165 // but as we don't have multiproceses support yet, we can just assume our application is
166 // valid for the time being
167 return true;
168 }
169
170 bool ConfirmStereoVisionPermissionImpl() const {
171 if (states.temporary_unlocked) {
172 return true;
173 }
174 if (pin_code[0] == '\0') {
175 return true;
176 }
177 if (!settings.is_stero_vision_restricted) {
178 return false;
179 }
180 return true;
181 }
182
183 void SetStereoVisionRestrictionImpl(bool is_restricted) {
184 if (settings.disabled) {
185 return;
186 }
187
188 if (pin_code[0] == '\0') {
189 return;
190 }
191 settings.is_stero_vision_restricted = is_restricted;
192 }
193
194 void Initialize(HLERequestContext& ctx) {
195 LOG_DEBUG(Service_PCTL, "called");
196 IPC::ResponseBuilder rb{ctx, 2};
197
198 if (False(capability & (Capability::Application | Capability::System))) {
199 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
200 return;
201 }
202
203 // TODO(ogniK): Recovery flag initialization for pctl:r
204
205 const auto tid = system.GetApplicationProcessProgramID();
206 if (tid != 0) {
207 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
208 system.GetContentProvider()};
209 const auto control = pm.GetControlMetadata();
210 if (control.first) {
211 states.tid_from_event = 0;
212 states.launch_time_valid = false;
213 states.is_suspended = false;
214 states.free_communication = false;
215 states.stereo_vision = false;
216 states.application_info = ApplicationInfo{
217 .tid = tid,
218 .age_rating = control.first->GetRatingAge(),
219 .parental_control_flag = control.first->GetParentalControlFlag(),
220 .capability = capability,
221 };
222
223 if (False(capability & (Capability::System | Capability::Recovery))) {
224 // TODO(ogniK): Signal application launch event
225 }
226 }
227 }
228
229 rb.Push(ResultSuccess);
230 }
231
232 void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
233 LOG_DEBUG(Service_PCTL, "called");
234
235 IPC::ResponseBuilder rb{ctx, 2};
236 if (!CheckFreeCommunicationPermissionImpl()) {
237 rb.Push(Error::ResultNoFreeCommunication);
238 } else {
239 rb.Push(ResultSuccess);
240 }
241
242 states.free_communication = true;
243 }
244
245 void ConfirmSnsPostPermission(HLERequestContext& ctx) {
246 LOG_WARNING(Service_PCTL, "(STUBBED) called");
247
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(Error::ResultNoFreeCommunication);
250 }
251
252 void IsRestrictionTemporaryUnlocked(HLERequestContext& ctx) {
253 const bool is_temporary_unlocked = false;
254
255 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
256 is_temporary_unlocked);
257
258 IPC::ResponseBuilder rb{ctx, 3};
259 rb.Push(ResultSuccess);
260 rb.Push<u8>(is_temporary_unlocked);
261 }
262
263 void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
264 LOG_DEBUG(Service_PCTL, "called");
265 states.stereo_vision = true;
266
267 IPC::ResponseBuilder rb{ctx, 2};
268 rb.Push(ResultSuccess);
269 }
270
271 void EndFreeCommunication(HLERequestContext& ctx) {
272 LOG_WARNING(Service_PCTL, "(STUBBED) called");
273
274 IPC::ResponseBuilder rb{ctx, 2};
275 rb.Push(ResultSuccess);
276 }
277
278 void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
279 LOG_WARNING(Service_PCTL, "(STUBBED) called");
280
281 IPC::ResponseBuilder rb{ctx, 2};
282 if (!CheckFreeCommunicationPermissionImpl()) {
283 rb.Push(Error::ResultNoFreeCommunication);
284 } else {
285 rb.Push(ResultSuccess);
286 }
287 }
288
289 void IsRestrictionEnabled(HLERequestContext& ctx) {
290 LOG_DEBUG(Service_PCTL, "called");
291
292 IPC::ResponseBuilder rb{ctx, 3};
293 if (False(capability & (Capability::Status | Capability::Recovery))) {
294 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
295 rb.Push(Error::ResultNoCapability);
296 rb.Push(false);
297 return;
298 }
299
300 rb.Push(pin_code[0] != '\0');
301 }
302
303 void GetSafetyLevel(HLERequestContext& ctx) {
304 const u32 safety_level = 0;
305
306 LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", safety_level);
307
308 IPC::ResponseBuilder rb{ctx, 3};
309 rb.Push(ResultSuccess);
310 rb.Push(safety_level);
311 }
312
313 void GetCurrentSettings(HLERequestContext& ctx) {
314 LOG_INFO(Service_PCTL, "called");
315
316 IPC::ResponseBuilder rb{ctx, 3};
317 rb.Push(ResultSuccess);
318 rb.PushRaw(restriction_settings);
319 }
320
321 void GetFreeCommunicationApplicationListCount(HLERequestContext& ctx) {
322 const u32 count = 4;
323
324 LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", count);
325
326 IPC::ResponseBuilder rb{ctx, 3};
327 rb.Push(ResultSuccess);
328 rb.Push(count);
329 }
330
331 void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
332 LOG_DEBUG(Service_PCTL, "called");
333
334 IPC::ResponseBuilder rb{ctx, 2};
335
336 if (False(capability & Capability::StereoVision)) {
337 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
338 rb.Push(Error::ResultNoCapability);
339 return;
340 }
341
342 if (pin_code[0] == '\0') {
343 rb.Push(Error::ResultNoRestrictionEnabled);
344 return;
345 }
346
347 rb.Push(ResultSuccess);
348 }
349
350 void IsStereoVisionPermitted(HLERequestContext& ctx) {
351 LOG_DEBUG(Service_PCTL, "called");
352
353 IPC::ResponseBuilder rb{ctx, 3};
354 if (!ConfirmStereoVisionPermissionImpl()) {
355 rb.Push(Error::ResultStereoVisionRestricted);
356 rb.Push(false);
357 } else {
358 rb.Push(ResultSuccess);
359 rb.Push(true);
360 }
361 }
362
363 void IsPairingActive(HLERequestContext& ctx) {
364 const bool is_pairing_active = false;
365
366 LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", is_pairing_active);
367
368 IPC::ResponseBuilder rb{ctx, 3};
369 rb.Push(ResultSuccess);
370 rb.Push<u8>(is_pairing_active);
371 }
372
373 void GetSynchronizationEvent(HLERequestContext& ctx) {
374 LOG_INFO(Service_PCTL, "called");
375
376 IPC::ResponseBuilder rb{ctx, 2, 1};
377 rb.Push(ResultSuccess);
378 rb.PushCopyObjects(synchronization_event->GetReadableEvent());
379 }
380
381 void GetPlayTimerSettings(HLERequestContext& ctx) {
382 LOG_WARNING(Service_PCTL, "(STUBBED) called");
383
384 const PlayTimerSettings timer_settings{};
385
386 IPC::ResponseBuilder rb{ctx, 15};
387 rb.Push(ResultSuccess);
388 rb.PushRaw(timer_settings);
389 }
390
391 void GetPlayTimerEventToRequestSuspension(HLERequestContext& ctx) {
392 LOG_INFO(Service_PCTL, "called");
393
394 IPC::ResponseBuilder rb{ctx, 2, 1};
395 rb.Push(ResultSuccess);
396 rb.PushCopyObjects(request_suspension_event->GetReadableEvent());
397 }
398
399 void IsPlayTimerAlarmDisabled(HLERequestContext& ctx) {
400 const bool is_play_timer_alarm_disabled = false;
401
402 LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
403 is_play_timer_alarm_disabled);
404
405 IPC::ResponseBuilder rb{ctx, 3};
406 rb.Push(ResultSuccess);
407 rb.Push<u8>(is_play_timer_alarm_disabled);
408 }
409
410 void GetUnlinkedEvent(HLERequestContext& ctx) {
411 LOG_INFO(Service_PCTL, "called");
412
413 IPC::ResponseBuilder rb{ctx, 2, 1};
414 rb.Push(ResultSuccess);
415 rb.PushCopyObjects(unlinked_event->GetReadableEvent());
416 }
417
418 void SetStereoVisionRestriction(HLERequestContext& ctx) {
419 IPC::RequestParser rp{ctx};
420 const auto can_use = rp.Pop<bool>();
421 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
422
423 IPC::ResponseBuilder rb{ctx, 2};
424 if (False(capability & Capability::StereoVision)) {
425 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
426 rb.Push(Error::ResultNoCapability);
427 return;
428 }
429
430 SetStereoVisionRestrictionImpl(can_use);
431 rb.Push(ResultSuccess);
432 }
433
434 void GetStereoVisionRestriction(HLERequestContext& ctx) {
435 LOG_DEBUG(Service_PCTL, "called");
436
437 IPC::ResponseBuilder rb{ctx, 3};
438 if (False(capability & Capability::StereoVision)) {
439 LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
440 rb.Push(Error::ResultNoCapability);
441 rb.Push(false);
442 return;
443 }
444
445 rb.Push(ResultSuccess);
446 rb.Push(settings.is_stero_vision_restricted);
447 }
448
449 void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
450 LOG_DEBUG(Service_PCTL, "called");
451
452 states.stereo_vision = false;
453
454 IPC::ResponseBuilder rb{ctx, 2};
455 rb.Push(ResultSuccess);
456 }
457
458 struct ApplicationInfo {
459 u64 tid{};
460 std::array<u8, 32> age_rating{};
461 u32 parental_control_flag{};
462 Capability capability{};
463 };
464
465 struct States {
466 u64 current_tid{};
467 ApplicationInfo application_info{};
468 u64 tid_from_event{};
469 bool launch_time_valid{};
470 bool is_suspended{};
471 bool temporary_unlocked{};
472 bool free_communication{};
473 bool stereo_vision{};
474 };
475
476 struct ParentalControlSettings {
477 bool is_stero_vision_restricted{};
478 bool is_free_communication_default_on{};
479 bool disabled{};
480 };
481
482 // This is nn::pctl::RestrictionSettings
483 struct RestrictionSettings {
484 u8 rating_age;
485 bool sns_post_restriction;
486 bool free_communication_restriction;
487 };
488 static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
489
490 // This is nn::pctl::PlayTimerSettings
491 struct PlayTimerSettings {
492 std::array<u32, 13> settings;
493 };
494 static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
495
496 States states{};
497 ParentalControlSettings settings{};
498 RestrictionSettings restriction_settings{};
499 std::array<char, 8> pin_code{};
500 Capability capability{};
501
502 Kernel::KEvent* synchronization_event;
503 Kernel::KEvent* unlinked_event;
504 Kernel::KEvent* request_suspension_event;
505 KernelHelpers::ServiceContext service_context;
506};
507
508void Module::Interface::CreateService(HLERequestContext& ctx) {
509 LOG_DEBUG(Service_PCTL, "called");
510
511 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
512 rb.Push(ResultSuccess);
513 // TODO(ogniK): Get TID from process
514
515 rb.PushIpcInterface<IParentalControlService>(system, capability);
516}
517
518void Module::Interface::CreateServiceWithoutInitialize(HLERequestContext& ctx) {
519 LOG_DEBUG(Service_PCTL, "called");
520
521 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
522 rb.Push(ResultSuccess);
523 rb.PushIpcInterface<IParentalControlService>(system, capability);
524}
525
526Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
527 const char* name_, Capability capability_)
528 : ServiceFramework{system_, name_}, module{std::move(module_)}, capability{capability_} {}
529
530Module::Interface::~Interface() = default;
531
532void LoopProcess(Core::System& system) {
533 auto server_manager = std::make_unique<ServerManager>(system);
534
535 auto module = std::make_shared<Module>();
536 server_manager->RegisterNamedService(
537 "pctl", std::make_shared<PCTL>(system, module, "pctl",
538 Capability::Application | Capability::SnsPost |
539 Capability::Status | Capability::StereoVision));
540 // TODO(ogniK): Implement remaining capabilities
541 server_manager->RegisterNamedService(
542 "pctl:a", std::make_shared<PCTL>(system, module, "pctl:a", Capability::None));
543 server_manager->RegisterNamedService(
544 "pctl:r", std::make_shared<PCTL>(system, module, "pctl:r", Capability::None));
545 server_manager->RegisterNamedService(
546 "pctl:s", std::make_shared<PCTL>(system, module, "pctl:s", Capability::None));
547 ServerManager::RunServer(std::move(server_manager));
548}
549
550} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.h b/src/core/hle/service/pctl/pctl_module.h
deleted file mode 100644
index dff0d3f08..000000000
--- a/src/core/hle/service/pctl/pctl_module.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::PCTL {
14
15enum class Capability : u32 {
16 None = 0,
17 Application = 1 << 0,
18 SnsPost = 1 << 1,
19 Recovery = 1 << 6,
20 Status = 1 << 8,
21 StereoVision = 1 << 9,
22 System = 1 << 15,
23};
24DECLARE_ENUM_FLAG_OPERATORS(Capability);
25
26class Module final {
27public:
28 class Interface : public ServiceFramework<Interface> {
29 public:
30 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
31 const char* name_, Capability capability_);
32 ~Interface() override;
33
34 void CreateService(HLERequestContext& ctx);
35 void CreateServiceWithoutInitialize(HLERequestContext& ctx);
36
37 protected:
38 std::shared_ptr<Module> module;
39
40 private:
41 Capability capability{};
42 };
43};
44
45void LoopProcess(Core::System& system);
46
47} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_results.h b/src/core/hle/service/pctl/pctl_results.h
new file mode 100644
index 000000000..1fc54727b
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_results.h
@@ -0,0 +1,15 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::PCTL {
9
10constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
11constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
12constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
13constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
14
15} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_types.h b/src/core/hle/service/pctl/pctl_types.h
new file mode 100644
index 000000000..daaecdf48
--- /dev/null
+++ b/src/core/hle/service/pctl/pctl_types.h
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7
8namespace Service::PCTL {
9
10enum class Capability : u32 {
11 None = 0,
12 Application = 1 << 0,
13 SnsPost = 1 << 1,
14 Recovery = 1 << 6,
15 Status = 1 << 8,
16 StereoVision = 1 << 9,
17 System = 1 << 15,
18};
19DECLARE_ENUM_FLAG_OPERATORS(Capability);
20
21struct ApplicationInfo {
22 u64 application_id{};
23 std::array<u8, 32> age_rating{};
24 u32 parental_control_flag{};
25 Capability capability{};
26};
27static_assert(sizeof(ApplicationInfo) == 0x30, "ApplicationInfo has incorrect size.");
28
29// This is nn::pctl::RestrictionSettings
30struct RestrictionSettings {
31 u8 rating_age;
32 bool sns_post_restriction;
33 bool free_communication_restriction;
34};
35static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
36
37// This is nn::pctl::PlayTimerSettings
38struct PlayTimerSettings {
39 std::array<u32, 13> settings;
40};
41static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
42
43} // namespace Service::PCTL
diff --git a/src/core/hle/service/psc/ovln/ovln_types.h b/src/core/hle/service/psc/ovln/ovln_types.h
new file mode 100644
index 000000000..343b05dcc
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/ovln_types.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8
9namespace Service::PSC {
10
11using OverlayNotification = std::array<u64, 0x10>;
12static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");
13
14union MessageFlags {
15 u64 raw;
16 BitField<0, 8, u64> message_type;
17 BitField<8, 8, u64> queue_type;
18};
19static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.cpp b/src/core/hle/service/psc/ovln/receiver.cpp
new file mode 100644
index 000000000..85f62816d
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/ovln/receiver.h"
5
6namespace Service::PSC {
7
8IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "AddSource"},
12 {1, nullptr, "RemoveSource"},
13 {2, nullptr, "GetReceiveEventHandle"},
14 {3, nullptr, "Receive"},
15 {4, nullptr, "ReceiveWithTick"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IReceiver::~IReceiver() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver.h b/src/core/hle/service/psc/ovln/receiver.h
new file mode 100644
index 000000000..c47a4ff7e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IReceiver final : public ServiceFramework<IReceiver> {
11public:
12 explicit IReceiver(Core::System& system_);
13 ~IReceiver() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.cpp b/src/core/hle/service/psc/ovln/receiver_service.cpp
new file mode 100644
index 000000000..bb988e905
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/receiver.h"
6#include "core/hle/service/psc/ovln/receiver_service.h"
7
8namespace Service::PSC {
9
10IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IReceiverService::~IReceiverService() = default;
21
22Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_receiver = std::make_shared<IReceiver>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/receiver_service.h b/src/core/hle/service/psc/ovln/receiver_service.h
new file mode 100644
index 000000000..b3b31ba4a
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/receiver_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IReceiver;
12
13class IReceiverService final : public ServiceFramework<IReceiverService> {
14public:
15 explicit IReceiverService(Core::System& system_);
16 ~IReceiverService() override;
17
18private:
19 Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.cpp b/src/core/hle/service/psc/ovln/sender.cpp
new file mode 100644
index 000000000..3227a56f2
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.cpp
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6
7namespace Service::PSC {
8
9ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, D<&ISender::Send>, "Send"},
13 {1, nullptr, "GetUnreceivedMessageCount"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISender::~ISender() = default;
21
22Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
23 std::string data;
24 for (const auto m : notification) {
25 data += fmt::format("{:016X} ", m);
26 }
27
28 LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
29 R_SUCCEED();
30}
31
32} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender.h b/src/core/hle/service/psc/ovln/sender.h
new file mode 100644
index 000000000..c1575428e
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/psc/ovln/ovln_types.h"
8#include "core/hle/service/service.h"
9
10namespace Service::PSC {
11
12class ISender final : public ServiceFramework<ISender> {
13public:
14 explicit ISender(Core::System& system_);
15 ~ISender() override;
16
17private:
18 Result Send(const OverlayNotification& notification, MessageFlags flags);
19};
20
21} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.cpp b/src/core/hle/service/psc/ovln/sender_service.cpp
new file mode 100644
index 000000000..18d2c83a3
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/ovln/sender.h"
6#include "core/hle/service/psc/ovln/sender_service.h"
7
8namespace Service::PSC {
9
10ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&ISenderService::OpenSender>, "OpenSender"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20ISenderService::~ISenderService() = default;
21
22Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
23 std::array<u64, 2> data) {
24 LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
25 data[0], data[1]);
26 *out_sender = std::make_shared<ISender>(system);
27 R_SUCCEED();
28}
29
30} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/ovln/sender_service.h b/src/core/hle/service/psc/ovln/sender_service.h
new file mode 100644
index 000000000..10027701f
--- /dev/null
+++ b/src/core/hle/service/psc/ovln/sender_service.h
@@ -0,0 +1,23 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class ISender;
12
13class ISenderService final : public ServiceFramework<ISenderService> {
14public:
15 explicit ISenderService(Core::System& system_);
16 ~ISenderService() override;
17
18private:
19 Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
20 std::array<u64, 2> data);
21};
22
23} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.cpp b/src/core/hle/service/psc/pm_control.cpp
new file mode 100644
index 000000000..7dedb7662
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_control.h"
5
6namespace Service::PSC {
7
8IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "DispatchRequest"},
13 {2, nullptr, "GetResult"},
14 {3, nullptr, "GetState"},
15 {4, nullptr, "Cancel"},
16 {5, nullptr, "PrintModuleInformation"},
17 {6, nullptr, "GetModuleInformation"},
18 {10, nullptr, "AcquireStateLock"},
19 {11, nullptr, "HasStateLock"},
20 };
21 // clang-format on
22
23 RegisterHandlers(functions);
24}
25
26IPmControl::~IPmControl() = default;
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_control.h b/src/core/hle/service/psc/pm_control.h
new file mode 100644
index 000000000..e0ae2f39c
--- /dev/null
+++ b/src/core/hle/service/psc/pm_control.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmControl final : public ServiceFramework<IPmControl> {
11public:
12 explicit IPmControl(Core::System& system_);
13 ~IPmControl() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.cpp b/src/core/hle/service/psc/pm_module.cpp
new file mode 100644
index 000000000..74dc7ed4e
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.cpp
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/psc/pm_module.h"
5
6namespace Service::PSC {
7
8IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {1, nullptr, "GetRequest"},
13 {2, nullptr, "Acknowledge"},
14 {3, nullptr, "Finalize"},
15 {4, nullptr, "AcknowledgeEx"},
16 };
17 // clang-format on
18
19 RegisterHandlers(functions);
20}
21
22IPmModule::~IPmModule() = default;
23
24} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_module.h b/src/core/hle/service/psc/pm_module.h
new file mode 100644
index 000000000..b3a2d2584
--- /dev/null
+++ b/src/core/hle/service/psc/pm_module.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::PSC {
9
10class IPmModule final : public ServiceFramework<IPmModule> {
11public:
12 explicit IPmModule(Core::System& system_);
13 ~IPmModule() override;
14};
15
16} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.cpp b/src/core/hle/service/psc/pm_service.cpp
new file mode 100644
index 000000000..c4e0ad228
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.cpp
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/pm_module.h"
6#include "core/hle/service/psc/pm_service.h"
7
8namespace Service::PSC {
9
10IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, D<&IPmService::GetPmModule>, "GetPmModule"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20IPmService::~IPmService() = default;
21
22Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
23 LOG_DEBUG(Service_PSC, "called");
24 *out_module = std::make_shared<IPmModule>(system);
25 R_SUCCEED();
26}
27
28} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/pm_service.h b/src/core/hle/service/psc/pm_service.h
new file mode 100644
index 000000000..08e14c6f8
--- /dev/null
+++ b/src/core/hle/service/psc/pm_service.h
@@ -0,0 +1,22 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Service::PSC {
10
11class IPmModule;
12
13class IPmService final : public ServiceFramework<IPmService> {
14public:
15 explicit IPmService(Core::System& system_);
16 ~IPmService() override;
17
18private:
19 Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
20};
21
22} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 44310756b..e1762d694 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -1,11 +1,10 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory> 4#include "core/hle/service/psc/ovln/receiver_service.h"
5 5#include "core/hle/service/psc/ovln/sender_service.h"
6#include "common/logging/log.h" 6#include "core/hle/service/psc/pm_control.h"
7#include "core/core.h" 7#include "core/hle/service/psc/pm_service.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/psc/psc.h" 8#include "core/hle/service/psc/psc.h"
10#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
11#include "core/hle/service/psc/time/power_state_service.h" 10#include "core/hle/service/psc/time/power_state_service.h"
@@ -15,71 +14,13 @@
15 14
16namespace Service::PSC { 15namespace Service::PSC {
17 16
18class IPmControl final : public ServiceFramework<IPmControl> {
19public:
20 explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "Initialize"},
24 {1, nullptr, "DispatchRequest"},
25 {2, nullptr, "GetResult"},
26 {3, nullptr, "GetState"},
27 {4, nullptr, "Cancel"},
28 {5, nullptr, "PrintModuleInformation"},
29 {6, nullptr, "GetModuleInformation"},
30 {10, nullptr, "AcquireStateLock"},
31 {11, nullptr, "HasStateLock"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36 }
37};
38
39class IPmModule final : public ServiceFramework<IPmModule> {
40public:
41 explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
42 // clang-format off
43 static const FunctionInfo functions[] = {
44 {0, nullptr, "Initialize"},
45 {1, nullptr, "GetRequest"},
46 {2, nullptr, "Acknowledge"},
47 {3, nullptr, "Finalize"},
48 {4, nullptr, "AcknowledgeEx"},
49 };
50 // clang-format on
51
52 RegisterHandlers(functions);
53 }
54};
55
56class IPmService final : public ServiceFramework<IPmService> {
57public:
58 explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
59 // clang-format off
60 static const FunctionInfo functions[] = {
61 {0, &IPmService::GetPmModule, "GetPmModule"},
62 };
63 // clang-format on
64
65 RegisterHandlers(functions);
66 }
67
68private:
69 void GetPmModule(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_PSC, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<IPmModule>(system);
75 }
76};
77
78void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
79 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
80 19
81 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); 20 server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
82 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); 21 server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
22 server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
23 server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));
83 24
84 auto time = std::make_shared<Time::TimeManager>(system); 25 auto time = std::make_shared<Time::TimeManager>(system);
85 26
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index 459137f42..c83d07ca8 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -7,10 +7,6 @@ namespace Core {
7class System; 7class System;
8} 8}
9 9
10namespace Service::SM {
11class ServiceManager;
12}
13
14namespace Service::PSC { 10namespace Service::PSC {
15 11
16void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp
index 24b85cc61..9a0adb295 100644
--- a/src/core/hle/service/psc/time/static.cpp
+++ b/src/core/hle/service/psc/time/static.cpp
@@ -144,7 +144,9 @@ Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
144 144
145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
146 Out<bool> out_is_enabled) { 146 Out<bool> out_is_enabled) {
147 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); }); 147 SCOPE_EXIT {
148 LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled);
149 };
148 150
149 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 151 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
150 152
@@ -180,7 +182,9 @@ Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
180} 182}
181 183
182Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) { 184Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); }); 185 SCOPE_EXIT {
186 LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient);
187 };
184 188
185 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); 189 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
186 190
@@ -189,7 +193,9 @@ Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> o
189 193
190Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 194Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
191 Out<SteadyClockTimePoint> out_time_point) { 195 Out<SteadyClockTimePoint> out_time_point) {
192 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 196 SCOPE_EXIT {
197 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
198 };
193 199
194 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 200 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
195 201
@@ -200,7 +206,9 @@ Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
200 206
201Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 207Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
202 Out<s64> out_time, const SystemClockContext& context) { 208 Out<s64> out_time, const SystemClockContext& context) {
203 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); }); 209 SCOPE_EXIT {
210 LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time);
211 };
204 212
205 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); 213 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
206 214
@@ -219,8 +227,9 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
219} 227}
220 228
221Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) { 229Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
222 SCOPE_EXIT( 230 SCOPE_EXIT {
223 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); }); 231 LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot);
232 };
224 233
225 SystemClockContext user_context{}; 234 SystemClockContext user_context{};
226 R_TRY(m_user_system_clock.GetContext(user_context)); 235 R_TRY(m_user_system_clock.GetContext(user_context));
@@ -234,11 +243,11 @@ Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType t
234Result StaticService::GetClockSnapshotFromSystemClockContext( 243Result StaticService::GetClockSnapshotFromSystemClockContext(
235 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context, 244 TimeType type, OutClockSnapshot out_snapshot, const SystemClockContext& user_context,
236 const SystemClockContext& network_context) { 245 const SystemClockContext& network_context) {
237 SCOPE_EXIT({ 246 SCOPE_EXIT {
238 LOG_DEBUG(Service_Time, 247 LOG_DEBUG(Service_Time,
239 "called. type={} user_context={} network_context={} out_snapshot={}", type, 248 "called. type={} user_context={} network_context={} out_snapshot={}", type,
240 user_context, network_context, *out_snapshot); 249 user_context, network_context, *out_snapshot);
241 }); 250 };
242 251
243 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); 252 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
244} 253}
@@ -246,9 +255,9 @@ Result StaticService::GetClockSnapshotFromSystemClockContext(
246Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference, 255Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
247 InClockSnapshot a, 256 InClockSnapshot a,
248 InClockSnapshot b) { 257 InClockSnapshot b) {
249 SCOPE_EXIT({ 258 SCOPE_EXIT {
250 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference); 259 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
251 }); 260 };
252 261
253 auto diff_s = 262 auto diff_s =
254 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset); 263 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
@@ -276,7 +285,9 @@ Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64>
276 285
277Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, 286Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
278 InClockSnapshot b) { 287 InClockSnapshot b) {
279 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); }); 288 SCOPE_EXIT {
289 LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time);
290 };
280 291
281 s64 time_s{}; 292 s64 time_s{};
282 auto res = 293 auto res =
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp
index 948610a2b..78dcf532c 100644
--- a/src/core/hle/service/psc/time/steady_clock.cpp
+++ b/src/core/hle/service/psc/time/steady_clock.cpp
@@ -29,7 +29,9 @@ SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> man
29} 29}
30 30
31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) { 31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) {
32 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); }); 32 SCOPE_EXIT {
33 LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point);
34 };
33 35
34 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 36 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
35 ResultClockUninitialized); 37 ResultClockUninitialized);
@@ -38,7 +40,9 @@ Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point
38} 40}
39 41
40Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) { 42Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) {
41 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); }); 43 SCOPE_EXIT {
44 LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset);
45 };
42 46
43 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 47 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
44 ResultClockUninitialized); 48 ResultClockUninitialized);
@@ -59,7 +63,9 @@ Result SteadyClock::SetTestOffset(s64 test_offset) {
59} 63}
60 64
61Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) { 65Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
62 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); }); 66 SCOPE_EXIT {
67 LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value);
68 };
63 69
64 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 70 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
65 ResultClockUninitialized); 71 ResultClockUninitialized);
@@ -68,7 +74,9 @@ Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
68} 74}
69 75
70Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) { 76Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
71 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); }); 77 SCOPE_EXIT {
78 LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected);
79 };
72 80
73 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 81 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
74 ResultClockUninitialized); 82 ResultClockUninitialized);
@@ -78,7 +86,9 @@ Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
78} 86}
79 87
80Result SteadyClock::GetSetupResultValue(Out<Result> out_result) { 88Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
81 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); }); 89 SCOPE_EXIT {
90 LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw);
91 };
82 92
83 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 93 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
84 ResultClockUninitialized); 94 ResultClockUninitialized);
@@ -88,8 +98,9 @@ Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
88} 98}
89 99
90Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) { 100Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) {
91 SCOPE_EXIT( 101 SCOPE_EXIT {
92 { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); }); 102 LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset);
103 };
93 104
94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 105 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
95 ResultClockUninitialized); 106 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp
index b4e9264d8..9f841d8e0 100644
--- a/src/core/hle/service/psc/time/system_clock.cpp
+++ b/src/core/hle/service/psc/time/system_clock.cpp
@@ -26,7 +26,9 @@ SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, boo
26} 26}
27 27
28Result SystemClock::GetCurrentTime(Out<s64> out_time) { 28Result SystemClock::GetCurrentTime(Out<s64> out_time) {
29 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); }); 29 SCOPE_EXIT {
30 LOG_DEBUG(Service_Time, "called. out_time={}", *out_time);
31 };
30 32
31 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 33 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
32 ResultClockUninitialized); 34 ResultClockUninitialized);
@@ -45,7 +47,9 @@ Result SystemClock::SetCurrentTime(s64 time) {
45} 47}
46 48
47Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) { 49Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
48 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); }); 50 SCOPE_EXIT {
51 LOG_DEBUG(Service_Time, "called. out_context={}", *out_context);
52 };
49 53
50 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 54 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
51 ResultClockUninitialized); 55 ResultClockUninitialized);
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp
index 2f80030a4..9e0674f27 100644
--- a/src/core/hle/service/psc/time/time_zone_service.cpp
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -37,7 +37,9 @@ TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore&
37} 37}
38 38
39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) { 39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) {
40 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); }); 40 SCOPE_EXIT {
41 LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name);
42 };
41 43
42 R_RETURN(m_time_zone.GetLocationName(*out_location_name)); 44 R_RETURN(m_time_zone.GetLocationName(*out_location_name));
43} 45}
@@ -50,7 +52,9 @@ Result TimeZoneService::SetDeviceLocationName(const LocationName& location_name)
50} 52}
51 53
52Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) { 54Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
53 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); }); 55 SCOPE_EXIT {
56 LOG_DEBUG(Service_Time, "called. out_count={}", *out_count);
57 };
54 58
55 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count)); 59 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count));
56} 60}
@@ -69,17 +73,19 @@ Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, const LocationName& l
69} 73}
70 74
71Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) { 75Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) {
72 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); }); 76 SCOPE_EXIT {
77 LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version);
78 };
73 79
74 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version)); 80 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version));
75} 81}
76 82
77Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 83Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
78 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) { 84 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) {
79 SCOPE_EXIT({ 85 SCOPE_EXIT {
80 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}", 86 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}",
81 *out_location_name, *out_time_point); 87 *out_location_name, *out_time_point);
82 }); 88 };
83 89
84 R_TRY(m_time_zone.GetLocationName(*out_location_name)); 90 R_TRY(m_time_zone.GetLocationName(*out_location_name));
85 R_RETURN(m_time_zone.GetTimePoint(*out_time_point)); 91 R_RETURN(m_time_zone.GetTimePoint(*out_time_point));
@@ -116,10 +122,10 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
116Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time, 122Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
117 Out<CalendarAdditionalInfo> out_additional_info, s64 time, 123 Out<CalendarAdditionalInfo> out_additional_info, s64 time,
118 InRule rule) { 124 InRule rule) {
119 SCOPE_EXIT({ 125 SCOPE_EXIT {
120 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 126 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
121 *out_calendar_time, *out_additional_info); 127 *out_calendar_time, *out_additional_info);
122 }); 128 };
123 129
124 R_RETURN( 130 R_RETURN(
125 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get())); 131 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get()));
@@ -128,10 +134,10 @@ Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
128Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, 134Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
129 Out<CalendarAdditionalInfo> out_additional_info, 135 Out<CalendarAdditionalInfo> out_additional_info,
130 s64 time) { 136 s64 time) {
131 SCOPE_EXIT({ 137 SCOPE_EXIT {
132 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time, 138 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
133 *out_calendar_time, *out_additional_info); 139 *out_calendar_time, *out_additional_info);
134 }); 140 };
135 141
136 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time)); 142 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time));
137} 143}
@@ -139,11 +145,11 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_
139Result TimeZoneService::ToPosixTime(Out<u32> out_count, 145Result TimeZoneService::ToPosixTime(Out<u32> out_count,
140 OutArray<s64, BufferAttr_HipcPointer> out_times, 146 OutArray<s64, BufferAttr_HipcPointer> out_times,
141 const CalendarTime& calendar_time, InRule rule) { 147 const CalendarTime& calendar_time, InRule rule) {
142 SCOPE_EXIT({ 148 SCOPE_EXIT {
143 LOG_DEBUG(Service_Time, 149 LOG_DEBUG(Service_Time,
144 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 150 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
145 calendar_time, *out_count, out_times[0], out_times[1]); 151 calendar_time, *out_count, out_times[0], out_times[1]);
146 }); 152 };
147 153
148 R_RETURN( 154 R_RETURN(
149 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule)); 155 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule));
@@ -152,11 +158,11 @@ Result TimeZoneService::ToPosixTime(Out<u32> out_count,
152Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, 158Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
153 OutArray<s64, BufferAttr_HipcPointer> out_times, 159 OutArray<s64, BufferAttr_HipcPointer> out_times,
154 const CalendarTime& calendar_time) { 160 const CalendarTime& calendar_time) {
155 SCOPE_EXIT({ 161 SCOPE_EXIT {
156 LOG_DEBUG(Service_Time, 162 LOG_DEBUG(Service_Time,
157 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ", 163 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
158 calendar_time, *out_count, out_times[0], out_times[1]); 164 calendar_time, *out_count, out_times[0], out_times[1]);
159 }); 165 };
160 166
161 R_RETURN( 167 R_RETURN(
162 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time)); 168 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time));
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 8c7f94c8c..0b41bbcb9 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -177,10 +177,10 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
177 Kernel::KPort::Register(m_system.Kernel(), port); 177 Kernel::KPort::Register(m_system.Kernel(), port);
178 178
179 // Ensure that our reference to the port is closed if we fail to register it. 179 // Ensure that our reference to the port is closed if we fail to register it.
180 SCOPE_EXIT({ 180 SCOPE_EXIT {
181 port->GetClientPort().Close(); 181 port->GetClientPort().Close();
182 port->GetServerPort().Close(); 182 port->GetServerPort().Close();
183 }); 183 };
184 184
185 // Register the object name with the kernel. 185 // Register the object name with the kernel.
186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()), 186 R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()),
@@ -237,7 +237,9 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre
237} 237}
238 238
239Result ServerManager::LoopProcess() { 239Result ServerManager::LoopProcess() {
240 SCOPE_EXIT({ m_stopped.Set(); }); 240 SCOPE_EXIT {
241 m_stopped.Set();
242 };
241 243
242 R_RETURN(this->LoopProcessImpl()); 244 R_RETURN(this->LoopProcessImpl());
243} 245}
diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp
index a2a3e556c..3defa4b31 100644
--- a/src/core/hle/service/services.cpp
+++ b/src/core/hle/service/services.cpp
@@ -46,7 +46,7 @@
46#include "core/hle/service/olsc/olsc.h" 46#include "core/hle/service/olsc/olsc.h"
47#include "core/hle/service/omm/omm.h" 47#include "core/hle/service/omm/omm.h"
48#include "core/hle/service/pcie/pcie.h" 48#include "core/hle/service/pcie/pcie.h"
49#include "core/hle/service/pctl/pctl_module.h" 49#include "core/hle/service/pctl/pctl.h"
50#include "core/hle/service/pcv/pcv.h" 50#include "core/hle/service/pcv/pcv.h"
51#include "core/hle/service/pm/pm.h" 51#include "core/hle/service/pm/pm.h"
52#include "core/hle/service/prepo/prepo.h" 52#include "core/hle/service/prepo/prepo.h"
diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h
index 29664e88c..4fd34f46b 100644
--- a/src/core/hle/service/set/settings_types.h
+++ b/src/core/hle/service/set/settings_types.h
@@ -405,8 +405,7 @@ struct EulaVersion {
405 SystemRegionCode region_code; 405 SystemRegionCode region_code;
406 EulaVersionClockType clock_type; 406 EulaVersionClockType clock_type;
407 INSERT_PADDING_BYTES(0x4); 407 INSERT_PADDING_BYTES(0x4);
408 s64 posix_time; 408 Service::PSC::Time::SystemClockContext system_clock_context;
409 Service::PSC::Time::SteadyClockTimePoint timestamp;
410}; 409};
411static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); 410static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
412 411
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index 93925f783..a4475441e 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -306,6 +306,20 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
306 RegisterHandlers(functions); 306 RegisterHandlers(functions);
307 307
308 SetupSettings(); 308 SetupSettings();
309
310 m_system_settings.region_code =
311 static_cast<SystemRegionCode>(Settings::values.region_index.GetValue());
312
313 // TODO: Remove this when starter applet is fully functional
314 EulaVersion eula_version{
315 .version = 0x10000,
316 .region_code = m_system_settings.region_code,
317 .clock_type = EulaVersionClockType::SteadyClock,
318 .system_clock_context = m_system_settings.user_system_clock_context,
319 };
320 m_system_settings.eula_versions[0] = eula_version;
321 m_system_settings.eula_version_count = 1;
322
309 m_save_thread = 323 m_save_thread =
310 std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); }); 324 std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); });
311} 325}
diff --git a/src/core/hle/service/vi/conductor.h b/src/core/hle/service/vi/conductor.h
index 52e3595d2..6dd105dd4 100644
--- a/src/core/hle/service/vi/conductor.h
+++ b/src/core/hle/service/vi/conductor.h
@@ -10,6 +10,8 @@
10#include "common/polyfill_thread.h" 10#include "common/polyfill_thread.h"
11#include "common/thread.h" 11#include "common/thread.h"
12 12
13#include "core/hle/service/vi/vsync_manager.h"
14
13namespace Core { 15namespace Core {
14class System; 16class System;
15} 17}
@@ -26,7 +28,6 @@ namespace Service::VI {
26 28
27class Container; 29class Container;
28class DisplayList; 30class DisplayList;
29class VsyncManager;
30 31
31class Conductor { 32class Conductor {
32public: 33public:
diff --git a/src/core/hle/service/vi/container.cpp b/src/core/hle/service/vi/container.cpp
index 310a207f1..9074f4ae0 100644
--- a/src/core/hle/service/vi/container.cpp
+++ b/src/core/hle/service/vi/container.cpp
@@ -43,11 +43,7 @@ void Container::OnTerminate() {
43 43
44 m_is_shut_down = true; 44 m_is_shut_down = true;
45 45
46 m_layers.ForEachLayer([&](auto& layer) { 46 m_layers.ForEachLayer([&](auto& layer) { this->DestroyLayerLocked(layer.GetId()); });
47 if (layer.IsOpen()) {
48 this->DestroyBufferQueueLocked(&layer);
49 }
50 });
51 47
52 m_displays.ForEachDisplay( 48 m_displays.ForEachDisplay(
53 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); }); 49 [&](auto& display) { m_surface_flinger->RemoveDisplay(display.GetId()); });
@@ -161,16 +157,29 @@ Result Container::CreateLayerLocked(u64* out_layer_id, u64 display_id, u64 owner
161 auto* const display = m_displays.GetDisplayById(display_id); 157 auto* const display = m_displays.GetDisplayById(display_id);
162 R_UNLESS(display != nullptr, VI::ResultNotFound); 158 R_UNLESS(display != nullptr, VI::ResultNotFound);
163 159
164 auto* const layer = m_layers.CreateLayer(owner_aruid, display); 160 s32 consumer_binder_id, producer_binder_id;
161 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
162
163 auto* const layer =
164 m_layers.CreateLayer(owner_aruid, display, consumer_binder_id, producer_binder_id);
165 R_UNLESS(layer != nullptr, VI::ResultNotFound); 165 R_UNLESS(layer != nullptr, VI::ResultNotFound);
166 166
167 m_surface_flinger->CreateLayer(consumer_binder_id);
168
167 *out_layer_id = layer->GetId(); 169 *out_layer_id = layer->GetId();
168 R_SUCCEED(); 170 R_SUCCEED();
169} 171}
170 172
171Result Container::DestroyLayerLocked(u64 layer_id) { 173Result Container::DestroyLayerLocked(u64 layer_id) {
172 R_SUCCEED_IF(m_layers.DestroyLayer(layer_id)); 174 auto* const layer = m_layers.GetLayerById(layer_id);
173 R_THROW(VI::ResultNotFound); 175 R_UNLESS(layer != nullptr, VI::ResultNotFound);
176
177 m_surface_flinger->DestroyLayer(layer->GetConsumerBinderId());
178 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(),
179 layer->GetProducerBinderId());
180 m_layers.DestroyLayer(layer_id);
181
182 R_SUCCEED();
174} 183}
175 184
176Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) { 185Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid) {
@@ -181,7 +190,12 @@ Result Container::OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64
181 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed); 190 R_UNLESS(!layer->IsOpen(), VI::ResultOperationFailed);
182 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied); 191 R_UNLESS(layer->GetOwnerAruid() == aruid, VI::ResultPermissionDenied);
183 192
184 this->CreateBufferQueueLocked(layer); 193 layer->Open();
194
195 if (auto* display = layer->GetDisplay(); display != nullptr) {
196 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), layer->GetConsumerBinderId());
197 }
198
185 *out_producer_binder_id = layer->GetProducerBinderId(); 199 *out_producer_binder_id = layer->GetProducerBinderId();
186 200
187 R_SUCCEED(); 201 R_SUCCEED();
@@ -192,30 +206,14 @@ Result Container::CloseLayerLocked(u64 layer_id) {
192 R_UNLESS(layer != nullptr, VI::ResultNotFound); 206 R_UNLESS(layer != nullptr, VI::ResultNotFound);
193 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed); 207 R_UNLESS(layer->IsOpen(), VI::ResultOperationFailed);
194 208
195 this->DestroyBufferQueueLocked(layer);
196
197 R_SUCCEED();
198}
199
200void Container::CreateBufferQueueLocked(Layer* layer) {
201 s32 consumer_binder_id, producer_binder_id;
202 m_surface_flinger->CreateBufferQueue(&consumer_binder_id, &producer_binder_id);
203 layer->Open(consumer_binder_id, producer_binder_id);
204
205 if (auto* display = layer->GetDisplay(); display != nullptr) {
206 m_surface_flinger->AddLayerToDisplayStack(display->GetId(), consumer_binder_id);
207 }
208}
209
210void Container::DestroyBufferQueueLocked(Layer* layer) {
211 if (auto* display = layer->GetDisplay(); display != nullptr) { 209 if (auto* display = layer->GetDisplay(); display != nullptr) {
212 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(), 210 m_surface_flinger->RemoveLayerFromDisplayStack(display->GetId(),
213 layer->GetConsumerBinderId()); 211 layer->GetConsumerBinderId());
214 } 212 }
215 213
216 layer->Close(); 214 layer->Close();
217 m_surface_flinger->DestroyBufferQueue(layer->GetConsumerBinderId(), 215
218 layer->GetProducerBinderId()); 216 R_SUCCEED();
219} 217}
220 218
221bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, 219bool Container::ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale,
diff --git a/src/core/hle/service/vi/container.h b/src/core/hle/service/vi/container.h
index cd0d2ca86..5eac4d77d 100644
--- a/src/core/hle/service/vi/container.h
+++ b/src/core/hle/service/vi/container.h
@@ -72,9 +72,6 @@ private:
72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid); 72 Result OpenLayerLocked(s32* out_producer_binder_id, u64 layer_id, u64 aruid);
73 Result CloseLayerLocked(u64 layer_id); 73 Result CloseLayerLocked(u64 layer_id);
74 74
75 void CreateBufferQueueLocked(Layer* layer);
76 void DestroyBufferQueueLocked(Layer* layer);
77
78public: 75public:
79 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id); 76 bool ComposeOnDisplay(s32* out_swap_interval, f32* out_compose_speed_scale, u64 display_id);
80 77
diff --git a/src/core/hle/service/vi/layer.h b/src/core/hle/service/vi/layer.h
index b85c8df61..e4c9c9864 100644
--- a/src/core/hle/service/vi/layer.h
+++ b/src/core/hle/service/vi/layer.h
@@ -13,29 +13,31 @@ class Layer {
13public: 13public:
14 constexpr Layer() = default; 14 constexpr Layer() = default;
15 15
16 void Initialize(u64 id, u64 owner_aruid, Display* display) { 16 void Initialize(u64 id, u64 owner_aruid, Display* display, s32 consumer_binder_id,
17 s32 producer_binder_id) {
17 m_id = id; 18 m_id = id;
18 m_owner_aruid = owner_aruid; 19 m_owner_aruid = owner_aruid;
19 m_display = display; 20 m_display = display;
21 m_consumer_binder_id = consumer_binder_id;
22 m_producer_binder_id = producer_binder_id;
20 m_is_initialized = true; 23 m_is_initialized = true;
21 } 24 }
22 25
23 void Finalize() { 26 void Finalize() {
24 m_id = {}; 27 m_id = {};
28 m_owner_aruid = {};
25 m_display = {}; 29 m_display = {};
30 m_consumer_binder_id = {};
31 m_producer_binder_id = {};
26 m_is_initialized = {}; 32 m_is_initialized = {};
27 } 33 }
28 34
29 void Open(s32 consumer_binder_id, s32 producer_binder_id) { 35 void Open() {
30 m_consumer_binder_id = consumer_binder_id;
31 m_producer_binder_id = producer_binder_id;
32 m_is_open = true; 36 m_is_open = true;
33 } 37 }
34 38
35 void Close() { 39 void Close() {
36 m_producer_binder_id = {}; 40 m_is_open = false;
37 m_consumer_binder_id = {};
38 m_is_open = {};
39 } 41 }
40 42
41 u64 GetId() const { 43 u64 GetId() const {
diff --git a/src/core/hle/service/vi/layer_list.h b/src/core/hle/service/vi/layer_list.h
index 1738ede9a..4afca6f40 100644
--- a/src/core/hle/service/vi/layer_list.h
+++ b/src/core/hle/service/vi/layer_list.h
@@ -11,13 +11,15 @@ class LayerList {
11public: 11public:
12 constexpr LayerList() = default; 12 constexpr LayerList() = default;
13 13
14 Layer* CreateLayer(u64 owner_aruid, Display* display) { 14 Layer* CreateLayer(u64 owner_aruid, Display* display, s32 consumer_binder_id,
15 s32 producer_binder_id) {
15 Layer* const layer = GetFreeLayer(); 16 Layer* const layer = GetFreeLayer();
16 if (!layer) { 17 if (!layer) {
17 return nullptr; 18 return nullptr;
18 } 19 }
19 20
20 layer->Initialize(++m_next_id, owner_aruid, display); 21 layer->Initialize(++m_next_id, owner_aruid, display, consumer_binder_id,
22 producer_binder_id);
21 return layer; 23 return layer;
22 } 24 }
23 25
diff --git a/src/core/hle/service/vi/shared_buffer_manager.cpp b/src/core/hle/service/vi/shared_buffer_manager.cpp
index 869b18961..12cba16fa 100644
--- a/src/core/hle/service/vi/shared_buffer_manager.cpp
+++ b/src/core/hle/service/vi/shared_buffer_manager.cpp
@@ -285,7 +285,7 @@ void SharedBufferManager::DestroySession(Kernel::KProcess* owner_process) {
285 auto& session = it->second; 285 auto& session = it->second;
286 286
287 // Destroy the layer. 287 // Destroy the layer.
288 R_ASSERT(m_container.DestroyStrayLayer(session.layer_id)); 288 m_container.DestroyStrayLayer(session.layer_id);
289 289
290 // Close nvmap handle. 290 // Close nvmap handle.
291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd); 291 FreeHandle(session.buffer_nvmap_handle, *m_nvdrv, session.nvmap_fd);
@@ -322,8 +322,6 @@ Result SharedBufferManager::GetSharedBufferMemoryHandleId(u64* out_buffer_size,
322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence, 322Result SharedBufferManager::AcquireSharedFrameBuffer(android::Fence* out_fence,
323 std::array<s32, 4>& out_slot_indexes, 323 std::array<s32, 4>& out_slot_indexes,
324 s64* out_target_slot, u64 layer_id) { 324 s64* out_target_slot, u64 layer_id) {
325 std::scoped_lock lk{m_guard};
326
327 // Get the producer. 325 // Get the producer.
328 std::shared_ptr<android::BufferQueueProducer> producer; 326 std::shared_ptr<android::BufferQueueProducer> producer;
329 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 327 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -347,8 +345,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
347 Common::Rectangle<s32> crop_region, 345 Common::Rectangle<s32> crop_region,
348 u32 transform, s32 swap_interval, u64 layer_id, 346 u32 transform, s32 swap_interval, u64 layer_id,
349 s64 slot) { 347 s64 slot) {
350 std::scoped_lock lk{m_guard};
351
352 // Get the producer. 348 // Get the producer.
353 std::shared_ptr<android::BufferQueueProducer> producer; 349 std::shared_ptr<android::BufferQueueProducer> producer;
354 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 350 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -379,8 +375,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
379} 375}
380 376
381Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) { 377Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
382 std::scoped_lock lk{m_guard};
383
384 // Get the producer. 378 // Get the producer.
385 std::shared_ptr<android::BufferQueueProducer> producer; 379 std::shared_ptr<android::BufferQueueProducer> producer;
386 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 380 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));
@@ -394,8 +388,6 @@ Result SharedBufferManager::CancelSharedFrameBuffer(u64 layer_id, s64 slot) {
394 388
395Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event, 389Result SharedBufferManager::GetSharedFrameBufferAcquirableEvent(Kernel::KReadableEvent** out_event,
396 u64 layer_id) { 390 u64 layer_id) {
397 std::scoped_lock lk{m_guard};
398
399 // Get the producer. 391 // Get the producer.
400 std::shared_ptr<android::BufferQueueProducer> producer; 392 std::shared_ptr<android::BufferQueueProducer> producer;
401 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id)); 393 R_TRY(m_container.GetLayerProducerHandle(std::addressof(producer), layer_id));