mirror of
https://git.citron-emu.org/citron/emulator
synced 2026-02-02 23:53:36 +00:00
feat(hle): implement misc service stubs for QLaunch compatibility
- audctl: Add GetAudioController (cmd 5000) returning IAudioController - vi: Improve display service with better non-default display handling - psc/ovln: Add GetReceiveEventHandle for overlay notifications - omm: Add GetNotificationMessageEventHandle for power state - olsc: Implement GetNativeHandle returning valid event - prepo: Add SaveSystemReport2 (cmd 20102) stub
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
@@ -72,7 +72,7 @@ IAudioController::IAudioController(Core::System& system_)
|
||||
{50001, D<&IAudioController::OverrideDefaultTargetForDebug>, "OverrideDefaultTargetForDebug"}, // [19.0.0-19.0.1]
|
||||
{50003, D<&IAudioController::SetForceOverrideExternalDeviceNameForDebug>, "SetForceOverrideExternalDeviceNameForDebug"}, // [19.0.0+]
|
||||
{50004, D<&IAudioController::ClearForceOverrideExternalDeviceNameForDebug>, "ClearForceOverrideExternalDeviceNameForDebug"}, // [19.0.0+]
|
||||
{5000, nullptr, "Unknown5000"}, // [19.0.0+]
|
||||
{5000, D<&IAudioController::GetAudioController>, "GetAudioController"}, // [19.0.0+]
|
||||
{10200, D<&IAudioController::Unknown10200>, "Unknown10200"}, // [20.0.0+]
|
||||
};
|
||||
// clang-format on
|
||||
@@ -407,4 +407,11 @@ Result IAudioController::Unknown10200() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAudioController::GetAudioController(
|
||||
Out<SharedPointer<IAudioController>> out_audio_controller) {
|
||||
LOG_DEBUG(Audio, "called GetAudioController [19.0.0+]");
|
||||
*out_audio_controller = std::make_shared<IAudioController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::Audio
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -90,6 +90,7 @@ private:
|
||||
Result OverrideDefaultTargetForDebug(u32 target); // [19.0.0-19.0.1]
|
||||
Result SetForceOverrideExternalDeviceNameForDebug(InLargeData<std::array<u8, 0x80>, BufferAttr_HipcMapAlias> device_name); // [19.0.0+]
|
||||
Result ClearForceOverrideExternalDeviceNameForDebug(); // [19.0.0+]
|
||||
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller); // [19.0.0+]
|
||||
Result Unknown10200(); // [20.0.0+]
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
@@ -7,7 +8,8 @@
|
||||
namespace Service::OLSC {
|
||||
|
||||
INativeHandleHolder::INativeHandleHolder(Core::System& system_)
|
||||
: ServiceFramework{system_, "INativeHandleHolder"} {
|
||||
: ServiceFramework{system_, "INativeHandleHolder"},
|
||||
service_context{system_, "INativeHandleHolder"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&INativeHandleHolder::GetNativeHandle>, "GetNativeHandle"},
|
||||
@@ -15,13 +17,17 @@ INativeHandleHolder::INativeHandleHolder(Core::System& system_)
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
event = service_context.CreateEvent("INativeHandleHolder:Event");
|
||||
}
|
||||
|
||||
INativeHandleHolder::~INativeHandleHolder() = default;
|
||||
INativeHandleHolder::~INativeHandleHolder() {
|
||||
service_context.CloseEvent(event);
|
||||
}
|
||||
|
||||
Result INativeHandleHolder::GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
*out_event = nullptr;
|
||||
LOG_DEBUG(Service_OLSC, "called");
|
||||
*out_event = &event->GetReadableEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
class KEvent;
|
||||
}
|
||||
|
||||
namespace Service::OLSC {
|
||||
@@ -17,6 +22,9 @@ public:
|
||||
|
||||
private:
|
||||
Result GetNativeHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* event;
|
||||
};
|
||||
|
||||
} // namespace Service::OLSC
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/omm/power_state_interface.h"
|
||||
|
||||
namespace Service::OMM {
|
||||
|
||||
IPowerStateInterface::IPowerStateInterface(Core::System& system_)
|
||||
: ServiceFramework{system_, "spsm"} {
|
||||
: ServiceFramework{system_, "spsm"}, service_context{system_, "IPowerStateInterface"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetState"},
|
||||
{1, nullptr, "EnterSleep"},
|
||||
{2, nullptr, "GetLastWakeReason"},
|
||||
{3, nullptr, "Shutdown"},
|
||||
{4, nullptr, "GetNotificationMessageEventHandle"},
|
||||
{4, D<&IPowerStateInterface::GetNotificationMessageEventHandle>, "GetNotificationMessageEventHandle"},
|
||||
{5, nullptr, "ReceiveNotificationMessage"},
|
||||
{6, nullptr, "AnalyzeLogForLastSleepWakeSequence"},
|
||||
{7, nullptr, "ResetEventLog"},
|
||||
@@ -25,8 +27,18 @@ IPowerStateInterface::IPowerStateInterface(Core::System& system_)
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
notification_event = service_context.CreateEvent("IPowerStateInterface:NotificationEvent");
|
||||
}
|
||||
|
||||
IPowerStateInterface::~IPowerStateInterface() = default;
|
||||
IPowerStateInterface::~IPowerStateInterface() {
|
||||
service_context.CloseEvent(notification_event);
|
||||
}
|
||||
|
||||
Result IPowerStateInterface::GetNotificationMessageEventHandle(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service, "called");
|
||||
*out_event = ¬ification_event->GetReadableEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::OMM
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -15,6 +22,12 @@ class IPowerStateInterface final : public ServiceFramework<IPowerStateInterface>
|
||||
public:
|
||||
explicit IPowerStateInterface(Core::System& system_);
|
||||
~IPowerStateInterface() override;
|
||||
|
||||
private:
|
||||
Result GetNotificationMessageEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* notification_event;
|
||||
};
|
||||
|
||||
} // namespace Service::OMM
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
{10500, &PlayReport::SendReportWithUser, "SendReportWithUser"},
|
||||
{20100, &PlayReport::SaveSystemReport, "SaveSystemReport"},
|
||||
{20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
|
||||
{20102, &PlayReport::SaveSystemReport2, "SaveSystemReport2"},
|
||||
{20200, &PlayReport::SetOperationMode, "SetOperationMode"},
|
||||
{30100, &PlayReport::ClearStorage, "ClearStorage"},
|
||||
{30200, &PlayReport::ClearStatistics, "ClearStatistics"},
|
||||
@@ -160,6 +161,13 @@ private:
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SaveSystemReport2(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PREPO, "(STUBBED) called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void SetOperationMode(HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_PREPO, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -1,24 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/psc/ovln/receiver.h"
|
||||
|
||||
namespace Service::PSC {
|
||||
|
||||
IReceiver::IReceiver(Core::System& system_) : ServiceFramework{system_, "IReceiver"} {
|
||||
IReceiver::IReceiver(Core::System& system_)
|
||||
: ServiceFramework{system_, "IReceiver"}, service_context{system_, "IReceiver"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "AddSource"},
|
||||
{1, nullptr, "RemoveSource"},
|
||||
{2, nullptr, "GetReceiveEventHandle"},
|
||||
{2, D<&IReceiver::GetReceiveEventHandle>, "GetReceiveEventHandle"},
|
||||
{3, nullptr, "Receive"},
|
||||
{4, nullptr, "ReceiveWithTick"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
event = service_context.CreateEvent("IReceiver:Event");
|
||||
}
|
||||
|
||||
IReceiver::~IReceiver() = default;
|
||||
IReceiver::~IReceiver() {
|
||||
service_context.CloseEvent(event);
|
||||
}
|
||||
|
||||
Result IReceiver::GetReceiveEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_PSC, "called");
|
||||
*out_event = &event->GetReadableEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::PSC
|
||||
|
||||
@@ -3,14 +3,27 @@
|
||||
|
||||
#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 Service::PSC {
|
||||
|
||||
class IReceiver final : public ServiceFramework<IReceiver> {
|
||||
public:
|
||||
explicit IReceiver(Core::System& system_);
|
||||
~IReceiver() override;
|
||||
|
||||
private:
|
||||
Result GetReceiveEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Kernel::KEvent* event;
|
||||
};
|
||||
|
||||
} // namespace Service::PSC
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/nvnflinger/hos_binder_driver.h"
|
||||
#include "core/hle/service/nvnflinger/parcel.h"
|
||||
@@ -88,8 +91,12 @@ Result IApplicationDisplayService::OpenDisplay(Out<u64> out_display_id, DisplayN
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
|
||||
display_name[display_name.size() - 1] = '\0';
|
||||
ASSERT_MSG(strcmp(display_name.data(), "Default") == 0,
|
||||
"Non-default displays aren't supported yet");
|
||||
if (strcmp(display_name.data(), "Default") != 0) {
|
||||
LOG_WARNING(Service_VI, "Non-default display '{}' requested, using Default display",
|
||||
display_name.data());
|
||||
// Use Default display for non-default display requests
|
||||
R_RETURN(m_container->OpenDisplay(out_display_id, DisplayName{"Default"}));
|
||||
}
|
||||
|
||||
R_RETURN(m_container->OpenDisplay(out_display_id, display_name));
|
||||
}
|
||||
@@ -142,14 +149,39 @@ Result IApplicationDisplayService::SetLayerScalingMode(NintendoScaleMode scale_m
|
||||
|
||||
Result IApplicationDisplayService::ListDisplays(
|
||||
Out<u64> out_count, OutArray<DisplayInfo, BufferAttr_HipcMapAlias> out_displays) {
|
||||
LOG_WARNING(Service_VI, "(STUBBED) called");
|
||||
LOG_DEBUG(Service_VI, "called");
|
||||
|
||||
if (out_displays.size() > 0) {
|
||||
out_displays[0] = DisplayInfo{};
|
||||
*out_count = 1;
|
||||
} else {
|
||||
*out_count = 0;
|
||||
// QLaunch expects multiple displays: Default, Edid, Internal, External, Null
|
||||
struct DisplayEntry {
|
||||
const char* name;
|
||||
u8 has_limited_layers;
|
||||
u64 max_layers;
|
||||
u64 width;
|
||||
u64 height;
|
||||
};
|
||||
|
||||
static constexpr std::array<DisplayEntry, 5> display_entries{{
|
||||
{"Default", 1, 1, 1920, 1080},
|
||||
{"Edid", 1, 1, 1920, 1080},
|
||||
{"Internal", 1, 1, 1280, 720},
|
||||
{"External", 1, 1, 1920, 1080},
|
||||
{"Null", 0, 0, 0, 0},
|
||||
}};
|
||||
|
||||
const u64 display_count =
|
||||
std::min(static_cast<u64>(display_entries.size()), out_displays.size());
|
||||
|
||||
for (u64 i = 0; i < display_count; ++i) {
|
||||
DisplayInfo info{};
|
||||
std::strncpy(info.display_name.data(), display_entries[i].name,
|
||||
info.display_name.size() - 1);
|
||||
info.has_limited_layers = display_entries[i].has_limited_layers;
|
||||
info.max_layers = display_entries[i].max_layers;
|
||||
info.width = display_entries[i].width;
|
||||
info.height = display_entries[i].height;
|
||||
out_displays[i] = info;
|
||||
}
|
||||
*out_count = display_count;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user