diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8f1234481..d05a41bb6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -505,6 +505,8 @@ add_library(core STATIC hle/service/am/window_system.h hle/service/aoc/addon_content_manager.cpp hle/service/aoc/addon_content_manager.h + hle/service/aoc/contents_service_manager.cpp + hle/service/aoc/contents_service_manager.h hle/service/aoc/purchase_event_manager.cpp hle/service/aoc/purchase_event_manager.h hle/service/apm/apm.cpp diff --git a/src/core/hle/service/aoc/addon_content_manager.cpp b/src/core/hle/service/aoc/addon_content_manager.cpp index d47f57d64..fcc3525c3 100644 --- a/src/core/hle/service/aoc/addon_content_manager.cpp +++ b/src/core/hle/service/aoc/addon_content_manager.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -16,6 +17,7 @@ #include "core/file_sys/registered_cache.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/aoc/addon_content_manager.h" +#include "core/hle/service/aoc/contents_service_manager.h" #include "core/hle/service/aoc/purchase_event_manager.h" #include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" @@ -68,7 +70,7 @@ IAddOnContentManager::IAddOnContentManager(Core::System& system_) {50, D<&IAddOnContentManager::CheckAddOnContentMountStatus>, "CheckAddOnContentMountStatus"}, {100, D<&IAddOnContentManager::CreateEcPurchasedEventManager>, "CreateEcPurchasedEventManager"}, {101, D<&IAddOnContentManager::CreatePermanentEcPurchasedEventManager>, "CreatePermanentEcPurchasedEventManager"}, - {110, nullptr, "CreateContentsServiceManager"}, + {110, D<&IAddOnContentManager::CreateContentsServiceManager>, "CreateContentsServiceManager"}, {200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"}, {300, nullptr, "SetupHostAddOnContent"}, {301, nullptr, "GetRegisteredAddOnContentPath"}, @@ -214,6 +216,15 @@ Result IAddOnContentManager::CreatePermanentEcPurchasedEventManager( R_SUCCEED(); } +Result IAddOnContentManager::CreateContentsServiceManager( + OutInterface out_interface) { + LOG_WARNING(Service_AOC, "(STUBBED) called"); + + *out_interface = std::make_shared(system); + + R_SUCCEED(); +} + void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); server_manager->RegisterNamedService("aoc:u", std::make_shared(system)); diff --git a/src/core/hle/service/aoc/addon_content_manager.h b/src/core/hle/service/aoc/addon_content_manager.h index 91857df4c..c56a462ea 100644 --- a/src/core/hle/service/aoc/addon_content_manager.h +++ b/src/core/hle/service/aoc/addon_content_manager.h @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once @@ -18,6 +19,7 @@ class KEvent; namespace Service::AOC { class IPurchaseEventManager; +class IContentsServiceManager; class IAddOnContentManager final : public ServiceFramework { public: @@ -38,6 +40,7 @@ public: Result CreateEcPurchasedEventManager(OutInterface out_interface); Result CreatePermanentEcPurchasedEventManager( OutInterface out_interface); + Result CreateContentsServiceManager(OutInterface out_interface); private: std::vector add_on_content; diff --git a/src/core/hle/service/aoc/contents_service_manager.cpp b/src/core/hle/service/aoc/contents_service_manager.cpp new file mode 100644 index 000000000..0172303e1 --- /dev/null +++ b/src/core/hle/service/aoc/contents_service_manager.cpp @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/aoc/contents_service_manager.h" +#include "core/hle/service/cmif_serialization.h" +#include "core/hle/kernel/k_event.h" +#include "common/logging/log.h" + +namespace Service::AOC { + +IContentsServiceManager::IContentsServiceManager(Core::System& system_) + : ServiceFramework{system_, "IContentsServiceManager"}, + service_context{system_, "IContentsServiceManager"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IContentsServiceManager::RequestContentsAuthorizationToken>, "RequestContentsAuthorizationToken"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IContentsServiceManager::~IContentsServiceManager() = default; + +Result IContentsServiceManager::RequestContentsAuthorizationToken(OutInterface out_async_data, + u64 unknown, + InBuffer in_buffer) { + LOG_WARNING(Service_AOC, "(STUBBED) called with unknown={:016X}, buffer_size={}", unknown, in_buffer.size()); + + // Create a new IAsyncData interface to handle the authorization token request + *out_async_data = std::make_shared(system); + + R_SUCCEED(); +} + +IAsyncData::IAsyncData(Core::System& system_) + : ServiceFramework{system_, "IAsyncData"}, + service_context{system_, "IAsyncData"}, + is_complete{false} { + // clang-format off + static const FunctionInfo functions[] = { + {0, D<&IAsyncData::GetSize>, "GetSize"}, + {1, D<&IAsyncData::Read>, "Read"}, + {2, D<&IAsyncData::Cancel>, "Cancel"}, + {3, D<&IAsyncData::GetSystemEvent>, "GetSystemEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); + + async_event = service_context.CreateEvent("IAsyncData:AsyncEvent"); + + // Simulate completion immediately for stub + data_buffer.resize(0x100, 0); + is_complete = true; + async_event->Signal(); +} + +IAsyncData::~IAsyncData() { + service_context.CloseEvent(async_event); +} + +Result IAsyncData::GetSize(Out out_size) { + LOG_DEBUG(Service_AOC, "called"); + + *out_size = data_buffer.size(); + + R_SUCCEED(); +} + +Result IAsyncData::Read(OutBuffer out_buffer, u64 offset, u64 size) { + LOG_DEBUG(Service_AOC, "called with offset={:016X}, size={:016X}", offset, size); + + if (offset >= data_buffer.size()) { + R_SUCCEED(); + } + + const u64 read_size = std::min(size, static_cast(data_buffer.size() - offset)); + const u64 copy_size = std::min(read_size, out_buffer.size()); + + std::memcpy(out_buffer.data(), data_buffer.data() + offset, copy_size); + + R_SUCCEED(); +} + +Result IAsyncData::Cancel() { + LOG_WARNING(Service_AOC, "(STUBBED) called"); + + is_complete = false; + async_event->Clear(); + + R_SUCCEED(); +} + +Result IAsyncData::GetSystemEvent(OutCopyHandle out_event) { + LOG_DEBUG(Service_AOC, "called"); + + *out_event = &async_event->GetReadableEvent(); + + R_SUCCEED(); +} + +} // namespace Service::AOC \ No newline at end of file diff --git a/src/core/hle/service/aoc/contents_service_manager.h b/src/core/hle/service/aoc/contents_service_manager.h new file mode 100644 index 000000000..25962183b --- /dev/null +++ b/src/core/hle/service/aoc/contents_service_manager.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KEvent; +class KReadableEvent; +} + +namespace Service::AOC { + +class IAsyncData; + +class IContentsServiceManager final : public ServiceFramework { +public: + explicit IContentsServiceManager(Core::System& system_); + ~IContentsServiceManager() override; + + Result RequestContentsAuthorizationToken(OutInterface out_async_data, + u64 unknown, + InBuffer in_buffer); + +private: + KernelHelpers::ServiceContext service_context; +}; + +class IAsyncData final : public ServiceFramework { +public: + explicit IAsyncData(Core::System& system_); + ~IAsyncData() override; + + Result GetSize(Out out_size); + Result Read(OutBuffer out_buffer, u64 offset, u64 size); + Result Cancel(); + Result GetSystemEvent(OutCopyHandle out_event); + +private: + KernelHelpers::ServiceContext service_context; + Kernel::KEvent* async_event; + std::vector data_buffer; + bool is_complete; +}; + +} // namespace Service::AOC \ No newline at end of file