code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/olsc/daemon_controller.h"
#include "core/hle/service/olsc/olsc_service_for_system_service.h"
#include "core/hle/service/olsc/remote_storage_controller.h"
#include "core/hle/service/olsc/transfer_task_list_controller.h"

namespace Service::OLSC {

IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_)
    : ServiceFramework{system_, "olsc:s"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
        {1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
        {2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
        {10, nullptr, "Unknown10"},
        {11, nullptr, "Unknown11"},
        {12, nullptr, "Unknown12"},
        {13, nullptr, "Unknown13"},
        {100, nullptr, "ListLastTransferTaskErrorInfo"},
        {101, nullptr, "GetLastErrorInfoCount"},
        {102, nullptr, "RemoveLastErrorInfoOld"},
        {103, nullptr, "GetLastErrorInfo"},
        {104, nullptr, "GetLastErrorEventHolder"},
        {105, nullptr, "GetLastTransferTaskErrorInfo"},
        {200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
        {201, nullptr, "RemoveDataTransferPolicyInfo"},
        {202, nullptr, "UpdateDataTransferPolicyOld"},
        {203, nullptr, "UpdateDataTransferPolicy"},
        {204, nullptr, "CleanupDataTransferPolicyInfo"},
        {205, nullptr, "RequestDataTransferPolicy"},
        {300, nullptr, "GetAutoTransferSeriesInfo"},
        {301, nullptr, "UpdateAutoTransferSeriesInfo"},
        {400, nullptr, "CleanupSaveDataArchiveInfoType1"},
        {900, nullptr, "CleanupTransferTask"},
        {902, nullptr, "CleanupSeriesInfoType0"},
        {903, nullptr, "CleanupSaveDataArchiveInfoType0"},
        {904, nullptr, "CleanupApplicationAutoTransferSetting"},
        {905, nullptr, "CleanupErrorHistory"},
        {906, nullptr, "SetLastError"},
        {907, nullptr, "AddSaveDataArchiveInfoType0"},
        {908, nullptr, "RemoveSeriesInfoType0"},
        {909, nullptr, "GetSeriesInfoType0"},
        {910, nullptr, "RemoveLastErrorInfo"},
        {911, nullptr, "CleanupSeriesInfoType1"},
        {912, nullptr, "RemoveSeriesInfoType1"},
        {913, nullptr, "GetSeriesInfoType1"},
        {1000, nullptr, "UpdateIssueOld"},
        {1010, nullptr, "Unknown1010"},
        {1011, nullptr, "ListIssueInfoOld"},
        {1012, nullptr, "GetIssueOld"},
        {1013, nullptr, "GetIssue2Old"},
        {1014, nullptr, "GetIssue3Old"},
        {1020, nullptr, "RepairIssueOld"},
        {1021, nullptr, "RepairIssueWithUserIdOld"},
        {1022, nullptr, "RepairIssue2Old"},
        {1023, nullptr, "RepairIssue3Old"},
        {1024, nullptr, "Unknown1024"},
        {1100, nullptr, "UpdateIssue"},
        {1110, nullptr, "Unknown1110"},
        {1111, nullptr, "ListIssueInfo"},
        {1112, nullptr, "GetIssue"},
        {1113, nullptr, "GetIssue2"},
        {1114, nullptr, "GetIssue3"},
        {1120, nullptr, "RepairIssue"},
        {1121, nullptr, "RepairIssueWithUserId"},
        {1122, nullptr, "RepairIssue2"},
        {1123, nullptr, "RepairIssue3"},
        {1124, nullptr, "Unknown1124"},
        {10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;

Result IOlscServiceForSystemService::OpenTransferTaskListController(
    Out<SharedPointer<ITransferTaskListController>> out_interface) {
    LOG_INFO(Service_OLSC, "called");
    *out_interface = std::make_shared<ITransferTaskListController>(system);
    R_SUCCEED();
}

Result IOlscServiceForSystemService::OpenRemoteStorageController(
    Out<SharedPointer<IRemoteStorageController>> out_interface) {
    LOG_INFO(Service_OLSC, "called");
    *out_interface = std::make_shared<IRemoteStorageController>(system);
    R_SUCCEED();
}

Result IOlscServiceForSystemService::OpenDaemonController(
    Out<SharedPointer<IDaemonController>> out_interface) {
    LOG_INFO(Service_OLSC, "called");
    *out_interface = std::make_shared<IDaemonController>(system);
    R_SUCCEED();
}

Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(Out<u16> out_policy_info,
                                                               u64 application_id) {
    LOG_WARNING(Service_OLSC, "(STUBBED) called");
    *out_policy_info = 0;
    R_SUCCEED();
}

Result IOlscServiceForSystemService::CloneService(
    Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
    LOG_INFO(Service_OLSC, "called");
    *out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
    R_SUCCEED();
}

} // namespace Service::OLSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::OLSC {

class IDaemonController;
class IRemoteStorageController;
class ITransferTaskListController;

class IOlscServiceForSystemService final : public ServiceFramework<IOlscServiceForSystemService> {
public:
    explicit IOlscServiceForSystemService(Core::System& system_);
    ~IOlscServiceForSystemService() override;

private:
    Result OpenTransferTaskListController(
        Out<SharedPointer<ITransferTaskListController>> out_interface);
    Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
    Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
    Result GetDataTransferPolicyInfo(Out<u16> out_policy_info, u64 application_id);
    Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
};

} // namespace Service::OLSC

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/olsc/remote_storage_controller.h"

namespace Service::OLSC {

IRemoteStorageController::IRemoteStorageController(Core::System& system_)
    : ServiceFramework{system_, "IRemoteStorageController"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "GetSaveDataArchiveInfoBySaveDataId"},
        {1, nullptr, "GetSaveDataArchiveInfoByApplicationId"},
        {3, nullptr, "GetSaveDataArchiveCount"},
        {6, nullptr, "CleanupSaveDataArchives"},
        {7, nullptr, "CreateSaveDataArchiveCacheUpdationTask"},
        {8, nullptr, "CreateSaveDataArchiveCacheUpdationForSpecifiedApplicationTask"},
        {9, nullptr, "Delete"},
        {10, nullptr, "GetSeriesInfo"},
        {11, nullptr, "CreateDeleteDataTask"},
        {12, nullptr, "DeleteSeriesInfo"},
        {13, nullptr, "CreateRegisterNotificationTokenTask"},
        {14, nullptr, "UpdateSeriesInfo"},
        {15, nullptr, "RegisterUploadSaveDataTransferTaskForAutonomyRegistration"},
        {16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
        {17, nullptr, "ListDataInfo"},
        {18, nullptr, "GetDataInfo"},
        {19, nullptr, "Unknown19"},
        {20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
        {21, nullptr, "ListSecondarySaves"},
        {22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
        {23, nullptr, "TouchSecondarySave"},
        {24, nullptr, "GetSecondarySaveDataInfo"},
        {25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
        {900, nullptr, "Unknown900"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IRemoteStorageController::~IRemoteStorageController() = default;

Result IRemoteStorageController::GetSecondarySave(Out<bool> out_has_secondary_save,
                                                  Out<std::array<u64, 3>> out_unknown,
                                                  u64 application_id) {
    LOG_ERROR(Service_OLSC, "(STUBBED) called, application_id={:016X}", application_id);
    *out_has_secondary_save = false;
    *out_unknown = {};
    R_SUCCEED();
}

} // namespace Service::OLSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::OLSC {

class IRemoteStorageController final : public ServiceFramework<IRemoteStorageController> {
public:
    explicit IRemoteStorageController(Core::System& system_);
    ~IRemoteStorageController() override;

private:
    Result GetSecondarySave(Out<bool> out_has_secondary_save, Out<std::array<u64, 3>> out_unknown,
                            u64 application_id);
};

} // namespace Service::OLSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/olsc/native_handle_holder.h"
#include "core/hle/service/olsc/transfer_task_list_controller.h"

namespace Service::OLSC {

ITransferTaskListController::ITransferTaskListController(Core::System& system_)
    : ServiceFramework{system_, "ITransferTaskListController"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "Unknown0"},
        {1, nullptr, "Unknown1"},
        {2, nullptr, "Unknown2"},
        {3, nullptr, "Unknown3"},
        {4, nullptr, "Unknown4"},
        {5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
        {6, nullptr, "Unknown6"},
        {7, nullptr, "Unknown7"},
        {8, nullptr, "GetRemoteStorageController"},
        {9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
        {10, nullptr, "Unknown10"},
        {11, nullptr, "Unknown11"},
        {12, nullptr, "Unknown12"},
        {13, nullptr, "Unknown13"},
        {14, nullptr, "Unknown14"},
        {15, nullptr, "Unknown15"},
        {16, nullptr, "Unknown16"},
        {17, nullptr, "Unknown17"},
        {18, nullptr, "Unknown18"},
        {19, nullptr, "Unknown19"},
        {20, nullptr, "Unknown20"},
        {21, nullptr, "Unknown21"},
        {22, nullptr, "Unknown22"},
        {23, nullptr, "Unknown23"},
        {24, nullptr, "Unknown24"},
        {25, nullptr, "Unknown25"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

ITransferTaskListController::~ITransferTaskListController() = default;

Result ITransferTaskListController::GetNativeHandleHolder(
    Out<SharedPointer<INativeHandleHolder>> out_holder) {
    LOG_WARNING(Service_OLSC, "(STUBBED) called");
    *out_holder = std::make_shared<INativeHandleHolder>(system);
    R_SUCCEED();
}

} // namespace Service::OLSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::OLSC {

class INativeHandleHolder;

class ITransferTaskListController final : public ServiceFramework<ITransferTaskListController> {
public:
    explicit ITransferTaskListController(Core::System& system_);
    ~ITransferTaskListController() override;

private:
    Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
};

} // namespace Service::OLSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/omm/omm.h"
#include "core/hle/service/omm/operation_mode_manager.h"
#include "core/hle/service/omm/policy_manager_system.h"
#include "core/hle/service/omm/power_state_interface.h"
#include "core/hle/service/server_manager.h"

namespace Service::OMM {

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("idle:sys",
                                         std::make_shared<IPolicyManagerSystem>(system));
    server_manager->RegisterNamedService("omm", std::make_shared<IOperationModeManager>(system));
    server_manager->RegisterNamedService("spsm", std::make_shared<IPowerStateInterface>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::OMM {

void LoopProcess(Core::System& system);

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/omm/operation_mode_manager.h"

namespace Service::OMM {

IOperationModeManager::IOperationModeManager(Core::System& system_)
    : ServiceFramework{system_, "omm"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "GetOperationMode"},
        {1, nullptr, "GetOperationModeChangeEvent"},
        {2, nullptr, "EnableAudioVisual"},
        {3, nullptr, "DisableAudioVisual"},
        {4, nullptr, "EnterSleepAndWait"},
        {5, nullptr, "GetCradleStatus"},
        {6, nullptr, "FadeInDisplay"},
        {7, nullptr, "FadeOutDisplay"},
        {8, nullptr, "GetCradleFwVersion"},
        {9, nullptr, "NotifyCecSettingsChanged"},
        {10, nullptr, "SetOperationModePolicy"},
        {11, nullptr, "GetDefaultDisplayResolution"},
        {12, nullptr, "GetDefaultDisplayResolutionChangeEvent"},
        {13, nullptr, "UpdateDefaultDisplayResolution"},
        {14, nullptr, "ShouldSleepOnBoot"},
        {15, nullptr, "NotifyHdcpApplicationExecutionStarted"},
        {16, nullptr, "NotifyHdcpApplicationExecutionFinished"},
        {17, nullptr, "NotifyHdcpApplicationDrawingStarted"},
        {18, nullptr, "NotifyHdcpApplicationDrawingFinished"},
        {19, nullptr, "GetHdcpAuthenticationFailedEvent"},
        {20, nullptr, "GetHdcpAuthenticationFailedEmulationEnabled"},
        {21, nullptr, "SetHdcpAuthenticationFailedEmulation"},
        {22, nullptr, "GetHdcpStateChangeEvent"},
        {23, nullptr, "GetHdcpState"},
        {24, nullptr, "ShowCardUpdateProcessing"},
        {25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"},
        {26, nullptr, "GetOperationModeSystemInfo"},
        {27, nullptr, "GetAppletFullAwakingSystemEvent"},
        {28, nullptr, "CreateCradleFirmwareUpdater"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IOperationModeManager::~IOperationModeManager() = default;

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::OMM {

class IOperationModeManager final : public ServiceFramework<IOperationModeManager> {
public:
    explicit IOperationModeManager(Core::System& system_);
    ~IOperationModeManager() override;
};

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/omm/policy_manager_system.h"

namespace Service::OMM {

IPolicyManagerSystem::IPolicyManagerSystem(Core::System& system_)
    : ServiceFramework{system_, "idle:sys"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "GetAutoPowerDownEvent"},
        {1, nullptr, "IsAutoPowerDownRequested"},
        {2, nullptr, "Unknown2"},
        {3, nullptr, "SetHandlingContext"},
        {4, nullptr, "LoadAndApplySettings"},
        {5, nullptr, "ReportUserIsActive"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IPolicyManagerSystem::~IPolicyManagerSystem() = default;

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::OMM {

class IPolicyManagerSystem final : public ServiceFramework<IPolicyManagerSystem> {
public:
    explicit IPolicyManagerSystem(Core::System& system_);
    ~IPolicyManagerSystem() override;
};

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/omm/power_state_interface.h"

namespace Service::OMM {

IPowerStateInterface::IPowerStateInterface(Core::System& system_)
    : ServiceFramework{system_, "spsm"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "GetState"},
        {1, nullptr, "EnterSleep"},
        {2, nullptr, "GetLastWakeReason"},
        {3, nullptr, "Shutdown"},
        {4, nullptr, "GetNotificationMessageEventHandle"},
        {5, nullptr, "ReceiveNotificationMessage"},
        {6, nullptr, "AnalyzeLogForLastSleepWakeSequence"},
        {7, nullptr, "ResetEventLog"},
        {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"},
        {9, nullptr, "ChangeHomeButtonLongPressingTime"},
        {10, nullptr, "PutErrorState"},
        {11, nullptr, "InvalidateCurrentHomeButtonPressing"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IPowerStateInterface::~IPowerStateInterface() = default;

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::OMM {

class IPowerStateInterface final : public ServiceFramework<IPowerStateInterface> {
public:
    explicit IPowerStateInterface(Core::System& system_);
    ~IPowerStateInterface() override;
};

} // namespace Service::OMM


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/kernel/k_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"

namespace Service {

Event::Event(KernelHelpers::ServiceContext& ctx) {
    m_event = ctx.CreateEvent("Event");
}

Event::~Event() {
    m_event->GetReadableEvent().Close();
    m_event->Close();
}

void Event::Signal() {
    m_event->Signal();
}

void Event::Clear() {
    m_event->Clear();
}

Kernel::KReadableEvent* Event::GetHandle() {
    return &m_event->GetReadableEvent();
}

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Kernel {
class KEvent;
class KReadableEvent;
} // namespace Kernel

namespace Service {

namespace KernelHelpers {
class ServiceContext;
}

class Event {
public:
    explicit Event(KernelHelpers::ServiceContext& ctx);
    ~Event();

    void Signal();
    void Clear();

    Kernel::KReadableEvent* GetHandle();

private:
    Kernel::KEvent* m_event;
};

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/kernel/k_hardware_timer.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_common.h"
#include "core/hle/service/os/multi_wait.h"

namespace Service {

MultiWait::MultiWait() = default;
MultiWait::~MultiWait() = default;

MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) {
    return this->TimedWaitImpl(kernel, -1);
}

MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) {
    return this->TimedWaitImpl(kernel, 0);
}

MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) {
    return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns);
}

MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) {
    std::array<MultiWaitHolder*, Kernel::Svc::ArgumentHandleCountMax> holders{};
    std::array<Kernel::KSynchronizationObject*, Kernel::Svc::ArgumentHandleCountMax> objects{};

    s32 out_index = -1;
    s32 num_objects = 0;

    for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) {
        ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax);
        holders[num_objects] = std::addressof(*it);
        objects[num_objects] = it->GetNativeHandle();
        num_objects++;
    }

    Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(),
                                         num_objects, timeout_tick);

    if (out_index == -1) {
        return nullptr;
    } else {
        return holders[out_index];
    }
}

void MultiWait::MoveAll(MultiWait* other) {
    while (!other->m_wait_list.empty()) {
        MultiWaitHolder& holder = other->m_wait_list.front();
        holder.UnlinkFromMultiWait();
        holder.LinkToMultiWait(this);
    }
}

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/os/multi_wait_holder.h"

namespace Kernel {
class KernelCore;
}

namespace Service {

class MultiWait final {
public:
    explicit MultiWait();
    ~MultiWait();

public:
    MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel);
    MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel);
    MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns);
    // TODO: SdkReplyAndReceive?

    void MoveAll(MultiWait* other);

private:
    MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick);

private:
    friend class MultiWaitHolder;
    using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType;
    ListType m_wait_list{};
};

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/os/multi_wait.h"
#include "core/hle/service/os/multi_wait_holder.h"

namespace Service {

void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) {
    if (m_multi_wait != nullptr) {
        UNREACHABLE();
    }

    m_multi_wait = multi_wait;
    m_multi_wait->m_wait_list.push_back(*this);
}

void MultiWaitHolder::UnlinkFromMultiWait() {
    if (m_multi_wait) {
        m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this));
        m_multi_wait = nullptr;
    }
}

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/intrusive_list.h"

namespace Kernel {
class KSynchronizationObject;
} // namespace Kernel

namespace Service {

class MultiWait;

class MultiWaitHolder {
public:
    explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle)
        : m_native_handle(native_handle) {}

    void LinkToMultiWait(MultiWait* multi_wait);
    void UnlinkFromMultiWait();

    void SetUserData(uintptr_t user_data) {
        m_user_data = user_data;
    }

    uintptr_t GetUserData() const {
        return m_user_data;
    }

    Kernel::KSynchronizationObject* GetNativeHandle() const {
        return m_native_handle;
    }

private:
    friend class MultiWait;
    Common::IntrusiveListNode m_list_node{};
    MultiWait* m_multi_wait{};
    Kernel::KSynchronizationObject* m_native_handle{};
    uintptr_t m_user_data{};
};

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/os/multi_wait.h"

namespace Service {

namespace impl {

class AutoMultiWaitHolder {
private:
    MultiWaitHolder m_holder;

public:
    template <typename T>
    explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) {
        m_holder.LinkToMultiWait(multi_wait);
    }

    ~AutoMultiWaitHolder() {
        m_holder.UnlinkFromMultiWait();
    }

    std::pair<MultiWaitHolder*, int> ConvertResult(const std::pair<MultiWaitHolder*, int> result,
                                                   int index) {
        if (result.first == std::addressof(m_holder)) {
            return std::make_pair(static_cast<MultiWaitHolder*>(nullptr), index);
        } else {
            return result;
        }
    }
};

using WaitAnyFunction = decltype(&MultiWait::WaitAny);

inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
                                                    MultiWait* multi_wait, WaitAnyFunction func,
                                                    int) {
    return std::pair<MultiWaitHolder*, int>((multi_wait->*func)(kernel), -1);
}

template <typename T, typename... Args>
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
                                                    MultiWait* multi_wait, WaitAnyFunction func,
                                                    int index, T&& x, Args&&... args) {
    AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x));
    return holder.ConvertResult(
        WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward<Args>(args)...), index);
}

template <typename... Args>
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
                                                    MultiWait* multi_wait, WaitAnyFunction func,
                                                    Args&&... args) {
    return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward<Args>(args)...);
}

template <typename... Args>
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
                                                    WaitAnyFunction func, Args&&... args) {
    MultiWait temp_multi_wait;
    return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0,
                       std::forward<Args>(args)...);
}

class NotBoolButInt {
public:
    constexpr NotBoolButInt(int v) : m_value(v) {}
    constexpr operator int() const {
        return m_value;
    }
    explicit operator bool() const = delete;

private:
    int m_value;
};

} // namespace impl

template <typename... Args>
    requires(sizeof...(Args) > 0)
inline std::pair<MultiWaitHolder*, int> WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait,
                                                Args&&... args) {
    return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward<Args>(args)...);
}

template <typename... Args>
    requires(sizeof...(Args) > 0)
inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) {
    return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second;
}

template <typename... Args>
    requires(sizeof...(Args) > 0)
inline std::pair<MultiWaitHolder*, int> TryWaitAny(Kernel::KernelCore& kernel,
                                                   MultiWait* multi_wait, Args&&... args) {
    return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait,
                             std::forward<Args>(args)...);
}

template <typename... Args>
    requires(sizeof...(Args) > 0)
inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) {
    return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward<Args>(args)...).second;
}

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/service/os/mutex.h"

namespace Service {

Mutex::Mutex(Core::System& system) : m_system(system) {
    m_event = Kernel::KEvent::Create(system.Kernel());
    m_event->Initialize(nullptr);

    // Register the event.
    Kernel::KEvent::Register(system.Kernel(), m_event);

    ASSERT(R_SUCCEEDED(m_event->Signal()));
}

Mutex::~Mutex() {
    m_event->GetReadableEvent().Close();
    m_event->Close();
}

void Mutex::lock() {
    // Infinitely retry until we successfully clear the event.
    while (R_FAILED(m_event->GetReadableEvent().Reset())) {
        s32 index;
        Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent();

        // The event was already cleared!
        // Wait for it to become signaled again.
        ASSERT(R_SUCCEEDED(
            Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1)));
    }

    // We successfully cleared the event, and now have exclusive ownership.
}

void Mutex::unlock() {
    // Unlock.
    ASSERT(R_SUCCEEDED(m_event->Signal()));
}

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_types.h"

namespace Core {
class System;
}

namespace Kernel {
class KEvent;
}

namespace Service {

class Mutex {
public:
    explicit Mutex(Core::System& system);
    ~Mutex();

    void lock();
    void unlock();

private:
    Core::System& m_system;
    Kernel::KEvent* m_event{};
};

} // namespace Service


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <memory>

#include "core/hle/service/pcie/pcie.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::PCIe {

class ISession final : public ServiceFramework<ISession> {
public:
    explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "QueryFunctions"},
            {1, nullptr, "AcquireFunction"},
            {2, nullptr, "ReleaseFunction"},
            {3, nullptr, "GetFunctionState"},
            {4, nullptr, "GetBarProfile"},
            {5, nullptr, "ReadConfig"},
            {6, nullptr, "WriteConfig"},
            {7, nullptr, "ReadBarRegion"},
            {8, nullptr, "WriteBarRegion"},
            {9, nullptr, "FindCapability"},
            {10, nullptr, "FindExtendedCapability"},
            {11, nullptr, "MapDma"},
            {12, nullptr, "UnmapDma"},
            {13, nullptr, "UnmapDmaBusAddress"},
            {14, nullptr, "GetDmaBusAddress"},
            {15, nullptr, "GetDmaBusAddressRange"},
            {16, nullptr, "SetDmaEnable"},
            {17, nullptr, "AcquireIrq"},
            {18, nullptr, "ReleaseIrq"},
            {19, nullptr, "SetIrqEnable"},
            {20, nullptr, "SetAspmEnable"},
            {21, nullptr, "SetResetUponResumeEnable"},
            {22, nullptr, "ResetFunction"},
            {23, nullptr, "Unknown23"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class PCIe final : public ServiceFramework<PCIe> {
public:
    explicit PCIe(Core::System& system_) : ServiceFramework{system_, "pcie"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "RegisterClassDriver"},
            {1, nullptr, "QueryFunctionsUnregistered"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("pcie", std::make_shared<PCIe>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PCIe


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::PCIe {

void LoopProcess(Core::System& system);

} // namespace Service::PCIe


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pctl/parental_control_service.h"
#include "core/hle/service/pctl/pctl_results.h"

namespace Service::PCTL {

IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
    : ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
      service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
      unlinked_event{service_context}, request_suspension_event{service_context} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {1, D<&IParentalControlService::Initialize>, "Initialize"},
        {1001, D<&IParentalControlService::CheckFreeCommunicationPermission>, "CheckFreeCommunicationPermission"},
        {1002, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
        {1003, D<&IParentalControlService::ConfirmResumeApplicationPermission>, "ConfirmResumeApplicationPermission"},
        {1004, D<&IParentalControlService::ConfirmSnsPostPermission>, "ConfirmSnsPostPermission"},
        {1005, nullptr, "ConfirmSystemSettingsPermission"},
        {1006, D<&IParentalControlService::IsRestrictionTemporaryUnlocked>, "IsRestrictionTemporaryUnlocked"},
        {1007, nullptr, "RevertRestrictionTemporaryUnlocked"},
        {1008, nullptr, "EnterRestrictedSystemSettings"},
        {1009, nullptr, "LeaveRestrictedSystemSettings"},
        {1010, D<&IParentalControlService::IsRestrictedSystemSettingsEntered>, "IsRestrictedSystemSettingsEntered"},
        {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
        {1012, nullptr, "GetRestrictedFeatures"},
        {1013, D<&IParentalControlService::ConfirmStereoVisionPermission>, "ConfirmStereoVisionPermission"},
        {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
        {1015, nullptr, "ConfirmPlayableApplicationVideo"},
        {1016, nullptr, "ConfirmShowNewsPermission"},
        {1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
        {1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
        {1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
        {1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
        {1033, nullptr, "SetSafetyLevel"},
        {1034, nullptr, "GetSafetyLevelSettings"},
        {1035, D<&IParentalControlService::GetCurrentSettings>, "GetCurrentSettings"},
        {1036, nullptr, "SetCustomSafetyLevelSettings"},
        {1037, nullptr, "GetDefaultRatingOrganization"},
        {1038, nullptr, "SetDefaultRatingOrganization"},
        {1039, D<&IParentalControlService::GetFreeCommunicationApplicationListCount>, "GetFreeCommunicationApplicationListCount"},
        {1042, nullptr, "AddToFreeCommunicationApplicationList"},
        {1043, nullptr, "DeleteSettings"},
        {1044, nullptr, "GetFreeCommunicationApplicationList"},
        {1045, nullptr, "UpdateFreeCommunicationApplicationList"},
        {1046, nullptr, "DisableFeaturesForReset"},
        {1047, nullptr, "NotifyApplicationDownloadStarted"},
        {1048, nullptr, "NotifyNetworkProfileCreated"},
        {1049, nullptr, "ResetFreeCommunicationApplicationList"},
        {1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
        {1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
        {1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
        {1064, D<&IParentalControlService::ResetConfirmedStereoVisionPermission>, "ResetConfirmedStereoVisionPermission"},
        {1065, D<&IParentalControlService::IsStereoVisionPermitted>, "IsStereoVisionPermitted"},
        {1201, nullptr, "UnlockRestrictionTemporarily"},
        {1202, nullptr, "UnlockSystemSettingsRestriction"},
        {1203, nullptr, "SetPinCode"},
        {1204, nullptr, "GenerateInquiryCode"},
        {1205, nullptr, "CheckMasterKey"},
        {1206, D<&IParentalControlService::GetPinCodeLength>, "GetPinCodeLength"},
        {1207, nullptr, "GetPinCodeChangedEvent"},
        {1208, nullptr, "GetPinCode"},
        {1403, D<&IParentalControlService::IsPairingActive>, "IsPairingActive"},
        {1406, nullptr, "GetSettingsLastUpdated"},
        {1411, nullptr, "GetPairingAccountInfo"},
        {1421, nullptr, "GetAccountNickname"},
        {1424, nullptr, "GetAccountState"},
        {1425, nullptr, "RequestPostEvents"},
        {1426, nullptr, "GetPostEventInterval"},
        {1427, nullptr, "SetPostEventInterval"},
        {1432, D<&IParentalControlService::GetSynchronizationEvent>, "GetSynchronizationEvent"},
        {1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
        {1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
        {1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
        {1454, nullptr, "GetPlayTimerRemainingTime"},
        {1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
        {1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
        {1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
        {1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
        {1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
        {1472, nullptr, "CancelNetworkRequest"},
        {1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
        {1474, nullptr, "ClearUnlinkedEvent"},
        {1601, nullptr, "DisableAllFeatures"},
        {1602, nullptr, "PostEnableAllFeatures"},
        {1603, nullptr, "IsAllFeaturesDisabled"},
        {1901, nullptr, "DeleteFromFreeCommunicationApplicationListForDebug"},
        {1902, nullptr, "ClearFreeCommunicationApplicationListForDebug"},
        {1903, nullptr, "GetExemptApplicationListCountForDebug"},
        {1904, nullptr, "GetExemptApplicationListForDebug"},
        {1905, nullptr, "UpdateExemptApplicationListForDebug"},
        {1906, nullptr, "AddToExemptApplicationListForDebug"},
        {1907, nullptr, "DeleteFromExemptApplicationListForDebug"},
        {1908, nullptr, "ClearExemptApplicationListForDebug"},
        {1941, nullptr, "DeletePairing"},
        {1951, nullptr, "SetPlayTimerSettingsForDebug"},
        {1952, nullptr, "GetPlayTimerSpentTimeForTest"},
        {1953, nullptr, "SetPlayTimerAlarmDisabledForDebug"},
        {2001, nullptr, "RequestPairingAsync"},
        {2002, nullptr, "FinishRequestPairing"},
        {2003, nullptr, "AuthorizePairingAsync"},
        {2004, nullptr, "FinishAuthorizePairing"},
        {2005, nullptr, "RetrievePairingInfoAsync"},
        {2006, nullptr, "FinishRetrievePairingInfo"},
        {2007, nullptr, "UnlinkPairingAsync"},
        {2008, nullptr, "FinishUnlinkPairing"},
        {2009, nullptr, "GetAccountMiiImageAsync"},
        {2010, nullptr, "FinishGetAccountMiiImage"},
        {2011, nullptr, "GetAccountMiiImageContentTypeAsync"},
        {2012, nullptr, "FinishGetAccountMiiImageContentType"},
        {2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
        {2014, nullptr, "FinishSynchronizeParentalControlSettings"},
        {2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
        {2016, nullptr, "RequestUpdateExemptionListAsync"},
    };
    // clang-format on
    RegisterHandlers(functions);
}

IParentalControlService::~IParentalControlService() = default;

bool IParentalControlService::CheckFreeCommunicationPermissionImpl() const {
    if (states.temporary_unlocked) {
        return true;
    }
    if ((states.application_info.parental_control_flag & 1) == 0) {
        return true;
    }
    if (pin_code[0] == '\0') {
        return true;
    }
    if (!settings.is_free_communication_default_on) {
        return true;
    }
    // TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
    // but as we don't have multiproceses support yet, we can just assume our application is
    // valid for the time being
    return true;
}

bool IParentalControlService::ConfirmStereoVisionPermissionImpl() const {
    if (states.temporary_unlocked) {
        return true;
    }
    if (pin_code[0] == '\0') {
        return true;
    }
    if (!settings.is_stero_vision_restricted) {
        return false;
    }
    return true;
}

void IParentalControlService::SetStereoVisionRestrictionImpl(bool is_restricted) {
    if (settings.disabled) {
        return;
    }

    if (pin_code[0] == '\0') {
        return;
    }
    settings.is_stero_vision_restricted = is_restricted;
}

Result IParentalControlService::Initialize() {
    LOG_DEBUG(Service_PCTL, "called");

    if (False(capability & (Capability::Application | Capability::System))) {
        LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
        R_THROW(PCTL::ResultNoCapability);
    }

    // TODO(ogniK): Recovery flag initialization for pctl:r

    const auto program_id = system.GetApplicationProcessProgramID();
    if (program_id != 0) {
        const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
                                       system.GetContentProvider()};
        const auto control = pm.GetControlMetadata();
        if (control.first) {
            states.tid_from_event = 0;
            states.launch_time_valid = false;
            states.is_suspended = false;
            states.free_communication = false;
            states.stereo_vision = false;
            states.application_info = ApplicationInfo{
                .application_id = program_id,
                .age_rating = control.first->GetRatingAge(),
                .parental_control_flag = control.first->GetParentalControlFlag(),
                .capability = capability,
            };

            if (False(capability & (Capability::System | Capability::Recovery))) {
                // TODO(ogniK): Signal application launch event
            }
        }
    }

    R_SUCCEED();
}

Result IParentalControlService::CheckFreeCommunicationPermission() {
    LOG_DEBUG(Service_PCTL, "called");

    if (!CheckFreeCommunicationPermissionImpl()) {
        R_THROW(PCTL::ResultNoFreeCommunication);
    } else {
        states.free_communication = true;
        R_SUCCEED();
    }
}

Result IParentalControlService::ConfirmLaunchApplicationPermission(
    InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
    LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
                application_id);
    R_SUCCEED();
}

Result IParentalControlService::ConfirmResumeApplicationPermission(
    InBuffer<BufferAttr_HipcPointer> restriction_bitset, u64 nacp_flag, u64 application_id) {
    LOG_WARNING(Service_PCTL, "(STUBBED) called, nacp_flag={:#x} application_id={:016X}", nacp_flag,
                application_id);
    R_SUCCEED();
}

Result IParentalControlService::ConfirmSnsPostPermission() {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");
    R_THROW(PCTL::ResultNoFreeCommunication);
}

Result IParentalControlService::IsRestrictionTemporaryUnlocked(
    Out<bool> out_is_temporary_unlocked) {
    *out_is_temporary_unlocked = false;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
                *out_is_temporary_unlocked);
    R_SUCCEED();
}

Result IParentalControlService::IsRestrictedSystemSettingsEntered(
    Out<bool> out_is_restricted_system_settings_entered) {
    *out_is_restricted_system_settings_entered = false;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, is_temporary_unlocked={}",
                *out_is_restricted_system_settings_entered);
    R_SUCCEED();
}

Result IParentalControlService::ConfirmStereoVisionPermission() {
    LOG_DEBUG(Service_PCTL, "called");
    states.stereo_vision = true;
    R_SUCCEED();
}

Result IParentalControlService::EndFreeCommunication() {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");
    R_SUCCEED();
}

Result IParentalControlService::IsFreeCommunicationAvailable() {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");

    if (!CheckFreeCommunicationPermissionImpl()) {
        R_THROW(PCTL::ResultNoFreeCommunication);
    } else {
        R_SUCCEED();
    }
}

Result IParentalControlService::IsRestrictionEnabled(Out<bool> out_restriction_enabled) {
    LOG_DEBUG(Service_PCTL, "called");

    if (False(capability & (Capability::Status | Capability::Recovery))) {
        LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
        *out_restriction_enabled = false;
        R_THROW(PCTL::ResultNoCapability);
    }

    *out_restriction_enabled = pin_code[0] != '\0';
    R_SUCCEED();
}

Result IParentalControlService::GetSafetyLevel(Out<u32> out_safety_level) {
    *out_safety_level = 0;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, safety_level={}", *out_safety_level);
    R_SUCCEED();
}

Result IParentalControlService::GetCurrentSettings(Out<RestrictionSettings> out_settings) {
    LOG_INFO(Service_PCTL, "called");
    *out_settings = restriction_settings;
    R_SUCCEED();
}

Result IParentalControlService::GetFreeCommunicationApplicationListCount(Out<s32> out_count) {
    *out_count = 4;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, count={}", *out_count);
    R_SUCCEED();
}

Result IParentalControlService::ConfirmStereoVisionRestrictionConfigurable() {
    LOG_DEBUG(Service_PCTL, "called");

    if (False(capability & Capability::StereoVision)) {
        LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
        R_THROW(PCTL::ResultNoCapability);
    }

    if (pin_code[0] == '\0') {
        R_THROW(PCTL::ResultNoRestrictionEnabled);
    }

    R_SUCCEED();
}

Result IParentalControlService::IsStereoVisionPermitted(Out<bool> out_is_permitted) {
    LOG_DEBUG(Service_PCTL, "called");

    if (!ConfirmStereoVisionPermissionImpl()) {
        *out_is_permitted = false;
        R_THROW(PCTL::ResultStereoVisionRestricted);
    } else {
        *out_is_permitted = true;
        R_SUCCEED();
    }
}

Result IParentalControlService::GetPinCodeLength(Out<s32> out_length) {
    *out_length = 0;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, length={}", *out_length);
    R_SUCCEED();
}

Result IParentalControlService::IsPairingActive(Out<bool> out_is_pairing_active) {
    *out_is_pairing_active = false;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, is_pairing_active={}", *out_is_pairing_active);
    R_SUCCEED();
}

Result IParentalControlService::GetSynchronizationEvent(
    OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_INFO(Service_PCTL, "called");
    *out_event = synchronization_event.GetHandle();
    R_SUCCEED();
}

Result IParentalControlService::StartPlayTimer() {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");
    R_SUCCEED();
}

Result IParentalControlService::StopPlayTimer() {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");
    R_SUCCEED();
}

Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled) {
    *out_is_play_timer_enabled = false;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, enabled={}", *out_is_play_timer_enabled);
    R_SUCCEED();
}

Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
    *out_is_restricted_by_play_timer = false;
    LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
    R_SUCCEED();
}

Result IParentalControlService::GetPlayTimerSettings(
    Out<PlayTimerSettings> out_play_timer_settings) {
    LOG_WARNING(Service_PCTL, "(STUBBED) called");
    *out_play_timer_settings = {};
    R_SUCCEED();
}

Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
    OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_INFO(Service_PCTL, "called");
    *out_event = request_suspension_event.GetHandle();
    R_SUCCEED();
}

Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
    *out_play_timer_alarm_disabled = false;
    LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
             *out_play_timer_alarm_disabled);
    R_SUCCEED();
}

Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_INFO(Service_PCTL, "called");
    *out_event = unlinked_event.GetHandle();
    R_SUCCEED();
}

Result IParentalControlService::GetStereoVisionRestriction(
    Out<bool> out_stereo_vision_restriction) {
    LOG_DEBUG(Service_PCTL, "called");

    if (False(capability & Capability::StereoVision)) {
        LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
        *out_stereo_vision_restriction = false;
        R_THROW(PCTL::ResultNoCapability);
    }

    *out_stereo_vision_restriction = settings.is_stero_vision_restricted;
    R_SUCCEED();
}

Result IParentalControlService::SetStereoVisionRestriction(bool stereo_vision_restriction) {
    LOG_DEBUG(Service_PCTL, "called, can_use={}", stereo_vision_restriction);

    if (False(capability & Capability::StereoVision)) {
        LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
        R_THROW(PCTL::ResultNoCapability);
    }

    SetStereoVisionRestrictionImpl(stereo_vision_restriction);
    R_SUCCEED();
}

Result IParentalControlService::ResetConfirmedStereoVisionPermission() {
    LOG_DEBUG(Service_PCTL, "called");

    states.stereo_vision = false;

    R_SUCCEED();
}

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/pctl/pctl_types.h"
#include "core/hle/service/service.h"

namespace Service::PCTL {

class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
    explicit IParentalControlService(Core::System& system_, Capability capability_);
    ~IParentalControlService() override;

private:
    bool CheckFreeCommunicationPermissionImpl() const;
    bool ConfirmStereoVisionPermissionImpl() const;
    void SetStereoVisionRestrictionImpl(bool is_restricted);

    Result Initialize();
    Result CheckFreeCommunicationPermission();
    Result ConfirmLaunchApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
                                              u64 nacp_flag, u64 application_id);
    Result ConfirmResumeApplicationPermission(InBuffer<BufferAttr_HipcPointer> restriction_bitset,
                                              u64 nacp_flag, u64 application_id);
    Result ConfirmSnsPostPermission();
    Result IsRestrictionTemporaryUnlocked(Out<bool> out_is_temporary_unlocked);
    Result IsRestrictedSystemSettingsEntered(Out<bool> out_is_restricted_system_settings_entered);
    Result ConfirmStereoVisionPermission();
    Result EndFreeCommunication();
    Result IsFreeCommunicationAvailable();
    Result IsRestrictionEnabled(Out<bool> out_restriction_enabled);
    Result GetSafetyLevel(Out<u32> out_safety_level);
    Result GetCurrentSettings(Out<RestrictionSettings> out_settings);
    Result GetFreeCommunicationApplicationListCount(Out<s32> out_count);
    Result ConfirmStereoVisionRestrictionConfigurable();
    Result IsStereoVisionPermitted(Out<bool> out_is_permitted);
    Result GetPinCodeLength(Out<s32> out_length);
    Result IsPairingActive(Out<bool> out_is_pairing_active);
    Result GetSynchronizationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
    Result StartPlayTimer();
    Result StopPlayTimer();
    Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
    Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
    Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
    Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
    Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
    Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
    Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
    Result SetStereoVisionRestriction(bool stereo_vision_restriction);
    Result ResetConfirmedStereoVisionPermission();

    struct States {
        u64 current_tid{};
        ApplicationInfo application_info{};
        u64 tid_from_event{};
        bool launch_time_valid{};
        bool is_suspended{};
        bool temporary_unlocked{};
        bool free_communication{};
        bool stereo_vision{};
    };

    struct ParentalControlSettings {
        bool is_stero_vision_restricted{};
        bool is_free_communication_default_on{};
        bool disabled{};
    };

    States states{};
    ParentalControlSettings settings{};
    RestrictionSettings restriction_settings{};
    std::array<char, 8> pin_code{};
    Capability capability{};

    KernelHelpers::ServiceContext service_context;
    Event synchronization_event;
    Event unlinked_event;
    Event request_suspension_event;
};

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pctl/parental_control_service.h"
#include "core/hle/service/pctl/parental_control_service_factory.h"

namespace Service::PCTL {

IParentalControlServiceFactory::IParentalControlServiceFactory(Core::System& system_,
                                                               const char* name_,
                                                               Capability capability_)
    : ServiceFramework{system_, name_}, capability{capability_} {
    static const FunctionInfo functions[] = {
        {0, D<&IParentalControlServiceFactory::CreateService>, "CreateService"},
        {1, D<&IParentalControlServiceFactory::CreateServiceWithoutInitialize>,
         "CreateServiceWithoutInitialize"},
    };
    RegisterHandlers(functions);
}

IParentalControlServiceFactory::~IParentalControlServiceFactory() = default;

Result IParentalControlServiceFactory::CreateService(
    Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
    LOG_DEBUG(Service_PCTL, "called");
    // TODO(ogniK): Get application id from process
    *out_service = std::make_shared<IParentalControlService>(system, capability);
    R_SUCCEED();
}

Result IParentalControlServiceFactory::CreateServiceWithoutInitialize(
    Out<SharedPointer<IParentalControlService>> out_service, ClientProcessId process_id) {
    LOG_DEBUG(Service_PCTL, "called");
    // TODO(ogniK): Get application id from process
    *out_service = std::make_shared<IParentalControlService>(system, capability);
    R_SUCCEED();
}

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/pctl/pctl_types.h"
#include "core/hle/service/service.h"

namespace Service::PCTL {

class IParentalControlService;

class IParentalControlServiceFactory : public ServiceFramework<IParentalControlServiceFactory> {
public:
    explicit IParentalControlServiceFactory(Core::System& system_, const char* name_,
                                            Capability capability_);
    ~IParentalControlServiceFactory() override;

    Result CreateService(Out<SharedPointer<IParentalControlService>> out_service,
                         ClientProcessId process_id);
    Result CreateServiceWithoutInitialize(Out<SharedPointer<IParentalControlService>> out_service,
                                          ClientProcessId process_id);

private:
    Capability capability{};
};

void LoopProcess(Core::System& system);

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/pctl/parental_control_service_factory.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/server_manager.h"

namespace Service::PCTL {

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("pctl",
                                         std::make_shared<IParentalControlServiceFactory>(
                                             system, "pctl",
                                             Capability::Application | Capability::SnsPost |
                                                 Capability::Status | Capability::StereoVision));
    // TODO(ogniK): Implement remaining capabilities
    server_manager->RegisterNamedService("pctl:a", std::make_shared<IParentalControlServiceFactory>(
                                                       system, "pctl:a", Capability::None));
    server_manager->RegisterNamedService("pctl:r", std::make_shared<IParentalControlServiceFactory>(
                                                       system, "pctl:r", Capability::None));
    server_manager->RegisterNamedService("pctl:s", std::make_shared<IParentalControlServiceFactory>(
                                                       system, "pctl:s", Capability::None));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::PCTL {

void LoopProcess(Core::System& system);

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/result.h"

namespace Service::PCTL {

constexpr Result ResultNoFreeCommunication{ErrorModule::PCTL, 101};
constexpr Result ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
constexpr Result ResultNoCapability{ErrorModule::PCTL, 131};
constexpr Result ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_funcs.h"

namespace Service::PCTL {

enum class Capability : u32 {
    None = 0,
    Application = 1 << 0,
    SnsPost = 1 << 1,
    Recovery = 1 << 6,
    Status = 1 << 8,
    StereoVision = 1 << 9,
    System = 1 << 15,
};
DECLARE_ENUM_FLAG_OPERATORS(Capability);

struct ApplicationInfo {
    u64 application_id{};
    std::array<u8, 32> age_rating{};
    u32 parental_control_flag{};
    Capability capability{};
};
static_assert(sizeof(ApplicationInfo) == 0x30, "ApplicationInfo has incorrect size.");

// This is nn::pctl::RestrictionSettings
struct RestrictionSettings {
    u8 rating_age;
    bool sns_post_restriction;
    bool free_communication_restriction;
};
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");

// This is nn::pctl::PlayTimerSettings
struct PlayTimerSettings {
    std::array<u32, 13> settings;
};
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");

} // namespace Service::PCTL


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <memory>

#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::PCV {

class PCV final : public ServiceFramework<PCV> {
public:
    explicit PCV(Core::System& system_) : ServiceFramework{system_, "pcv"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "SetPowerEnabled"},
            {1, nullptr, "SetClockEnabled"},
            {2, nullptr, "SetClockRate"},
            {3, nullptr, "GetClockRate"},
            {4, nullptr, "GetState"},
            {5, nullptr, "GetPossibleClockRates"},
            {6, nullptr, "SetMinVClockRate"},
            {7, nullptr, "SetReset"},
            {8, nullptr, "SetVoltageEnabled"},
            {9, nullptr, "GetVoltageEnabled"},
            {10, nullptr, "GetVoltageRange"},
            {11, nullptr, "SetVoltageValue"},
            {12, nullptr, "GetVoltageValue"},
            {13, nullptr, "GetTemperatureThresholds"},
            {14, nullptr, "SetTemperature"},
            {15, nullptr, "Initialize"},
            {16, nullptr, "IsInitialized"},
            {17, nullptr, "Finalize"},
            {18, nullptr, "PowerOn"},
            {19, nullptr, "PowerOff"},
            {20, nullptr, "ChangeVoltage"},
            {21, nullptr, "GetPowerClockInfoEvent"},
            {22, nullptr, "GetOscillatorClock"},
            {23, nullptr, "GetDvfsTable"},
            {24, nullptr, "GetModuleStateTable"},
            {25, nullptr, "GetPowerDomainStateTable"},
            {26, nullptr, "GetFuseInfo"},
            {27, nullptr, "GetDramId"},
            {28, nullptr, "IsPoweredOn"},
            {29, nullptr, "GetVoltage"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class IClkrstSession final : public ServiceFramework<IClkrstSession> {
public:
    explicit IClkrstSession(Core::System& system_, DeviceCode device_code_)
        : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "SetClockEnabled"},
            {1, nullptr, "SetClockDisabled"},
            {2, nullptr, "SetResetAsserted"},
            {3, nullptr, "SetResetDeasserted"},
            {4, nullptr, "SetPowerEnabled"},
            {5, nullptr, "SetPowerDisabled"},
            {6, nullptr, "GetState"},
            {7, &IClkrstSession::SetClockRate, "SetClockRate"},
            {8, &IClkrstSession::GetClockRate, "GetClockRate"},
            {9, nullptr, "SetMinVClockRate"},
            {10, nullptr, "GetPossibleClockRates"},
            {11, nullptr, "GetDvfsTable"},
        };
        // clang-format on
        RegisterHandlers(functions);
    }

private:
    void SetClockRate(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        clock_rate = rp.Pop<u32>();
        LOG_DEBUG(Service_PCV, "(STUBBED) called, clock_rate={}", clock_rate);

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void GetClockRate(HLERequestContext& ctx) {
        LOG_DEBUG(Service_PCV, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.Push<u32>(clock_rate);
    }

    DeviceCode device_code;
    u32 clock_rate{};
};

class CLKRST final : public ServiceFramework<CLKRST> {
public:
    explicit CLKRST(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, &CLKRST::OpenSession, "OpenSession"},
            {1, nullptr, "GetTemperatureThresholds"},
            {2, nullptr, "SetTemperature"},
            {3, nullptr, "GetModuleStateTable"},
            {4, nullptr, "GetModuleStateTableEvent"},
            {5, nullptr, "GetModuleStateTableMaxCount"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    void OpenSession(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
        const auto unknown_input = rp.Pop<u32>();

        LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input);

        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
        rb.Push(ResultSuccess);
        rb.PushIpcInterface<IClkrstSession>(system, device_code);
    }
};

class CLKRST_A final : public ServiceFramework<CLKRST_A> {
public:
    explicit CLKRST_A(Core::System& system_) : ServiceFramework{system_, "clkrst:a"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "ReleaseControl"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("pcv", std::make_shared<PCV>(system));
    server_manager->RegisterNamedService("clkrst", std::make_shared<CLKRST>(system, "clkrst"));
    server_manager->RegisterNamedService("clkrst:i", std::make_shared<CLKRST>(system, "clkrst:i"));
    server_manager->RegisterNamedService("clkrst:a", std::make_shared<CLKRST_A>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PCV


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/core.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::PM {

namespace {

constexpr Result ResultProcessNotFound{ErrorModule::PM, 1};
[[maybe_unused]] constexpr Result ResultAlreadyStarted{ErrorModule::PM, 2};
[[maybe_unused]] constexpr Result ResultNotTerminated{ErrorModule::PM, 3};
[[maybe_unused]] constexpr Result ResultDebugHookInUse{ErrorModule::PM, 4};
[[maybe_unused]] constexpr Result ResultApplicationRunning{ErrorModule::PM, 5};
[[maybe_unused]] constexpr Result ResultInvalidSize{ErrorModule::PM, 6};

constexpr u64 NO_PROCESS_FOUND_PID{0};

using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>;

template <typename F>
Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list,
                                                              F&& predicate) {
    const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate);

    if (iter == process_list.end()) {
        return nullptr;
    }

    return iter->GetPointerUnsafe();
}

void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) {
    auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); });

    IPC::ResponseBuilder rb{ctx, 4};
    rb.Push(ResultSuccess);
    rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId());
}

} // Anonymous namespace

class BootMode final : public ServiceFramework<BootMode> {
public:
    explicit BootMode(Core::System& system_) : ServiceFramework{system_, "pm:bm"} {
        static const FunctionInfo functions[] = {
            {0, &BootMode::GetBootMode, "GetBootMode"},
            {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"},
        };
        RegisterHandlers(functions);
    }

private:
    void GetBootMode(HLERequestContext& ctx) {
        LOG_DEBUG(Service_PM, "called");

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.PushEnum(boot_mode);
    }

    void SetMaintenanceBoot(HLERequestContext& ctx) {
        LOG_DEBUG(Service_PM, "called");

        boot_mode = SystemBootMode::Maintenance;

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    SystemBootMode boot_mode = SystemBootMode::Normal;
};

class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
    explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "GetJitDebugProcessIdList"},
            {1, nullptr, "StartProcess"},
            {2, &DebugMonitor::GetProcessId, "GetProcessId"},
            {3, nullptr, "HookToCreateProcess"},
            {4, &DebugMonitor::GetApplicationProcessId, "GetApplicationProcessId"},
            {5, nullptr, "HookToCreateApplicationProgress"},
            {6, nullptr, "ClearHook"},
            {65000, &DebugMonitor::AtmosphereGetProcessInfo, "AtmosphereGetProcessInfo"},
            {65001, nullptr, "AtmosphereGetCurrentLimitInfo"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    void GetProcessId(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto program_id = rp.PopRaw<u64>();

        LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);

        auto list = kernel.GetProcessList();
        auto process = SearchProcessList(
            list, [program_id](auto& p) { return p->GetProgramId() == program_id; });

        if (process.IsNull()) {
            IPC::ResponseBuilder rb{ctx, 2};
            rb.Push(ResultProcessNotFound);
            return;
        }

        IPC::ResponseBuilder rb{ctx, 4};
        rb.Push(ResultSuccess);
        rb.Push(process->GetProcessId());
    }

    void GetApplicationProcessId(HLERequestContext& ctx) {
        LOG_DEBUG(Service_PM, "called");
        auto list = kernel.GetProcessList();
        GetApplicationPidGeneric(ctx, list);
    }

    void AtmosphereGetProcessInfo(HLERequestContext& ctx) {
        // https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/pm/source/impl/pm_process_manager.cpp#L614
        // This implementation is incomplete; only a handle to the process is returned.
        IPC::RequestParser rp{ctx};
        const auto pid = rp.PopRaw<u64>();

        LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);

        auto list = kernel.GetProcessList();
        auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; });

        if (process.IsNull()) {
            IPC::ResponseBuilder rb{ctx, 2};
            rb.Push(ResultProcessNotFound);
            return;
        }

        struct ProgramLocation {
            u64 program_id;
            u8 storage_id;
        };
        static_assert(sizeof(ProgramLocation) == 0x10, "ProgramLocation has an invalid size");

        struct OverrideStatus {
            u64 keys_held;
            u64 flags;
        };
        static_assert(sizeof(OverrideStatus) == 0x10, "OverrideStatus has an invalid size");

        OverrideStatus override_status{};
        ProgramLocation program_location{
            .program_id = process->GetProgramId(),
            .storage_id = 0,
        };

        IPC::ResponseBuilder rb{ctx, 10, 1};
        rb.Push(ResultSuccess);
        rb.PushCopyObjects(*process);
        rb.PushRaw(program_location);
        rb.PushRaw(override_status);
    }
};

class Info final : public ServiceFramework<Info> {
public:
    explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} {
        static const FunctionInfo functions[] = {
            {0, &Info::GetProgramId, "GetProgramId"},
            {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"},
            {65001, nullptr, "AtmosphereHasLaunchedProgram"},
            {65002, nullptr, "AtmosphereGetProcessInfo"},
        };
        RegisterHandlers(functions);
    }

private:
    void GetProgramId(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto process_id = rp.PopRaw<u64>();

        LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);

        auto list = kernel.GetProcessList();
        auto process = SearchProcessList(
            list, [process_id](auto& p) { return p->GetProcessId() == process_id; });

        if (process.IsNull()) {
            IPC::ResponseBuilder rb{ctx, 2};
            rb.Push(ResultProcessNotFound);
            return;
        }

        IPC::ResponseBuilder rb{ctx, 4};
        rb.Push(ResultSuccess);
        rb.Push(process->GetProgramId());
    }

    void AtmosphereGetProcessId(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto program_id = rp.PopRaw<u64>();

        LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);

        auto list = system.Kernel().GetProcessList();
        auto process = SearchProcessList(
            list, [program_id](auto& p) { return p->GetProgramId() == program_id; });

        if (process.IsNull()) {
            IPC::ResponseBuilder rb{ctx, 2};
            rb.Push(ResultProcessNotFound);
            return;
        }

        IPC::ResponseBuilder rb{ctx, 4};
        rb.Push(ResultSuccess);
        rb.Push(process->GetProcessId());
    }
};

class Shell final : public ServiceFramework<Shell> {
public:
    explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "LaunchProgram"},
            {1, nullptr, "TerminateProcess"},
            {2, nullptr, "TerminateProgram"},
            {3, nullptr, "GetProcessEventHandle"},
            {4, nullptr, "GetProcessEventInfo"},
            {5, nullptr, "NotifyBootFinished"},
            {6, &Shell::GetApplicationProcessIdForShell, "GetApplicationProcessIdForShell"},
            {7, nullptr, "BoostSystemMemoryResourceLimit"},
            {8, nullptr, "BoostApplicationThreadResourceLimit"},
            {9, nullptr, "GetBootFinishedEventHandle"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    void GetApplicationProcessIdForShell(HLERequestContext& ctx) {
        LOG_DEBUG(Service_PM, "called");
        auto list = kernel.GetProcessList();
        GetApplicationPidGeneric(ctx, list);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system));
    server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system));
    server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system));
    server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::PM {

enum class SystemBootMode {
    Normal,
    Maintenance,
};

void LoopProcess(Core::System& system);

} // namespace Service::PM


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/reporter.h"

namespace Service::PlayReport {

class PlayReport final : public ServiceFramework<PlayReport> {
public:
    explicit PlayReport(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"},
            {10101, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old>, "SaveReportWithUserOld"},
            {10102, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old2>, "SaveReportOld2"},
            {10103, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::Old2>, "SaveReportWithUserOld2"},
            {10104, &PlayReport::SaveReport<Core::Reporter::PlayReportType::New>, "SaveReport"},
            {10105, &PlayReport::SaveReportWithUser<Core::Reporter::PlayReportType::New>, "SaveReportWithUser"},
            {10200, &PlayReport::RequestImmediateTransmission, "RequestImmediateTransmission"},
            {10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"},
            {10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"},
            {20100, &PlayReport::SaveSystemReport, "SaveSystemReport"},
            {20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
            {20200, nullptr, "SetOperationMode"},
            {30100, nullptr, "ClearStorage"},
            {30200, nullptr, "ClearStatistics"},
            {30300, nullptr, "GetStorageUsage"},
            {30400, nullptr, "GetStatistics"},
            {30401, nullptr, "GetThroughputHistory"},
            {30500, nullptr, "GetLastUploadError"},
            {30600, nullptr, "GetApplicationUploadSummary"},
            {40100, nullptr, "IsUserAgreementCheckEnabled"},
            {40101, nullptr, "SetUserAgreementCheckEnabled"},
            {50100, nullptr, "ReadAllApplicationReportFiles"},
            {90100, nullptr, "ReadAllReportFiles"},
            {90101, nullptr, "Unknown90101"},
            {90102, nullptr, "Unknown90102"},
            {90200, nullptr, "GetStatistics"},
            {90201, nullptr, "GetThroughputHistory"},
            {90300, nullptr, "GetLastUploadError"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    template <Core::Reporter::PlayReportType Type>
    void SaveReport(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto process_id = rp.PopRaw<u64>();

        const auto data1 = ctx.ReadBufferA(0);
        const auto data2 = ctx.ReadBufferX(0);

        LOG_DEBUG(Service_PREPO,
                  "called, type={:02X}, process_id={:016X}, data1_size={:016X}, data2_size={:016X}",
                  Type, process_id, data1.size(), data2.size());

        const auto& reporter{system.GetReporter()};
        reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
                                process_id);

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    template <Core::Reporter::PlayReportType Type>
    void SaveReportWithUser(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto user_id = rp.PopRaw<u128>();
        const auto process_id = rp.PopRaw<u64>();

        const auto data1 = ctx.ReadBufferA(0);
        const auto data2 = ctx.ReadBufferX(0);

        LOG_DEBUG(Service_PREPO,
                  "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, "
                  "data1_size={:016X}, data2_size={:016X}",
                  Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());

        const auto& reporter{system.GetReporter()};
        reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
                                process_id, user_id);

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void RequestImmediateTransmission(HLERequestContext& ctx) {
        LOG_WARNING(Service_PREPO, "(STUBBED) called");

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void GetTransmissionStatus(HLERequestContext& ctx) {
        LOG_WARNING(Service_PREPO, "(STUBBED) called");

        constexpr s32 status = 0;

        IPC::ResponseBuilder rb{ctx, 3};
        rb.Push(ResultSuccess);
        rb.Push(status);
    }

    void GetSystemSessionId(HLERequestContext& ctx) {
        LOG_WARNING(Service_PREPO, "(STUBBED) called");

        constexpr u64 system_session_id = 0;
        IPC::ResponseBuilder rb{ctx, 4};
        rb.Push(ResultSuccess);
        rb.Push(system_session_id);
    }

    void SaveSystemReport(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto title_id = rp.PopRaw<u64>();

        const auto data1 = ctx.ReadBufferA(0);
        const auto data2 = ctx.ReadBufferX(0);

        LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
                  title_id, data1.size(), data2.size());

        const auto& reporter{system.GetReporter()};
        reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2});

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }

    void SaveSystemReportWithUser(HLERequestContext& ctx) {
        IPC::RequestParser rp{ctx};
        const auto user_id = rp.PopRaw<u128>();
        const auto title_id = rp.PopRaw<u64>();

        const auto data1 = ctx.ReadBufferA(0);
        const auto data2 = ctx.ReadBufferX(0);

        LOG_DEBUG(Service_PREPO,
                  "called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, "
                  "data2_size={:016X}",
                  user_id[1], user_id[0], title_id, data1.size(), data2.size());

        const auto& reporter{system.GetReporter()};
        reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2},
                                std::nullopt, user_id);

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(ResultSuccess);
    }
};

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("prepo:a",
                                         std::make_shared<PlayReport>("prepo:a", system));
    server_manager->RegisterNamedService("prepo:a2",
                                         std::make_shared<PlayReport>("prepo:a2", system));
    server_manager->RegisterNamedService("prepo:m",
                                         std::make_shared<PlayReport>("prepo:m", system));
    server_manager->RegisterNamedService("prepo:s",
                                         std::make_shared<PlayReport>("prepo:s", system));
    server_manager->RegisterNamedService("prepo:u",
                                         std::make_shared<PlayReport>("prepo:u", system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PlayReport


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::PlayReport {

void LoopProcess(Core::System& system);

} // namespace Service::PlayReport


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/bit_field.h"
#include "common/common_types.h"

namespace Service::PSC {

using OverlayNotification = std::array<u64, 0x10>;
static_assert(sizeof(OverlayNotification) == 0x80, "OverlayNotification has incorrect size");

union MessageFlags {
    u64 raw;
    BitField<0, 8, u64> message_type;
    BitField<8, 8, u64> queue_type;
};
static_assert(sizeof(MessageFlags) == 0x8, "MessageFlags has incorrect size");

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/psc/ovln/receiver.h"

namespace Service::PSC {

IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
    // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "AddSource"},
            {1, nullptr, "RemoveSource"},
            {2, nullptr, "GetReceiveEventHandle"},
            {3, nullptr, "Receive"},
            {4, nullptr, "ReceiveWithTick"},
        };
    // clang-format on

    RegisterHandlers(functions);
}

IReceiver::~IReceiver() = default;

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Service::PSC {

class IReceiver final : public ServiceFramework<IReceiver> {
public:
    explicit IReceiver(Core::System& system_);
    ~IReceiver() override;
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/psc/ovln/receiver.h"
#include "core/hle/service/psc/ovln/receiver_service.h"

namespace Service::PSC {

IReceiverService::IReceiverService(Core::System& system_) : ServiceFramework{system_, "ovln:rcv"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IReceiverService::OpenReceiver>, "OpenReceiver"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IReceiverService::~IReceiverService() = default;

Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
    LOG_DEBUG(Service_PSC, "called");
    *out_receiver = std::make_shared<IReceiver>(system);
    R_SUCCEED();
}

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::PSC {

class IReceiver;

class IReceiverService final : public ServiceFramework<IReceiverService> {
public:
    explicit IReceiverService(Core::System& system_);
    ~IReceiverService() override;

private:
    Result OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver);
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/psc/ovln/sender.h"

namespace Service::PSC {

ISender::ISender(Core::System& system_) : ServiceFramework{system_, "ISender"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&ISender::Send>, "Send"},
        {1, nullptr, "GetUnreceivedMessageCount"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

ISender::~ISender() = default;

Result ISender::Send(const OverlayNotification& notification, MessageFlags flags) {
    std::string data;
    for (const auto m : notification) {
        data += fmt::format("{:016X} ", m);
    }

    LOG_WARNING(Service_PSC, "(STUBBED) called, flags={} notification={}", flags.raw, data);
    R_SUCCEED();
}

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/psc/ovln/ovln_types.h"
#include "core/hle/service/service.h"

namespace Service::PSC {

class ISender final : public ServiceFramework<ISender> {
public:
    explicit ISender(Core::System& system_);
    ~ISender() override;

private:
    Result Send(const OverlayNotification& notification, MessageFlags flags);
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/psc/ovln/sender.h"
#include "core/hle/service/psc/ovln/sender_service.h"

namespace Service::PSC {

ISenderService::ISenderService(Core::System& system_) : ServiceFramework{system_, "ovln:snd"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&ISenderService::OpenSender>, "OpenSender"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

ISenderService::~ISenderService() = default;

Result ISenderService::OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
                                  std::array<u64, 2> data) {
    LOG_WARNING(Service_PSC, "(STUBBED) called, sender_id={}, data={:016X} {:016X}", sender_id,
                data[0], data[1]);
    *out_sender = std::make_shared<ISender>(system);
    R_SUCCEED();
}

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::PSC {

class ISender;

class ISenderService final : public ServiceFramework<ISenderService> {
public:
    explicit ISenderService(Core::System& system_);
    ~ISenderService() override;

private:
    Result OpenSender(Out<SharedPointer<ISender>> out_sender, u32 sender_id,
                      std::array<u64, 2> data);
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/psc/pm_control.h"

namespace Service::PSC {

IPmControl::IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "Initialize"},
        {1, nullptr, "DispatchRequest"},
        {2, nullptr, "GetResult"},
        {3, nullptr, "GetState"},
        {4, nullptr, "Cancel"},
        {5, nullptr, "PrintModuleInformation"},
        {6, nullptr, "GetModuleInformation"},
        {10, nullptr, "AcquireStateLock"},
        {11, nullptr, "HasStateLock"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IPmControl::~IPmControl() = default;

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Service::PSC {

class IPmControl final : public ServiceFramework<IPmControl> {
public:
    explicit IPmControl(Core::System& system_);
    ~IPmControl() override;
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/psc/pm_module.h"

namespace Service::PSC {

IPmModule::IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
    // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "Initialize"},
            {1, nullptr, "GetRequest"},
            {2, nullptr, "Acknowledge"},
            {3, nullptr, "Finalize"},
            {4, nullptr, "AcknowledgeEx"},
        };
    // clang-format on

    RegisterHandlers(functions);
}

IPmModule::~IPmModule() = default;

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/service.h"

namespace Service::PSC {

class IPmModule final : public ServiceFramework<IPmModule> {
public:
    explicit IPmModule(Core::System& system_);
    ~IPmModule() override;
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/psc/pm_module.h"
#include "core/hle/service/psc/pm_service.h"

namespace Service::PSC {

IPmService::IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IPmService::GetPmModule>, "GetPmModule"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IPmService::~IPmService() = default;

Result IPmService::GetPmModule(Out<SharedPointer<IPmModule>> out_module) {
    LOG_DEBUG(Service_PSC, "called");
    *out_module = std::make_shared<IPmModule>(system);
    R_SUCCEED();
}

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::PSC {

class IPmModule;

class IPmService final : public ServiceFramework<IPmService> {
public:
    explicit IPmService(Core::System& system_);
    ~IPmService() override;

private:
    Result GetPmModule(Out<SharedPointer<IPmModule>> out_module);
};

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/hle/service/psc/ovln/receiver_service.h"
#include "core/hle/service/psc/ovln/sender_service.h"
#include "core/hle/service/psc/pm_control.h"
#include "core/hle/service/psc/pm_service.h"
#include "core/hle/service/psc/psc.h"
#include "core/hle/service/psc/time/manager.h"
#include "core/hle/service/psc/time/power_state_service.h"
#include "core/hle/service/psc/time/service_manager.h"
#include "core/hle/service/psc/time/static.h"
#include "core/hle/service/service.h"

namespace Service::PSC {

void LoopProcess(Core::System& system) {
    auto server_manager = std::make_unique<ServerManager>(system);

    server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
    server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
    server_manager->RegisterNamedService("ovln:rcv", std::make_shared<IReceiverService>(system));
    server_manager->RegisterNamedService("ovln:snd", std::make_shared<ISenderService>(system));

    auto time = std::make_shared<Time::TimeManager>(system);

    server_manager->RegisterNamedService(
        "time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get()));
    server_manager->RegisterNamedService(
        "time:su", std::make_shared<Time::StaticService>(
                       system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su"));
    server_manager->RegisterNamedService("time:al",
                                         std::make_shared<Time::IAlarmService>(system, time));

    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::PSC


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

namespace Core {
class System;
}

namespace Service::PSC {

void LoopProcess(Core::System& system);

} // namespace Service::PSC