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

#pragma once

#include "audio_core/opus/decoder.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::Audio {

class IHardwareOpusDecoder final : public ServiceFramework<IHardwareOpusDecoder> {
public:
    explicit IHardwareOpusDecoder(Core::System& system_,
                                  AudioCore::OpusDecoder::HardwareOpus& hardware_opus);
    ~IHardwareOpusDecoder() override;

    Result Initialize(const AudioCore::OpusDecoder::OpusParametersEx& params,
                      Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
    Result Initialize(const AudioCore::OpusDecoder::OpusMultiStreamParametersEx& params,
                      Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);

private:
    Result DecodeInterleavedOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
                                Out<u32> out_data_size, Out<u32> out_sample_count,
                                InBuffer<BufferAttr_HipcMapAlias> opus_data);
    Result SetContext(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
    Result DecodeInterleavedForMultiStreamOld(OutBuffer<BufferAttr_HipcMapAlias> out_pcm_data,
                                              Out<u32> out_data_size, Out<u32> out_sample_count,
                                              InBuffer<BufferAttr_HipcMapAlias> opus_data);
    Result SetContextForMultiStream(InBuffer<BufferAttr_HipcMapAlias> decoder_context);
    Result DecodeInterleavedWithPerfOld(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias> opus_data);
    Result DecodeInterleavedForMultiStreamWithPerfOld(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias> opus_data);
    Result DecodeInterleavedWithPerfAndResetOld(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
    Result DecodeInterleavedForMultiStreamWithPerfAndResetOld(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias> opus_data, bool reset);
    Result DecodeInterleaved(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
        bool reset);
    Result DecodeInterleavedForMultiStream(
        OutBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> out_pcm_data,
        Out<u32> out_data_size, Out<u32> out_sample_count, Out<u64> out_time_taken,
        InBuffer<BufferAttr_HipcMapAlias | BufferAttr_HipcMapTransferAllowsNonSecure> opus_data,
        bool reset);

    std::unique_ptr<AudioCore::OpusDecoder::OpusDecoder> impl;
    Common::ScratchBuffer<u8> output_data;
};

} // namespace Service::Audio


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

#include "core/hle/service/audio/hardware_opus_decoder.h"
#include "core/hle/service/audio/hardware_opus_decoder_manager.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::Audio {

using namespace AudioCore::OpusDecoder;

IHardwareOpusDecoderManager::IHardwareOpusDecoderManager(Core::System& system_)
    : ServiceFramework{system_, "hwopus"}, system{system_}, impl{system} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoder>, "OpenHardwareOpusDecoder"},
        {1, D<&IHardwareOpusDecoderManager::GetWorkBufferSize>, "GetWorkBufferSize"},
        {2, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream>, "OpenOpusDecoderForMultiStream"},
        {3, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream>, "GetWorkBufferSizeForMultiStream"},
        {4, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx>, "OpenHardwareOpusDecoderEx"},
        {5, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeEx>, "GetWorkBufferSizeEx"},
        {6, D<&IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx>, "OpenHardwareOpusDecoderForMultiStreamEx"},
        {7, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx>, "GetWorkBufferSizeForMultiStreamEx"},
        {8, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeExEx>, "GetWorkBufferSizeExEx"},
        {9, D<&IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx>, "GetWorkBufferSizeForMultiStreamExEx"},
    };
    // clang-format on
    RegisterHandlers(functions);
}

IHardwareOpusDecoderManager::~IHardwareOpusDecoderManager() = default;

Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoder(
    Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParameters params, u32 tmem_size,
    InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
    LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
              params.sample_rate, params.channel_count, tmem_size);

    auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
    OpusParametersEx ex{
        .sample_rate = params.sample_rate,
        .channel_count = params.channel_count,
        .use_large_frame_size = false,
    };
    R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));

    *out_decoder = decoder;
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSize(Out<u32> out_size, OpusParameters params) {
    R_TRY(impl.GetWorkBufferSize(params, *out_size));
    LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} -- returned size {:#x}",
              params.sample_rate, params.channel_count, *out_size);
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStream(
    Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
    InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
    InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
    LOG_DEBUG(Service_Audio,
              "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
              "transfer_memory_size {:#x}",
              params->sample_rate, params->channel_count, params->total_stream_count,
              params->stereo_stream_count, tmem_size);

    auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};

    OpusMultiStreamParametersEx ex{
        .sample_rate = params->sample_rate,
        .channel_count = params->channel_count,
        .total_stream_count = params->total_stream_count,
        .stereo_stream_count = params->stereo_stream_count,
        .use_large_frame_size = false,
        .mappings{},
    };
    std::memcpy(ex.mappings.data(), params->mappings.data(), sizeof(params->mappings));
    R_TRY(decoder->Initialize(ex, tmem_handle.Get(), tmem_size));

    *out_decoder = decoder;
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStream(
    Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params) {
    R_TRY(impl.GetWorkBufferSizeForMultiStream(*params, *out_size));
    LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderEx(
    Out<SharedPointer<IHardwareOpusDecoder>> out_decoder, OpusParametersEx params, u32 tmem_size,
    InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
    LOG_DEBUG(Service_Audio, "sample_rate {} channel_count {} transfer_memory_size {:#x}",
              params.sample_rate, params.channel_count, tmem_size);

    auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};
    R_TRY(decoder->Initialize(params, tmem_handle.Get(), tmem_size));

    *out_decoder = decoder;
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSizeEx(Out<u32> out_size,
                                                        OpusParametersEx params) {
    R_TRY(impl.GetWorkBufferSizeEx(params, *out_size));
    LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::OpenHardwareOpusDecoderForMultiStreamEx(
    Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
    InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
    InCopyHandle<Kernel::KTransferMemory> tmem_handle) {
    LOG_DEBUG(Service_Audio,
              "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
              "use_large_frame_size {}"
              "transfer_memory_size {:#x}",
              params->sample_rate, params->channel_count, params->total_stream_count,
              params->stereo_stream_count, params->use_large_frame_size, tmem_size);

    auto decoder{std::make_shared<IHardwareOpusDecoder>(system, impl.GetHardwareOpus())};

    R_TRY(decoder->Initialize(*params, tmem_handle.Get(), tmem_size));

    *out_decoder = decoder;
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
    Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
    R_TRY(impl.GetWorkBufferSizeForMultiStreamEx(*params, *out_size));
    LOG_DEBUG(Service_Audio,
              "sample_rate {} channel_count {} total_stream_count {} stereo_stream_count {} "
              "use_large_frame_size {} -- returned size {:#x}",
              params->sample_rate, params->channel_count, params->total_stream_count,
              params->stereo_stream_count, params->use_large_frame_size, *out_size);
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSizeExEx(Out<u32> out_size,
                                                          OpusParametersEx params) {
    R_TRY(impl.GetWorkBufferSizeExEx(params, *out_size));
    LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
    R_SUCCEED();
}

Result IHardwareOpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
    Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params) {
    R_TRY(impl.GetWorkBufferSizeForMultiStreamExEx(*params, *out_size));
    LOG_DEBUG(Service_Audio, "size {:#x}", *out_size);
    R_SUCCEED();
}

} // namespace Service::Audio

repo_name: litucks/torzu

license: mit


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

#pragma once

#include "audio_core/opus/decoder_manager.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Service::Audio {

class IHardwareOpusDecoder;

using AudioCore::OpusDecoder::OpusMultiStreamParameters;
using AudioCore::OpusDecoder::OpusMultiStreamParametersEx;
using AudioCore::OpusDecoder::OpusParameters;
using AudioCore::OpusDecoder::OpusParametersEx;

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

private:
    Result OpenHardwareOpusDecoder(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
                                   OpusParameters params, u32 tmem_size,
                                   InCopyHandle<Kernel::KTransferMemory> tmem_handle);
    Result GetWorkBufferSize(Out<u32> out_size, OpusParameters params);
    Result OpenHardwareOpusDecoderForMultiStream(
        Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
        InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params, u32 tmem_size,
        InCopyHandle<Kernel::KTransferMemory> tmem_handle);
    Result GetWorkBufferSizeForMultiStream(
        Out<u32> out_size, InLargeData<OpusMultiStreamParameters, BufferAttr_HipcPointer> params);
    Result OpenHardwareOpusDecoderEx(Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
                                     OpusParametersEx params, u32 tmem_size,
                                     InCopyHandle<Kernel::KTransferMemory> tmem_handle);
    Result GetWorkBufferSizeEx(Out<u32> out_size, OpusParametersEx params);
    Result OpenHardwareOpusDecoderForMultiStreamEx(
        Out<SharedPointer<IHardwareOpusDecoder>> out_decoder,
        InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params, u32 tmem_size,
        InCopyHandle<Kernel::KTransferMemory> tmem_handle);
    Result GetWorkBufferSizeForMultiStreamEx(
        Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);
    Result GetWorkBufferSizeExEx(Out<u32> out_size, OpusParametersEx params);
    Result GetWorkBufferSizeForMultiStreamExEx(
        Out<u32> out_size, InLargeData<OpusMultiStreamParametersEx, BufferAttr_HipcPointer> params);

    Core::System& system;
    AudioCore::OpusDecoder::OpusDecoderManager impl;
};

} // namespace Service::Audio


code:
// SPDX-FileCopyrightText: Copyright 2019 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/kernel/k_event.h"
#include "core/hle/service/bcat/backend/backend.h"

namespace Service::BCAT {

ProgressServiceBackend::ProgressServiceBackend(Core::System& system, std::string_view event_name)
    : service_context{system, "ProgressServiceBackend"} {
    update_event = service_context.CreateEvent("ProgressServiceBackend:UpdateEvent:" +
                                               std::string(event_name));
}

ProgressServiceBackend::~ProgressServiceBackend() {
    service_context.CloseEvent(update_event);
}

Kernel::KReadableEvent& ProgressServiceBackend::GetEvent() {
    return update_event->GetReadableEvent();
}

DeliveryCacheProgressImpl& ProgressServiceBackend::GetImpl() {
    return impl;
}

void ProgressServiceBackend::SetTotalSize(u64 size) {
    impl.total_bytes = size;
    SignalUpdate();
}

void ProgressServiceBackend::StartConnecting() {
    impl.status = DeliveryCacheProgressStatus::Connecting;
    SignalUpdate();
}

void ProgressServiceBackend::StartProcessingDataList() {
    impl.status = DeliveryCacheProgressStatus::ProcessingDataList;
    SignalUpdate();
}

void ProgressServiceBackend::StartDownloadingFile(std::string_view dir_name,
                                                  std::string_view file_name, u64 file_size) {
    impl.status = DeliveryCacheProgressStatus::Downloading;
    impl.current_downloaded_bytes = 0;
    impl.current_total_bytes = file_size;
    std::memcpy(impl.current_directory.data(), dir_name.data(),
                std::min<u64>(dir_name.size(), 0x31ull));
    std::memcpy(impl.current_file.data(), file_name.data(),
                std::min<u64>(file_name.size(), 0x31ull));
    SignalUpdate();
}

void ProgressServiceBackend::UpdateFileProgress(u64 downloaded) {
    impl.current_downloaded_bytes = downloaded;
    SignalUpdate();
}

void ProgressServiceBackend::FinishDownloadingFile() {
    impl.total_downloaded_bytes += impl.current_total_bytes;
    SignalUpdate();
}

void ProgressServiceBackend::CommitDirectory(std::string_view dir_name) {
    impl.status = DeliveryCacheProgressStatus::Committing;
    impl.current_file.fill(0);
    impl.current_downloaded_bytes = 0;
    impl.current_total_bytes = 0;
    std::memcpy(impl.current_directory.data(), dir_name.data(),
                std::min<u64>(dir_name.size(), 0x31ull));
    SignalUpdate();
}

void ProgressServiceBackend::FinishDownload(Result result) {
    impl.total_downloaded_bytes = impl.total_bytes;
    impl.status = DeliveryCacheProgressStatus::Done;
    impl.result = result;
    SignalUpdate();
}

void ProgressServiceBackend::SignalUpdate() {
    update_event->Signal();
}

BcatBackend::BcatBackend(DirectoryGetter getter) : dir_getter(std::move(getter)) {}

BcatBackend::~BcatBackend() = default;

NullBcatBackend::NullBcatBackend(DirectoryGetter getter) : BcatBackend(std::move(getter)) {}

NullBcatBackend::~NullBcatBackend() = default;

bool NullBcatBackend::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
              title.build_id);

    progress.FinishDownload(ResultSuccess);
    return true;
}

bool NullBcatBackend::SynchronizeDirectory(TitleIDVersion title, std::string name,
                                           ProgressServiceBackend& progress) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}, name={}", title.title_id,
              title.build_id, name);

    progress.FinishDownload(ResultSuccess);
    return true;
}

bool NullBcatBackend::Clear(u64 title_id) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", title_id);

    return true;
}

void NullBcatBackend::SetPassphrase(u64 title_id, const Passphrase& passphrase) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, passphrase={}", title_id,
              Common::HexToString(passphrase));
}

std::optional<std::vector<u8>> NullBcatBackend::GetLaunchParameter(TitleIDVersion title) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}, build_id={:016X}", title.title_id,
              title.build_id);
    return std::nullopt;
}

} // namespace Service::BCAT


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

#pragma once

#include <functional>
#include <optional>
#include <string>

#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"
#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/kernel_helpers.h"

namespace Core {
class System;
}

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

namespace Service::BCAT {

// A class to manage the signalling to the game about BCAT download progress.
// Some of this class is implemented in module.cpp to avoid exposing the implementation structure.
class ProgressServiceBackend {
    friend class IBcatService;

public:
    ~ProgressServiceBackend();

    // Sets the number of bytes total in the entire download.
    void SetTotalSize(u64 size);

    // Notifies the application that the backend has started connecting to the server.
    void StartConnecting();
    // Notifies the application that the backend has begun accumulating and processing metadata.
    void StartProcessingDataList();

    // Notifies the application that a file is starting to be downloaded.
    void StartDownloadingFile(std::string_view dir_name, std::string_view file_name, u64 file_size);
    // Updates the progress of the current file to the size passed.
    void UpdateFileProgress(u64 downloaded);
    // Notifies the application that the current file has completed download.
    void FinishDownloadingFile();

    // Notifies the application that all files in this directory have completed and are being
    // finalized.
    void CommitDirectory(std::string_view dir_name);

    // Notifies the application that the operation completed with result code result.
    void FinishDownload(Result result);

private:
    explicit ProgressServiceBackend(Core::System& system, std::string_view event_name);

    Kernel::KReadableEvent& GetEvent();
    DeliveryCacheProgressImpl& GetImpl();

    void SignalUpdate();

    KernelHelpers::ServiceContext service_context;

    DeliveryCacheProgressImpl impl{};
    Kernel::KEvent* update_event;
};

// A class representing an abstract backend for BCAT functionality.
class BcatBackend {
public:
    explicit BcatBackend(DirectoryGetter getter);
    virtual ~BcatBackend();

    // Called when the backend is needed to synchronize the data for the game with title ID and
    // version in title. A ProgressServiceBackend object is provided to alert the application of
    // status.
    virtual bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) = 0;
    // Very similar to Synchronize, but only for the directory provided. Backends should not alter
    // the data for any other directories.
    virtual bool SynchronizeDirectory(TitleIDVersion title, std::string name,
                                      ProgressServiceBackend& progress) = 0;

    // Removes all cached data associated with title id provided.
    virtual bool Clear(u64 title_id) = 0;

    // Sets the BCAT Passphrase to be used with the associated title ID.
    virtual void SetPassphrase(u64 title_id, const Passphrase& passphrase) = 0;

    // Gets the launch parameter used by AM associated with the title ID and version provided.
    virtual std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) = 0;

protected:
    DirectoryGetter dir_getter;
};

// A backend of BCAT that provides no operation.
class NullBcatBackend : public BcatBackend {
public:
    explicit NullBcatBackend(DirectoryGetter getter);
    ~NullBcatBackend() override;

    bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
    bool SynchronizeDirectory(TitleIDVersion title, std::string name,
                              ProgressServiceBackend& progress) override;

    bool Clear(u64 title_id) override;

    void SetPassphrase(u64 title_id, const Passphrase& passphrase) override;

    std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
};

std::unique_ptr<BcatBackend> CreateBackendFromSettings(Core::System& system,
                                                       DirectoryGetter getter);

} // namespace Service::BCAT


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

#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/bcat/news/service_creator.h"
#include "core/hle/service/bcat/service_creator.h"
#include "core/hle/service/server_manager.h"

namespace Service::BCAT {

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

    server_manager->RegisterNamedService("bcat:a",
                                         std::make_shared<IServiceCreator>(system, "bcat:a"));
    server_manager->RegisterNamedService("bcat:m",
                                         std::make_shared<IServiceCreator>(system, "bcat:m"));
    server_manager->RegisterNamedService("bcat:u",
                                         std::make_shared<IServiceCreator>(system, "bcat:u"));
    server_manager->RegisterNamedService("bcat:s",
                                         std::make_shared<IServiceCreator>(system, "bcat:s"));

    server_manager->RegisterNamedService(
        "news:a", std::make_shared<News::IServiceCreator>(system, 0xffffffff, "news:a"));
    server_manager->RegisterNamedService(
        "news:p", std::make_shared<News::IServiceCreator>(system, 0x1, "news:p"));
    server_manager->RegisterNamedService(
        "news:c", std::make_shared<News::IServiceCreator>(system, 0x2, "news:c"));
    server_manager->RegisterNamedService(
        "news:v", std::make_shared<News::IServiceCreator>(system, 0x4, "news:v"));
    server_manager->RegisterNamedService(
        "news:m", std::make_shared<News::IServiceCreator>(system, 0xd, "news:m"));

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

} // namespace Service::BCAT


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::BCAT {

void LoopProcess(Core::System& system);

} // namespace Service::BCAT


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

#pragma once

#include "core/hle/result.h"

namespace Service::BCAT {

constexpr Result ResultInvalidArgument{ErrorModule::BCAT, 1};
constexpr Result ResultFailedOpenEntity{ErrorModule::BCAT, 2};
constexpr Result ResultEntityAlreadyOpen{ErrorModule::BCAT, 6};
constexpr Result ResultNoOpenEntry{ErrorModule::BCAT, 7};

} // namespace Service::BCAT


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

#include "common/hex_util.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/errors.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/bcat_service.h"
#include "core/hle/service/bcat/bcat_util.h"
#include "core/hle/service/bcat/delivery_cache_progress_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BCAT {

static u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
    u64 out{};
    std::memcpy(&out, id.data(), sizeof(u64));
    return out;
}

IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
    : ServiceFramework{system_, "IBcatService"}, backend{backend_},
      progress{{
          ProgressServiceBackend{system_, "Normal"},
          ProgressServiceBackend{system_, "Directory"},
      }} {
    // clang-format off
        static const FunctionInfo functions[] = {
            {10100, D<&IBcatService::RequestSyncDeliveryCache>, "RequestSyncDeliveryCache"},
            {10101, D<&IBcatService::RequestSyncDeliveryCacheWithDirectoryName>, "RequestSyncDeliveryCacheWithDirectoryName"},
            {10200, nullptr, "CancelSyncDeliveryCacheRequest"},
            {20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
            {20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
            {20300, nullptr, "GetDeliveryCacheStorageUpdateNotifier"},
            {20301, nullptr, "RequestSuspendDeliveryTask"},
            {20400, nullptr, "RegisterSystemApplicationDeliveryTask"},
            {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
            {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
            {30100, D<&IBcatService::SetPassphrase>, "SetPassphrase"},
            {30101, nullptr, "Unknown30101"},
            {30102, nullptr, "Unknown30102"},
            {30200, nullptr, "RegisterBackgroundDeliveryTask"},
            {30201, nullptr, "UnregisterBackgroundDeliveryTask"},
            {30202, nullptr, "BlockDeliveryTask"},
            {30203, nullptr, "UnblockDeliveryTask"},
            {30210, nullptr, "SetDeliveryTaskTimer"},
            {30300, D<&IBcatService::RegisterSystemApplicationDeliveryTasks>, "RegisterSystemApplicationDeliveryTasks"},
            {90100, nullptr, "EnumerateBackgroundDeliveryTask"},
            {90101, nullptr, "Unknown90101"},
            {90200, nullptr, "GetDeliveryList"},
            {90201, D<&IBcatService::ClearDeliveryCacheStorage>, "ClearDeliveryCacheStorage"},
            {90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
            {90300, nullptr, "GetPushNotificationLog"},
            {90301, nullptr, "Unknown90301"},
        };
    // clang-format on
    RegisterHandlers(functions);
}

IBcatService::~IBcatService() = default;

Result IBcatService::RequestSyncDeliveryCache(
    OutInterface<IDeliveryCacheProgressService> out_interface) {
    LOG_DEBUG(Service_BCAT, "called");

    auto& progress_backend{GetProgressBackend(SyncType::Normal)};
    backend.Synchronize({system.GetApplicationProcessProgramID(),
                         GetCurrentBuildID(system.GetApplicationProcessBuildID())},
                        GetProgressBackend(SyncType::Normal));

    *out_interface = std::make_shared<IDeliveryCacheProgressService>(
        system, progress_backend.GetEvent(), progress_backend.GetImpl());
    R_SUCCEED();
}

Result IBcatService::RequestSyncDeliveryCacheWithDirectoryName(
    const DirectoryName& name_raw, OutInterface<IDeliveryCacheProgressService> out_interface) {
    const auto name = Common::StringFromFixedZeroTerminatedBuffer(name_raw.data(), name_raw.size());

    LOG_DEBUG(Service_BCAT, "called, name={}", name);

    auto& progress_backend{GetProgressBackend(SyncType::Directory)};
    backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(),
                                  GetCurrentBuildID(system.GetApplicationProcessBuildID())},
                                 name, progress_backend);

    *out_interface = std::make_shared<IDeliveryCacheProgressService>(
        system, progress_backend.GetEvent(), progress_backend.GetImpl());
    R_SUCCEED();
}

Result IBcatService::SetPassphrase(u64 application_id,
                                   InBuffer<BufferAttr_HipcPointer> passphrase_buffer) {
    LOG_DEBUG(Service_BCAT, "called, application_id={:016X}, passphrase={}", application_id,
              Common::HexToString(passphrase_buffer));

    R_UNLESS(application_id != 0, ResultInvalidArgument);
    R_UNLESS(passphrase_buffer.size() <= 0x40, ResultInvalidArgument);

    Passphrase passphrase{};
    std::memcpy(passphrase.data(), passphrase_buffer.data(),
                std::min(passphrase.size(), passphrase_buffer.size()));

    backend.SetPassphrase(application_id, passphrase);
    R_SUCCEED();
}

Result IBcatService::RegisterSystemApplicationDeliveryTasks() {
    LOG_WARNING(Service_BCAT, "(STUBBED) called");
    R_SUCCEED();
}

Result IBcatService::ClearDeliveryCacheStorage(u64 application_id) {
    LOG_DEBUG(Service_BCAT, "called, title_id={:016X}", application_id);

    R_UNLESS(application_id != 0, ResultInvalidArgument);
    R_UNLESS(backend.Clear(application_id), FileSys::ResultPermissionDenied);
    R_SUCCEED();
}

ProgressServiceBackend& IBcatService::GetProgressBackend(SyncType type) {
    return progress.at(static_cast<size_t>(type));
}

const ProgressServiceBackend& IBcatService::GetProgressBackend(SyncType type) const {
    return progress.at(static_cast<size_t>(type));
}

} // namespace Service::BCAT


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

#pragma once

#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::BCAT {
class BcatBackend;
class IDeliveryCacheStorageService;
class IDeliveryCacheProgressService;

class IBcatService final : public ServiceFramework<IBcatService> {
public:
    explicit IBcatService(Core::System& system_, BcatBackend& backend_);
    ~IBcatService() override;

private:
    Result RequestSyncDeliveryCache(OutInterface<IDeliveryCacheProgressService> out_interface);

    Result RequestSyncDeliveryCacheWithDirectoryName(
        const DirectoryName& name, OutInterface<IDeliveryCacheProgressService> out_interface);

    Result SetPassphrase(u64 application_id, InBuffer<BufferAttr_HipcPointer> passphrase_buffer);

    Result RegisterSystemApplicationDeliveryTasks();

    Result ClearDeliveryCacheStorage(u64 application_id);

private:
    ProgressServiceBackend& GetProgressBackend(SyncType type);
    const ProgressServiceBackend& GetProgressBackend(SyncType type) const;

    BcatBackend& backend;
    std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
};

} // namespace Service::BCAT


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

#pragma once

#include <array>
#include <functional>

#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/result.h"

namespace Service::BCAT {

using DirectoryName = std::array<char, 0x20>;
using FileName = std::array<char, 0x20>;
using BcatDigest = std::array<u8, 0x10>;
using Passphrase = std::array<u8, 0x20>;
using DirectoryGetter = std::function<FileSys::VirtualDir(u64)>;

enum class SyncType {
    Normal,
    Directory,
    Count,
};

enum class DeliveryCacheProgressStatus : s32 {
    None = 0x0,
    Queued = 0x1,
    Connecting = 0x2,
    ProcessingDataList = 0x3,
    Downloading = 0x4,
    Committing = 0x5,
    Done = 0x9,
};

struct DeliveryCacheDirectoryEntry {
    FileName name;
    u64 size;
    BcatDigest digest;
};

struct TitleIDVersion {
    u64 title_id;
    u64 build_id;
};

struct DeliveryCacheProgressImpl {
    DeliveryCacheProgressStatus status;
    Result result;
    DirectoryName current_directory;
    FileName current_file;
    s64 current_downloaded_bytes; ///< Bytes downloaded on current file.
    s64 current_total_bytes;      ///< Bytes total on current file.
    s64 total_downloaded_bytes;   ///< Bytes downloaded on overall download.
    s64 total_bytes;              ///< Bytes total on overall download.
    INSERT_PADDING_BYTES_NOINIT(
        0x198); ///< Appears to be unused in official code, possibly reserved for future use.
};
static_assert(sizeof(DeliveryCacheProgressImpl) == 0x200,
              "DeliveryCacheProgressImpl has incorrect size.");
static_assert(std::is_trivial_v<DeliveryCacheProgressImpl>,
              "DeliveryCacheProgressImpl type must be trivially copyable.");

} // namespace Service::BCAT


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

#pragma once

#include <array>
#include <cctype>
#include <mbedtls/md5.h>

#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/bcat_types.h"

namespace Service::BCAT {

// For a name to be valid it must be non-empty, must have a null terminating character as the final
// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if
// file.
constexpr Result VerifyNameValidInternal(std::array<char, 0x20> name, char match_char) {
    const auto null_chars = std::count(name.begin(), name.end(), 0);
    const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) {
        return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0';
    });
    if (null_chars == 0x20 || null_chars == 0 || bad_chars != 0 || name[0x1F] != '\0') {
        LOG_ERROR(Service_BCAT, "Name passed was invalid!");
        return ResultInvalidArgument;
    }

    return ResultSuccess;
}

constexpr Result VerifyNameValidDir(DirectoryName name) {
    return VerifyNameValidInternal(name, '-');
}

constexpr Result VerifyNameValidFile(FileName name) {
    return VerifyNameValidInternal(name, '.');
}

} // namespace Service::BCAT


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

#include "common/string_util.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/bcat_util.h"
#include "core/hle/service/bcat/delivery_cache_directory_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BCAT {

// The digest is only used to determine if a file is unique compared to others of the same name.
// Since the algorithm isn't ever checked in game, MD5 is safe.
static BcatDigest DigestFile(const FileSys::VirtualFile& file) {
    BcatDigest out{};
    const auto bytes = file->ReadAllBytes();
    mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
    return out;
}

IDeliveryCacheDirectoryService::IDeliveryCacheDirectoryService(Core::System& system_,
                                                               FileSys::VirtualDir root_)
    : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IDeliveryCacheDirectoryService::Open>, "Open"},
        {1, D<&IDeliveryCacheDirectoryService::Read>, "Read"},
        {2, D<&IDeliveryCacheDirectoryService::GetCount>, "GetCount"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IDeliveryCacheDirectoryService::~IDeliveryCacheDirectoryService() = default;

Result IDeliveryCacheDirectoryService::Open(const DirectoryName& dir_name_raw) {
    const auto dir_name =
        Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());

    LOG_DEBUG(Service_BCAT, "called, dir_name={}", dir_name);

    R_TRY(VerifyNameValidDir(dir_name_raw));
    R_UNLESS(current_dir == nullptr, ResultEntityAlreadyOpen);

    const auto dir = root->GetSubdirectory(dir_name);
    R_UNLESS(dir != nullptr, ResultFailedOpenEntity);

    R_SUCCEED();
}

Result IDeliveryCacheDirectoryService::Read(
    Out<s32> out_count, OutArray<DeliveryCacheDirectoryEntry, BufferAttr_HipcMapAlias> out_buffer) {
    LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", out_buffer.size());

    R_UNLESS(current_dir != nullptr, ResultNoOpenEntry);

    const auto files = current_dir->GetFiles();
    *out_count = static_cast<s32>(std::min(files.size(), out_buffer.size()));
    std::transform(files.begin(), files.begin() + *out_count, out_buffer.begin(),
                   [](const auto& file) {
                       FileName name{};
                       std::memcpy(name.data(), file->GetName().data(),
                                   std::min(file->GetName().size(), name.size()));
                       return DeliveryCacheDirectoryEntry{name, file->GetSize(), DigestFile(file)};
                   });
    R_SUCCEED();
}

Result IDeliveryCacheDirectoryService::GetCount(Out<s32> out_count) {
    LOG_DEBUG(Service_BCAT, "called");

    R_UNLESS(current_dir != nullptr, ResultNoOpenEntry);

    *out_count = static_cast<s32>(current_dir->GetFiles().size());
    R_SUCCEED();
}

} // namespace Service::BCAT


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

#pragma once

#include "core/file_sys/vfs/vfs.h"
#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::BCAT {

class IDeliveryCacheDirectoryService final
    : public ServiceFramework<IDeliveryCacheDirectoryService> {
public:
    explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_);
    ~IDeliveryCacheDirectoryService() override;

private:
    Result Open(const DirectoryName& dir_name_raw);
    Result Read(Out<s32> out_count,
                OutArray<DeliveryCacheDirectoryEntry, BufferAttr_HipcMapAlias> out_buffer);
    Result GetCount(Out<s32> out_count);

    FileSys::VirtualDir root;
    FileSys::VirtualDir current_dir;
};

} // namespace Service::BCAT


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

#include "common/string_util.h"
#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/bcat_util.h"
#include "core/hle/service/bcat/delivery_cache_file_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BCAT {

IDeliveryCacheFileService::IDeliveryCacheFileService(Core::System& system_,
                                                     FileSys::VirtualDir root_)
    : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IDeliveryCacheFileService::Open>, "Open"},
        {1, D<&IDeliveryCacheFileService::Read>, "Read"},
        {2, D<&IDeliveryCacheFileService::GetSize>, "GetSize"},
        {3, D<&IDeliveryCacheFileService::GetDigest>, "GetDigest"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IDeliveryCacheFileService::~IDeliveryCacheFileService() = default;

Result IDeliveryCacheFileService::Open(const DirectoryName& dir_name_raw,
                                       const FileName& file_name_raw) {
    const auto dir_name =
        Common::StringFromFixedZeroTerminatedBuffer(dir_name_raw.data(), dir_name_raw.size());
    const auto file_name =
        Common::StringFromFixedZeroTerminatedBuffer(file_name_raw.data(), file_name_raw.size());

    LOG_DEBUG(Service_BCAT, "called, dir_name={}, file_name={}", dir_name, file_name);

    R_TRY(VerifyNameValidDir(dir_name_raw));
    R_TRY(VerifyNameValidDir(file_name_raw));
    R_UNLESS(current_file == nullptr, ResultEntityAlreadyOpen);

    const auto dir = root->GetSubdirectory(dir_name);
    R_UNLESS(dir != nullptr, ResultFailedOpenEntity);

    current_file = dir->GetFile(file_name);
    R_UNLESS(current_file != nullptr, ResultFailedOpenEntity);

    R_SUCCEED();
}

Result IDeliveryCacheFileService::Read(Out<u64> out_buffer_size, u64 offset,
                                       OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
    LOG_DEBUG(Service_BCAT, "called, offset={:016X}, size={:016X}", offset, out_buffer.size());

    R_UNLESS(current_file != nullptr, ResultNoOpenEntry);

    *out_buffer_size = std::min<u64>(current_file->GetSize() - offset, out_buffer.size());
    const auto buffer = current_file->ReadBytes(*out_buffer_size, offset);
    memcpy(out_buffer.data(), buffer.data(), buffer.size());

    R_SUCCEED();
}

Result IDeliveryCacheFileService::GetSize(Out<u64> out_size) {
    LOG_DEBUG(Service_BCAT, "called");

    R_UNLESS(current_file != nullptr, ResultNoOpenEntry);

    *out_size = current_file->GetSize();
    R_SUCCEED();
}

Result IDeliveryCacheFileService::GetDigest(Out<BcatDigest> out_digest) {
    LOG_DEBUG(Service_BCAT, "called");

    R_UNLESS(current_file != nullptr, ResultNoOpenEntry);

    //*out_digest = DigestFile(current_file);
    R_SUCCEED();
}

} // namespace Service::BCAT


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

#pragma once

#include "core/file_sys/vfs/vfs.h"
#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::BCAT {

class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
public:
    explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_);
    ~IDeliveryCacheFileService() override;

private:
    Result Open(const DirectoryName& dir_name_raw, const FileName& file_name_raw);
    Result Read(Out<u64> out_buffer_size, u64 offset,
                OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
    Result GetSize(Out<u64> out_size);
    Result GetDigest(Out<BcatDigest> out_digest);

    FileSys::VirtualDir root;
    FileSys::VirtualFile current_file;
};

} // namespace Service::BCAT


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

#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/bcat/delivery_cache_progress_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BCAT {

IDeliveryCacheProgressService::IDeliveryCacheProgressService(Core::System& system_,
                                                             Kernel::KReadableEvent& event_,
                                                             const DeliveryCacheProgressImpl& impl_)
    : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{event_}, impl{impl_} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IDeliveryCacheProgressService::GetEvent>, "Get"},
        {1, D<&IDeliveryCacheProgressService::GetImpl>, "Get"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IDeliveryCacheProgressService::~IDeliveryCacheProgressService() = default;

Result IDeliveryCacheProgressService::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_DEBUG(Service_BCAT, "called");

    *out_event = &event;
    R_SUCCEED();
}

Result IDeliveryCacheProgressService::GetImpl(
    OutLargeData<DeliveryCacheProgressImpl, BufferAttr_HipcPointer> out_impl) {
    LOG_DEBUG(Service_BCAT, "called");

    *out_impl = impl;
    R_SUCCEED();
}

} // namespace Service::BCAT


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

#pragma once

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

namespace Core {
class System;
}

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

namespace Service::BCAT {
struct DeliveryCacheProgressImpl;

class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
public:
    explicit IDeliveryCacheProgressService(Core::System& system_, Kernel::KReadableEvent& event_,
                                           const DeliveryCacheProgressImpl& impl_);
    ~IDeliveryCacheProgressService() override;

private:
    Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
    Result GetImpl(OutLargeData<DeliveryCacheProgressImpl, BufferAttr_HipcPointer> out_impl);

    Kernel::KReadableEvent& event;
    const DeliveryCacheProgressImpl& impl;
};

} // namespace Service::BCAT


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

#include "core/hle/service/bcat/bcat_result.h"
#include "core/hle/service/bcat/delivery_cache_directory_service.h"
#include "core/hle/service/bcat/delivery_cache_file_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BCAT {

IDeliveryCacheStorageService::IDeliveryCacheStorageService(Core::System& system_,
                                                           FileSys::VirtualDir root_)
    : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IDeliveryCacheStorageService::CreateFileService>, "CreateFileService"},
        {1, D<&IDeliveryCacheStorageService::CreateDirectoryService>, "CreateDirectoryService"},
        {10, D<&IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory>, "EnumerateDeliveryCacheDirectory"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IDeliveryCacheStorageService::~IDeliveryCacheStorageService() = default;

Result IDeliveryCacheStorageService::CreateFileService(
    OutInterface<IDeliveryCacheFileService> out_interface) {
    LOG_DEBUG(Service_BCAT, "called");

    *out_interface = std::make_shared<IDeliveryCacheFileService>(system, root);
    R_SUCCEED();
}

Result IDeliveryCacheStorageService::CreateDirectoryService(
    OutInterface<IDeliveryCacheDirectoryService> out_interface) {
    LOG_DEBUG(Service_BCAT, "called");

    *out_interface = std::make_shared<IDeliveryCacheDirectoryService>(system, root);
    R_SUCCEED();
}

Result IDeliveryCacheStorageService::EnumerateDeliveryCacheDirectory(
    Out<s32> out_directory_count,
    OutArray<DirectoryName, BufferAttr_HipcMapAlias> out_directories) {
    LOG_DEBUG(Service_BCAT, "called, size={:016X}", out_directories.size());

    *out_directory_count =
        static_cast<s32>(std::min(out_directories.size(), entries.size() - next_read_index));
    memcpy(out_directories.data(), entries.data() + next_read_index,
           *out_directory_count * sizeof(DirectoryName));
    next_read_index += *out_directory_count;
    R_SUCCEED();
}

} // namespace Service::BCAT


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

#pragma once

#include "core/file_sys/vfs/vfs.h"
#include "core/hle/service/bcat/bcat_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"

namespace Core {
class System;
}

namespace Service::BCAT {
class IDeliveryCacheFileService;
class IDeliveryCacheDirectoryService;

class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
public:
    explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_);
    ~IDeliveryCacheStorageService() override;

private:
    Result CreateFileService(OutInterface<IDeliveryCacheFileService> out_interface);
    Result CreateDirectoryService(OutInterface<IDeliveryCacheDirectoryService> out_interface);
    Result EnumerateDeliveryCacheDirectory(
        Out<s32> out_directory_count,
        OutArray<DirectoryName, BufferAttr_HipcMapAlias> out_directories);

    FileSys::VirtualDir root;
    std::vector<DirectoryName> entries;
    std::size_t next_read_index = 0;
};

} // namespace Service::BCAT


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

#include "core/hle/service/bcat/news/newly_arrived_event_holder.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::News {

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

    RegisterHandlers(functions);
    arrived_event = service_context.CreateEvent("INewlyArrivedEventHolder::ArrivedEvent");
}

INewlyArrivedEventHolder::~INewlyArrivedEventHolder() {
    service_context.CloseEvent(arrived_event);
}

Result INewlyArrivedEventHolder::Get(OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_INFO(Service_BCAT, "called");

    *out_event = &arrived_event->GetReadableEvent();
    R_SUCCEED();
}

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

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

namespace Service::News {

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

private:
    Result Get(OutCopyHandle<Kernel::KReadableEvent> out_event);

    Kernel::KEvent* arrived_event;
    KernelHelpers::ServiceContext service_context;
};

} // namespace Service::News


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

#include "core/hle/service/bcat/news/news_data_service.h"

namespace Service::News {

INewsDataService::INewsDataService(Core::System& system_)
    : ServiceFramework{system_, "INewsDataService"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "Open"},
        {1, nullptr, "OpenWithNewsRecordV1"},
        {2, nullptr, "Read"},
        {3, nullptr, "GetSize"},
        {1001, nullptr, "OpenWithNewsRecord"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

INewsDataService::~INewsDataService() = default;

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::News {

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

} // namespace Service::News


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

#include "core/hle/service/bcat/news/news_database_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::News {

INewsDatabaseService::INewsDatabaseService(Core::System& system_)
    : ServiceFramework{system_, "INewsDatabaseService"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "GetListV1"},
        {1, D<&INewsDatabaseService::Count>, "Count"},
        {2, nullptr, "CountWithKey"},
        {3, nullptr, "UpdateIntegerValue"},
        {4, D<&INewsDatabaseService::UpdateIntegerValueWithAddition>, "UpdateIntegerValueWithAddition"},
        {5, nullptr, "UpdateStringValue"},
        {1000, D<&INewsDatabaseService::GetList>, "GetList"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

INewsDatabaseService::~INewsDatabaseService() = default;

Result INewsDatabaseService::Count(Out<s32> out_count,
                                   InBuffer<BufferAttr_HipcPointer> buffer_data) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called, buffer_size={}", buffer_data.size());
    *out_count = 0;
    R_SUCCEED();
}

Result INewsDatabaseService::UpdateIntegerValueWithAddition(
    u32 value, InBuffer<BufferAttr_HipcPointer> buffer_data_1,
    InBuffer<BufferAttr_HipcPointer> buffer_data_2) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called, value={}, buffer_size_1={}, buffer_data_2={}",
                value, buffer_data_1.size(), buffer_data_2.size());
    R_SUCCEED();
}

Result INewsDatabaseService::GetList(Out<s32> out_count, u32 value,
                                     OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data,
                                     InBuffer<BufferAttr_HipcPointer> buffer_data_1,
                                     InBuffer<BufferAttr_HipcPointer> buffer_data_2) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called, value={}, buffer_size_1={}, buffer_data_2={}",
                value, buffer_data_1.size(), buffer_data_2.size());
    *out_count = 0;
    R_SUCCEED();
}

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::News {

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

private:
    Result Count(Out<s32> out_count, InBuffer<BufferAttr_HipcPointer> buffer_data);

    Result UpdateIntegerValueWithAddition(u32 value, InBuffer<BufferAttr_HipcPointer> buffer_data_1,
                                          InBuffer<BufferAttr_HipcPointer> buffer_data_2);

    Result GetList(Out<s32> out_count, u32 value,
                   OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data,
                   InBuffer<BufferAttr_HipcPointer> buffer_data_1,
                   InBuffer<BufferAttr_HipcPointer> buffer_data_2);
};

} // namespace Service::News


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

#include "core/hle/service/bcat/news/news_service.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::News {

INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "INewsService"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {10100, nullptr, "PostLocalNews"},
        {20100, nullptr, "SetPassphrase"},
        {30100, D<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"},
        {30101, nullptr, "GetTopicList"},
        {30110, nullptr, "Unknown30110"},
        {30200, D<&INewsService::IsSystemUpdateRequired>, "IsSystemUpdateRequired"},
        {30201, nullptr, "Unknown30201"},
        {30210, nullptr, "Unknown30210"},
        {30300, nullptr, "RequestImmediateReception"},
        {30400, nullptr, "DecodeArchiveFile"},
        {30500, nullptr, "Unknown30500"},
        {30900, nullptr, "Unknown30900"},
        {30901, nullptr, "Unknown30901"},
        {30902, nullptr, "Unknown30902"},
        {40100, nullptr, "SetSubscriptionStatus"},
        {40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"},
        {40200, nullptr, "ClearStorage"},
        {40201, nullptr, "ClearSubscriptionStatusAll"},
        {90100, nullptr, "GetNewsDatabaseDump"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

INewsService::~INewsService() = default;

Result INewsService::GetSubscriptionStatus(Out<u32> out_status,
                                           InBuffer<BufferAttr_HipcPointer> buffer_data) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called, buffer_size={}", buffer_data.size());
    *out_status = 0;
    R_SUCCEED();
}

Result INewsService::IsSystemUpdateRequired(Out<bool> out_is_system_update_required) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called");
    *out_is_system_update_required = false;
    R_SUCCEED();
}

Result INewsService::RequestAutoSubscription(u64 value) {
    LOG_WARNING(Service_BCAT, "(STUBBED) called");
    R_SUCCEED();
}

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::News {

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

private:
    Result GetSubscriptionStatus(Out<u32> out_status, InBuffer<BufferAttr_HipcPointer> buffer_data);

    Result IsSystemUpdateRequired(Out<bool> out_is_system_update_required);

    Result RequestAutoSubscription(u64 value);
};

} // namespace Service::News


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

#include "core/hle/service/bcat/news/overwrite_event_holder.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::News {

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

    RegisterHandlers(functions);
    overwrite_event = service_context.CreateEvent("IOverwriteEventHolder::OverwriteEvent");
}

IOverwriteEventHolder::~IOverwriteEventHolder() {
    service_context.CloseEvent(overwrite_event);
}

Result IOverwriteEventHolder::Get(OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_INFO(Service_BCAT, "called");

    *out_event = &overwrite_event->GetReadableEvent();
    R_SUCCEED();
}

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

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

namespace Service::News {

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

private:
    Result Get(OutCopyHandle<Kernel::KReadableEvent> out_event);

    Kernel::KEvent* overwrite_event;
    KernelHelpers::ServiceContext service_context;
};

} // namespace Service::News


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

#include "core/hle/service/bcat/news/newly_arrived_event_holder.h"
#include "core/hle/service/bcat/news/news_data_service.h"
#include "core/hle/service/bcat/news/news_database_service.h"
#include "core/hle/service/bcat/news/news_service.h"
#include "core/hle/service/bcat/news/overwrite_event_holder.h"
#include "core/hle/service/bcat/news/service_creator.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::News {

IServiceCreator::IServiceCreator(Core::System& system_, u32 permissions_, const char* name_)
    : ServiceFramework{system_, name_}, permissions{permissions_} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IServiceCreator::CreateNewsService>, "CreateNewsService"},
        {1, D<&IServiceCreator::CreateNewlyArrivedEventHolder>, "CreateNewlyArrivedEventHolder"},
        {2, D<&IServiceCreator::CreateNewsDataService>, "CreateNewsDataService"},
        {3, D<&IServiceCreator::CreateNewsDatabaseService>, "CreateNewsDatabaseService"},
        {4, D<&IServiceCreator::CreateOverwriteEventHolder>, "CreateOverwriteEventHolder"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IServiceCreator::~IServiceCreator() = default;

Result IServiceCreator::CreateNewsService(OutInterface<INewsService> out_interface) {
    LOG_INFO(Service_BCAT, "called");
    *out_interface = std::make_shared<INewsService>(system);
    R_SUCCEED();
}

Result IServiceCreator::CreateNewlyArrivedEventHolder(
    OutInterface<INewlyArrivedEventHolder> out_interface) {
    LOG_INFO(Service_BCAT, "called");
    *out_interface = std::make_shared<INewlyArrivedEventHolder>(system);
    R_SUCCEED();
}

Result IServiceCreator::CreateNewsDataService(OutInterface<INewsDataService> out_interface) {
    LOG_INFO(Service_BCAT, "called");
    *out_interface = std::make_shared<INewsDataService>(system);
    R_SUCCEED();
}

Result IServiceCreator::CreateNewsDatabaseService(
    OutInterface<INewsDatabaseService> out_interface) {
    LOG_INFO(Service_BCAT, "called");
    *out_interface = std::make_shared<INewsDatabaseService>(system);
    R_SUCCEED();
}

Result IServiceCreator::CreateOverwriteEventHolder(
    OutInterface<IOverwriteEventHolder> out_interface) {
    LOG_INFO(Service_BCAT, "called");
    *out_interface = std::make_shared<IOverwriteEventHolder>(system);
    R_SUCCEED();
}

} // namespace Service::News


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::News {
class INewsService;
class INewlyArrivedEventHolder;
class INewsDataService;
class INewsDatabaseService;
class IOverwriteEventHolder;

class IServiceCreator final : public ServiceFramework<IServiceCreator> {
public:
    explicit IServiceCreator(Core::System& system_, u32 permissions_, const char* name_);
    ~IServiceCreator() override;

private:
    Result CreateNewsService(OutInterface<INewsService> out_interface);
    Result CreateNewlyArrivedEventHolder(OutInterface<INewlyArrivedEventHolder> out_interface);
    Result CreateNewsDataService(OutInterface<INewsDataService> out_interface);
    Result CreateNewsDatabaseService(OutInterface<INewsDatabaseService> out_interface);
    Result CreateOverwriteEventHolder(OutInterface<IOverwriteEventHolder> out_interface);

    u32 permissions;
};

} // namespace Service::News


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

#include "core/hle/service/bcat/bcat_service.h"
#include "core/hle/service/bcat/delivery_cache_storage_service.h"
#include "core/hle/service/bcat/service_creator.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"

namespace Service::BCAT {

std::unique_ptr<BcatBackend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
                                                       DirectoryGetter getter) {
    return std::make_unique<NullBcatBackend>(std::move(getter));
}

IServiceCreator::IServiceCreator(Core::System& system_, const char* name_)
    : ServiceFramework{system_, name_}, fsc{system.GetFileSystemController()} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, D<&IServiceCreator::CreateBcatService>, "CreateBcatService"},
        {1, D<&IServiceCreator::CreateDeliveryCacheStorageService>, "CreateDeliveryCacheStorageService"},
        {2, D<&IServiceCreator::CreateDeliveryCacheStorageServiceWithApplicationId>, "CreateDeliveryCacheStorageServiceWithApplicationId"},
        {3, nullptr, "CreateDeliveryCacheProgressService"},
        {4, nullptr, "CreateDeliveryCacheProgressServiceWithApplicationId"},
    };
    // clang-format on

    RegisterHandlers(functions);

    backend =
        CreateBackendFromSettings(system_, [this](u64 tid) { return fsc.GetBCATDirectory(tid); });
}

IServiceCreator::~IServiceCreator() = default;

Result IServiceCreator::CreateBcatService(ClientProcessId process_id,
                                          OutInterface<IBcatService> out_interface) {
    LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);
    *out_interface = std::make_shared<IBcatService>(system, *backend);
    R_SUCCEED();
}

Result IServiceCreator::CreateDeliveryCacheStorageService(
    ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
    LOG_INFO(Service_BCAT, "called, process_id={}", process_id.pid);

    const auto title_id = system.GetApplicationProcessProgramID();
    *out_interface =
        std::make_shared<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
    R_SUCCEED();
}

Result IServiceCreator::CreateDeliveryCacheStorageServiceWithApplicationId(
    u64 application_id, OutInterface<IDeliveryCacheStorageService> out_interface) {
    LOG_DEBUG(Service_BCAT, "called, application_id={:016X}", application_id);
    *out_interface = std::make_shared<IDeliveryCacheStorageService>(
        system, fsc.GetBCATDirectory(application_id));
    R_SUCCEED();
}

} // namespace Service::BCAT


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::FileSystem {
class FileSystemController;
}

namespace Service::BCAT {
class BcatBackend;
class IBcatService;
class IDeliveryCacheStorageService;

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

private:
    Result CreateBcatService(ClientProcessId process_id, OutInterface<IBcatService> out_interface);

    Result CreateDeliveryCacheStorageService(
        ClientProcessId process_id, OutInterface<IDeliveryCacheStorageService> out_interface);

    Result CreateDeliveryCacheStorageServiceWithApplicationId(
        u64 application_id, OutInterface<IDeliveryCacheStorageService> out_interface);

    std::unique_ptr<BcatBackend> backend;
    Service::FileSystem::FileSystemController& fsc;
};

} // namespace Service::BCAT


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

#include <memory>

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

namespace Service::BPC {

class BPC final : public ServiceFramework<BPC> {
public:
    explicit BPC(Core::System& system_) : ServiceFramework{system_, "bpc"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "ShutdownSystem"},
            {1, nullptr, "RebootSystem"},
            {2, nullptr, "GetWakeupReason"},
            {3, nullptr, "GetShutdownReason"},
            {4, nullptr, "GetAcOk"},
            {5, nullptr, "GetBoardPowerControlEvent"},
            {6, nullptr, "GetSleepButtonState"},
            {7, nullptr, "GetPowerEvent"},
            {8, nullptr, "CreateWakeupTimer"},
            {9, nullptr, "CancelWakeupTimer"},
            {10, nullptr, "EnableWakeupTimerOnDevice"},
            {11, nullptr, "CreateWakeupTimerEx"},
            {12, nullptr, "GetLastEnabledWakeupTimerType"},
            {13, nullptr, "CleanAllWakeupTimers"},
            {14, nullptr, "GetPowerButton"},
            {15, nullptr, "SetEnableWakeupTimer"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

class BPC_R final : public ServiceFramework<BPC_R> {
public:
    explicit BPC_R(Core::System& system_) : ServiceFramework{system_, "bpc:r"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "GetRtcTime"},
            {1, nullptr, "SetRtcTime"},
            {2, nullptr, "GetRtcResetDetected"},
            {3, nullptr, "ClearRtcResetDetected"},
            {4, nullptr, "SetUpRtcResetOnShutdown"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

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

    server_manager->RegisterNamedService("bpc", std::make_shared<BPC>(system));
    server_manager->RegisterNamedService("bpc:r", std::make_shared<BPC_R>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::BPC


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

#pragma once

namespace Core {
class System;
}

namespace Service::SM {
class ServiceManager;
}

namespace Service::BPC {

void LoopProcess(Core::System& system);

} // namespace Service::BPC


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

#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/btdrv/btdrv.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"

namespace Service::BtDrv {

class IBluetoothUser final : public ServiceFramework<IBluetoothUser> {
public:
    explicit IBluetoothUser(Core::System& system_)
        : ServiceFramework{system_, "bt"}, service_context{system_, "bt"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "LeClientReadCharacteristic"},
            {1, nullptr, "LeClientReadDescriptor"},
            {2, nullptr, "LeClientWriteCharacteristic"},
            {3, nullptr, "LeClientWriteDescriptor"},
            {4, nullptr, "LeClientRegisterNotification"},
            {5, nullptr, "LeClientDeregisterNotification"},
            {6, nullptr, "SetLeResponse"},
            {7, nullptr, "LeSendIndication"},
            {8, nullptr, "GetLeEventInfo"},
            {9, C<&IBluetoothUser::RegisterBleEvent>, "RegisterBleEvent"},
        };
        // clang-format on
        RegisterHandlers(functions);

        register_event = service_context.CreateEvent("BT:RegisterEvent");
    }

    ~IBluetoothUser() override {
        service_context.CloseEvent(register_event);
    }

private:
    Result RegisterBleEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
        LOG_WARNING(Service_BTM, "(STUBBED) called");

        *out_event = &register_event->GetReadableEvent();
        R_SUCCEED();
    }

    KernelHelpers::ServiceContext service_context;

    Kernel::KEvent* register_event;
};

class IBluetoothDriver final : public ServiceFramework<IBluetoothDriver> {
public:
    explicit IBluetoothDriver(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "InitializeBluetoothDriver"},
            {1, nullptr, "InitializeBluetooth"},
            {2, nullptr, "EnableBluetooth"},
            {3, nullptr, "DisableBluetooth"},
            {4, nullptr, "FinalizeBluetooth"},
            {5, nullptr, "GetAdapterProperties"},
            {6, nullptr, "GetAdapterProperty"},
            {7, nullptr, "SetAdapterProperty"},
            {8, nullptr, "StartInquiry"},
            {9, nullptr, "StopInquiry"},
            {10, nullptr, "CreateBond"},
            {11, nullptr, "RemoveBond"},
            {12, nullptr, "CancelBond"},
            {13, nullptr, "RespondToPinRequest"},
            {14, nullptr, "RespondToSspRequest"},
            {15, nullptr, "GetEventInfo"},
            {16, nullptr, "InitializeHid"},
            {17, nullptr, "OpenHidConnection"},
            {18, nullptr, "CloseHidConnection"},
            {19, nullptr, "WriteHidData"},
            {20, nullptr, "WriteHidData2"},
            {21, nullptr, "SetHidReport"},
            {22, nullptr, "GetHidReport"},
            {23, nullptr, "TriggerConnection"},
            {24, nullptr, "AddPairedDeviceInfo"},
            {25, nullptr, "GetPairedDeviceInfo"},
            {26, nullptr, "FinalizeHid"},
            {27, nullptr, "GetHidEventInfo"},
            {28, nullptr, "SetTsi"},
            {29, nullptr, "EnableBurstMode"},
            {30, nullptr, "SetZeroRetransmission"},
            {31, nullptr, "EnableMcMode"},
            {32, nullptr, "EnableLlrScan"},
            {33, nullptr, "DisableLlrScan"},
            {34, C<&IBluetoothDriver::EnableRadio>, "EnableRadio"},
            {35, nullptr, "SetVisibility"},
            {36, nullptr, "EnableTbfcScan"},
            {37, nullptr, "RegisterHidReportEvent"},
            {38, nullptr, "GetHidReportEventInfo"},
            {39, nullptr, "GetLatestPlr"},
            {40, nullptr, "GetPendingConnections"},
            {41, nullptr, "GetChannelMap"},
            {42, nullptr, "EnableTxPowerBoostSetting"},
            {43, nullptr, "IsTxPowerBoostSettingEnabled"},
            {44, nullptr, "EnableAfhSetting"},
            {45, nullptr, "IsAfhSettingEnabled"},
            {46, nullptr, "InitializeBle"},
            {47, nullptr, "EnableBle"},
            {48, nullptr, "DisableBle"},
            {49, nullptr, "FinalizeBle"},
            {50, nullptr, "SetBleVisibility"},
            {51, nullptr, "SetBleConnectionParameter"},
            {52, nullptr, "SetBleDefaultConnectionParameter"},
            {53, nullptr, "SetBleAdvertiseData"},
            {54, nullptr, "SetBleAdvertiseParameter"},
            {55, nullptr, "StartBleScan"},
            {56, nullptr, "StopBleScan"},
            {57, nullptr, "AddBleScanFilterCondition"},
            {58, nullptr, "DeleteBleScanFilterCondition"},
            {59, nullptr, "DeleteBleScanFilter"},
            {60, nullptr, "ClearBleScanFilters"},
            {61, nullptr, "EnableBleScanFilter"},
            {62, nullptr, "RegisterGattClient"},
            {63, nullptr, "UnregisterGattClient"},
            {64, nullptr, "UnregisterAllGattClients"},
            {65, nullptr, "ConnectGattServer"},
            {66, nullptr, "CancelConnectGattServer"},
            {67, nullptr, "DisconnectGattServer"},
            {68, nullptr, "GetGattAttribute"},
            {69, nullptr, "GetGattService"},
            {70, nullptr, "ConfigureAttMtu"},
            {71, nullptr, "RegisterGattServer"},
            {72, nullptr, "UnregisterGattServer"},
            {73, nullptr, "ConnectGattClient"},
            {74, nullptr, "DisconnectGattClient"},
            {75, nullptr, "AddGattService"},
            {76, nullptr, "EnableGattService"},
            {77, nullptr, "AddGattCharacteristic"},
            {78, nullptr, "AddGattDescriptor"},
            {79, nullptr, "GetBleManagedEventInfo"},
            {80, nullptr, "GetGattFirstCharacteristic"},
            {81, nullptr, "GetGattNextCharacteristic"},
            {82, nullptr, "GetGattFirstDescriptor"},
            {83, nullptr, "GetGattNextDescriptor"},
            {84, nullptr, "RegisterGattManagedDataPath"},
            {85, nullptr, "UnregisterGattManagedDataPath"},
            {86, nullptr, "RegisterGattHidDataPath"},
            {87, nullptr, "UnregisterGattHidDataPath"},
            {88, nullptr, "RegisterGattDataPath"},
            {89, nullptr, "UnregisterGattDataPath"},
            {90, nullptr, "ReadGattCharacteristic"},
            {91, nullptr, "ReadGattDescriptor"},
            {92, nullptr, "WriteGattCharacteristic"},
            {93, nullptr, "WriteGattDescriptor"},
            {94, nullptr, "RegisterGattNotification"},
            {95, nullptr, "UnregisterGattNotification"},
            {96, nullptr, "GetLeHidEventInfo"},
            {97, nullptr, "RegisterBleHidEvent"},
            {98, nullptr, "SetBleScanParameter"},
            {99, nullptr, "MoveToSecondaryPiconet"},
            {100, nullptr, "IsBluetoothEnabled"},
            {128, nullptr, "AcquireAudioEvent"},
            {129, nullptr, "GetAudioEventInfo"},
            {130, nullptr, "OpenAudioConnection"},
            {131, nullptr, "CloseAudioConnection"},
            {132, nullptr, "OpenAudioOut"},
            {133, nullptr, "CloseAudioOut"},
            {134, nullptr, "AcquireAudioOutStateChangedEvent"},
            {135, nullptr, "StartAudioOut"},
            {136, nullptr, "StopAudioOut"},
            {137, nullptr, "GetAudioOutState"},
            {138, nullptr, "GetAudioOutFeedingCodec"},
            {139, nullptr, "GetAudioOutFeedingParameter"},
            {140, nullptr, "AcquireAudioOutBufferAvailableEvent"},
            {141, nullptr, "SendAudioData"},
            {142, nullptr, "AcquireAudioControlInputStateChangedEvent"},
            {143, nullptr, "GetAudioControlInputState"},
            {144, nullptr, "AcquireAudioConnectionStateChangedEvent"},
            {145, nullptr, "GetConnectedAudioDevice"},
            {146, nullptr, "CloseAudioControlInput"},
            {147, nullptr, "RegisterAudioControlNotification"},
            {148, nullptr, "SendAudioControlPassthroughCommand"},
            {149, nullptr, "SendAudioControlSetAbsoluteVolumeCommand"},
            {150, nullptr, "AcquireAudioSinkVolumeLocallyChangedEvent"},
            {151, nullptr, "AcquireAudioSinkVolumeUpdateRequestCompletedEvent"},
            {152, nullptr, "GetAudioSinkVolume"},
            {153, nullptr, "RequestUpdateAudioSinkVolume"},
            {154, nullptr, "IsAudioSinkVolumeSupported"},
            {256, nullptr, "IsManufacturingMode"},
            {257, nullptr, "EmulateBluetoothCrash"},
            {258, nullptr, "GetBleChannelMap"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }

private:
    Result EnableRadio() {
        LOG_WARNING(Service_BTDRV, "(STUBBED) called");
        R_SUCCEED();
    }
};

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

    server_manager->RegisterNamedService("btdrv", std::make_shared<IBluetoothDriver>(system));
    server_manager->RegisterNamedService("bt", std::make_shared<IBluetoothUser>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::BtDrv


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

#pragma once

namespace Service::SM {
class ServiceManager;
}

namespace Core {
class System;
}

namespace Service::BtDrv {

void LoopProcess(Core::System& system);

} // namespace Service::BtDrv


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

#include <memory>

#include "core/hle/service/btm/btm.h"
#include "core/hle/service/btm/btm_debug.h"
#include "core/hle/service/btm/btm_system.h"
#include "core/hle/service/btm/btm_user.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"

namespace Service::BTM {

class IBtm final : public ServiceFramework<IBtm> {
public:
    explicit IBtm(Core::System& system_) : ServiceFramework{system_, "btm"} {
        // clang-format off
        static const FunctionInfo functions[] = {
            {0, nullptr, "GetState"},
            {1, nullptr, "GetHostDeviceProperty"},
            {2, nullptr, "AcquireDeviceConditionEvent"},
            {3, nullptr, "GetDeviceCondition"},
            {4, nullptr, "SetBurstMode"},
            {5, nullptr, "SetSlotMode"},
            {6, nullptr, "SetBluetoothMode"},
            {7, nullptr, "SetWlanMode"},
            {8, nullptr, "AcquireDeviceInfoEvent"},
            {9, nullptr, "GetDeviceInfo"},
            {10, nullptr, "AddDeviceInfo"},
            {11, nullptr, "RemoveDeviceInfo"},
            {12, nullptr, "IncreaseDeviceInfoOrder"},
            {13, nullptr, "LlrNotify"},
            {14, nullptr, "EnableRadio"},
            {15, nullptr, "DisableRadio"},
            {16, nullptr, "HidDisconnect"},
            {17, nullptr, "HidSetRetransmissionMode"},
            {18, nullptr, "AcquireAwakeReqEvent"},
            {19, nullptr, "AcquireLlrStateEvent"},
            {20, nullptr, "IsLlrStarted"},
            {21, nullptr, "EnableSlotSaving"},
            {22, nullptr, "ProtectDeviceInfo"},
            {23, nullptr, "AcquireBleScanEvent"},
            {24, nullptr, "GetBleScanParameterGeneral"},
            {25, nullptr, "GetBleScanParameterSmartDevice"},
            {26, nullptr, "StartBleScanForGeneral"},
            {27, nullptr, "StopBleScanForGeneral"},
            {28, nullptr, "GetBleScanResultsForGeneral"},
            {29, nullptr, "StartBleScanForPairedDevice"},
            {30, nullptr, "StopBleScanForPairedDevice"},
            {31, nullptr, "StartBleScanForSmartDevice"},
            {32, nullptr, "StopBleScanForSmartDevice"},
            {33, nullptr, "GetBleScanResultsForSmartDevice"},
            {34, nullptr, "AcquireBleConnectionEvent"},
            {35, nullptr, "BleConnect"},
            {36, nullptr, "BleOverrideConnection"},
            {37, nullptr, "BleDisconnect"},
            {38, nullptr, "BleGetConnectionState"},
            {39, nullptr, "BleGetGattClientConditionList"},
            {40, nullptr, "AcquireBlePairingEvent"},
            {41, nullptr, "BlePairDevice"},
            {42, nullptr, "BleUnpairDeviceOnBoth"},
            {43, nullptr, "BleUnpairDevice"},
            {44, nullptr, "BleGetPairedAddresses"},
            {45, nullptr, "AcquireBleServiceDiscoveryEvent"},
            {46, nullptr, "GetGattServices"},
            {47, nullptr, "GetGattService"},
            {48, nullptr, "GetGattIncludedServices"},
            {49, nullptr, "GetBelongingService"},
            {50, nullptr, "GetGattCharacteristics"},
            {51, nullptr, "GetGattDescriptors"},
            {52, nullptr, "AcquireBleMtuConfigEvent"},
            {53, nullptr, "ConfigureBleMtu"},
            {54, nullptr, "GetBleMtu"},
            {55, nullptr, "RegisterBleGattDataPath"},
            {56, nullptr, "UnregisterBleGattDataPath"},
            {57, nullptr, "RegisterAppletResourceUserId"},
            {58, nullptr, "UnregisterAppletResourceUserId"},
            {59, nullptr, "SetAppletResourceUserId"},
            {60, nullptr, "Unknown60"},
            {61, nullptr, "Unknown61"},
            {62, nullptr, "Unknown62"},
            {63, nullptr, "Unknown63"},
            {64, nullptr, "Unknown64"},
            {65, nullptr, "Unknown65"},
            {66, nullptr, "Unknown66"},
            {67, nullptr, "Unknown67"},
            {68, nullptr, "Unknown68"},
            {69, nullptr, "Unknown69"},
            {70, nullptr, "Unknown70"},
            {71, nullptr, "Unknown71"},
            {72, nullptr, "Unknown72"},
            {73, nullptr, "Unknown73"},
            {74, nullptr, "Unknown74"},
            {75, nullptr, "Unknown75"},
            {76, nullptr, "Unknown76"},
            {100, nullptr, "Unknown100"},
            {101, nullptr, "Unknown101"},
            {110, nullptr, "Unknown110"},
            {111, nullptr, "Unknown111"},
            {112, nullptr, "Unknown112"},
            {113, nullptr, "Unknown113"},
            {114, nullptr, "Unknown114"},
            {115, nullptr, "Unknown115"},
        };
        // clang-format on

        RegisterHandlers(functions);
    }
};

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

    server_manager->RegisterNamedService("btm", std::make_shared<IBtm>(system));
    server_manager->RegisterNamedService("btm:dbg", std::make_shared<IBtmDebug>(system));
    server_manager->RegisterNamedService("btm:sys", std::make_shared<IBtmSystem>(system));
    server_manager->RegisterNamedService("btm:u", std::make_shared<IBtmUser>(system));
    ServerManager::RunServer(std::move(server_manager));
}

} // namespace Service::BTM


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

#pragma once

namespace Core {
class System;
};

namespace Service::BTM {

void LoopProcess(Core::System& system);

} // namespace Service::BTM


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

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

namespace Service::BTM {

IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, nullptr, "AcquireDiscoveryEvent"},
        {1, nullptr, "StartDiscovery"},
        {2, nullptr, "CancelDiscovery"},
        {3, nullptr, "GetDeviceProperty"},
        {4, nullptr, "CreateBond"},
        {5, nullptr, "CancelBond"},
        {6, nullptr, "SetTsiMode"},
        {7, nullptr, "GeneralTest"},
        {8, nullptr, "HidConnect"},
        {9, nullptr, "GeneralGet"},
        {10, nullptr, "GetGattClientDisconnectionReason"},
        {11, nullptr, "GetBleConnectionParameter"},
        {12, nullptr, "GetBleConnectionParameterRequest"},
        {13, nullptr, "Unknown13"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IBtmDebug::~IBtmDebug() = default;

} // namespace Service::BTM


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::BTM {

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

} // namespace Service::BTM


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

#include "common/logging/log.h"
#include "core/hle/service/btm/btm_system.h"
#include "core/hle/service/btm/btm_system_core.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/service.h"

namespace Service::BTM {

IBtmSystem::IBtmSystem(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, C<&IBtmSystem::GetCore>, "GetCore"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IBtmSystem::~IBtmSystem() = default;

Result IBtmSystem::GetCore(OutInterface<IBtmSystemCore> out_interface) {
    LOG_WARNING(Service_BTM, "called");

    *out_interface = std::make_shared<IBtmSystemCore>(system);
    R_SUCCEED();
}

} // namespace Service::BTM


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::BTM {
class IBtmSystemCore;

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

private:
    Result GetCore(OutInterface<IBtmSystemCore> out_interface);
};

} // namespace Service::BTM


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

#include "common/logging/log.h"
#include "core/hle/service/btm/btm_system_core.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"

namespace Service::BTM {

IBtmSystemCore::IBtmSystemCore(Core::System& system_)
    : ServiceFramework{system_, "IBtmSystemCore"}, service_context{system_, "IBtmSystemCore"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, C<&IBtmSystemCore::StartGamepadPairing>, "StartGamepadPairing"},
        {1, C<&IBtmSystemCore::CancelGamepadPairing>, "CancelGamepadPairing"},
        {2, nullptr, "ClearGamepadPairingDatabase"},
        {3, nullptr, "GetPairedGamepadCount"},
        {4, C<&IBtmSystemCore::EnableRadio>, "EnableRadio"},
        {5, C<&IBtmSystemCore::DisableRadio>, "DisableRadio"},
        {6, C<&IBtmSystemCore::IsRadioEnabled>, "IsRadioEnabled"},
        {7, C<&IBtmSystemCore::AcquireRadioEvent>, "AcquireRadioEvent"},
        {8, nullptr, "AcquireGamepadPairingEvent"},
        {9, nullptr, "IsGamepadPairingStarted"},
        {10, nullptr, "StartAudioDeviceDiscovery"},
        {11, nullptr, "StopAudioDeviceDiscovery"},
        {12, nullptr, "IsDiscoveryingAudioDevice"},
        {13, nullptr, "GetDiscoveredAudioDevice"},
        {14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
        {15, nullptr, "ConnectAudioDevice"},
        {16, nullptr, "IsConnectingAudioDevice"},
        {17, C<&IBtmSystemCore::GetConnectedAudioDevices>, "GetConnectedAudioDevices"},
        {18, nullptr, "DisconnectAudioDevice"},
        {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
        {20, C<&IBtmSystemCore::GetPairedAudioDevices>, "GetPairedAudioDevices"},
        {21, nullptr, "RemoveAudioDevicePairing"},
        {22, C<&IBtmSystemCore::RequestAudioDeviceConnectionRejection>, "RequestAudioDeviceConnectionRejection"},
        {23, C<&IBtmSystemCore::CancelAudioDeviceConnectionRejection>, "CancelAudioDeviceConnectionRejection"}
    };
    // clang-format on

    RegisterHandlers(functions);
    radio_event = service_context.CreateEvent("IBtmSystemCore::RadioEvent");
    audio_device_connection_event =
        service_context.CreateEvent("IBtmSystemCore::AudioDeviceConnectionEvent");

    m_set_sys =
        system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true);
}

IBtmSystemCore::~IBtmSystemCore() {
    service_context.CloseEvent(radio_event);
    service_context.CloseEvent(audio_device_connection_event);
}

Result IBtmSystemCore::StartGamepadPairing() {
    LOG_WARNING(Service_BTM, "(STUBBED) called");
    R_SUCCEED();
}

Result IBtmSystemCore::CancelGamepadPairing() {
    LOG_WARNING(Service_BTM, "(STUBBED) called");
    R_SUCCEED();
}

Result IBtmSystemCore::EnableRadio() {
    LOG_DEBUG(Service_BTM, "called");

    R_RETURN(m_set_sys->SetBluetoothEnableFlag(true));
}
Result IBtmSystemCore::DisableRadio() {
    LOG_DEBUG(Service_BTM, "called");

    R_RETURN(m_set_sys->SetBluetoothEnableFlag(false));
}

Result IBtmSystemCore::IsRadioEnabled(Out<bool> out_is_enabled) {
    LOG_DEBUG(Service_BTM, "called");

    R_RETURN(m_set_sys->GetBluetoothEnableFlag(out_is_enabled));
}

Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
                                         OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_WARNING(Service_BTM, "(STUBBED) called");

    *out_is_valid = true;
    *out_event = &radio_event->GetReadableEvent();
    R_SUCCEED();
}

Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
    OutCopyHandle<Kernel::KReadableEvent> out_event) {
    LOG_WARNING(Service_BTM, "(STUBBED) called");

    *out_event = &audio_device_connection_event->GetReadableEvent();
    R_SUCCEED();
}

Result IBtmSystemCore::GetConnectedAudioDevices(
    Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
    LOG_WARNING(Service_BTM, "(STUBBED) called");

    *out_count = 0;
    R_SUCCEED();
}

Result IBtmSystemCore::GetPairedAudioDevices(
    Out<s32> out_count, OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices) {
    LOG_WARNING(Service_BTM, "(STUBBED) called");

    *out_count = 0;
    R_SUCCEED();
}

Result IBtmSystemCore::RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
    LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
    R_SUCCEED();
}

Result IBtmSystemCore::CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid) {
    LOG_WARNING(Service_BTM, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
    R_SUCCEED();
}

} // namespace Service::BTM


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

#pragma once

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

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

namespace Core {
class System;
}

namespace Service::Set {
class ISystemSettingsServer;
}

namespace Service::BTM {

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

private:
    Result StartGamepadPairing();
    Result CancelGamepadPairing();
    Result EnableRadio();
    Result DisableRadio();
    Result IsRadioEnabled(Out<bool> out_is_enabled);

    Result AcquireRadioEvent(Out<bool> out_is_valid,
                             OutCopyHandle<Kernel::KReadableEvent> out_event);

    Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);

    Result GetConnectedAudioDevices(
        Out<s32> out_count,
        OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);

    Result GetPairedAudioDevices(
        Out<s32> out_count,
        OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices);

    Result RequestAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);
    Result CancelAudioDeviceConnectionRejection(ClientAppletResourceUserId aruid);

    KernelHelpers::ServiceContext service_context;

    Kernel::KEvent* radio_event;
    Kernel::KEvent* audio_device_connection_event;
    std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};

} // namespace Service::BTM


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

#include "common/logging/log.h"
#include "core/hle/service/btm/btm_user.h"
#include "core/hle/service/btm/btm_user_core.h"
#include "core/hle/service/cmif_serialization.h"

namespace Service::BTM {

IBtmUser::IBtmUser(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
    // clang-format off
    static const FunctionInfo functions[] = {
        {0, C<&IBtmUser::GetCore>, "GetCore"},
    };
    // clang-format on

    RegisterHandlers(functions);
}

IBtmUser::~IBtmUser() = default;

Result IBtmUser::GetCore(OutInterface<IBtmUserCore> out_interface) {
    LOG_WARNING(Service_BTM, "called");

    *out_interface = std::make_shared<IBtmUserCore>(system);
    R_SUCCEED();
}

} // namespace Service::BTM


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

#pragma once

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

namespace Core {
class System;
}

namespace Service::BTM {
class IBtmUserCore;

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

private:
    Result GetCore(OutInterface<IBtmUserCore> out_interface);
};

} // namespace Service::BTM