mirror of
https://git.citron-emu.org/citron/emulator
synced 2026-02-02 23:53:36 +00:00
Merge pull request 'feat/qlaunch-home-menu-support' (#115) from feat/qlaunch-home-menu-support into main
Reviewed-on: https://git.citron-emu.org/Citron/Emulator/pulls/115
This commit is contained in:
@@ -44,6 +44,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
||||
INSERT(Settings, wifi_web_auth_applet_mode, tr("Wifi web auth"), QStringLiteral());
|
||||
INSERT(Settings, my_page_applet_mode, tr("My page"), QStringLiteral());
|
||||
|
||||
// System Applet
|
||||
INSERT(Settings, qlaunch_enabled, tr("Enable Home Menu (QLaunch)"),
|
||||
tr("When enabled, pressing the Home button will launch the firmware's Home Menu.\n"
|
||||
"Requires firmware to be installed."));
|
||||
|
||||
// Audio
|
||||
INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral());
|
||||
INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral());
|
||||
|
||||
@@ -1725,6 +1725,7 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig);
|
||||
|
||||
// Tools
|
||||
connect_menu(ui->action_Load_Home_Menu, &GMainWindow::OnQLaunch);
|
||||
connect_menu(ui->action_Load_Album, &GMainWindow::OnAlbum);
|
||||
connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
|
||||
[this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
|
||||
@@ -1769,7 +1770,8 @@ void GMainWindow::UpdateMenuState() {
|
||||
ui->action_Pause,
|
||||
};
|
||||
|
||||
const std::array applet_actions{ui->action_Load_Album,
|
||||
const std::array applet_actions{ui->action_Load_Home_Menu,
|
||||
ui->action_Load_Album,
|
||||
ui->action_Load_Cabinet_Nickname_Owner,
|
||||
ui->action_Load_Cabinet_Eraser,
|
||||
ui->action_Load_Cabinet_Restorer,
|
||||
@@ -2167,6 +2169,9 @@ void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletP
|
||||
render_window->Exit();
|
||||
});
|
||||
|
||||
// Set up home menu callback for QLaunch support
|
||||
SetupHomeMenuCallback();
|
||||
|
||||
connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame);
|
||||
connect(render_window, &GRenderWindow::MouseActivity, this, &GMainWindow::OnMouseActivity);
|
||||
|
||||
@@ -5393,6 +5398,31 @@ void GMainWindow::OnOpenControllerMenu() {
|
||||
LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller));
|
||||
}
|
||||
|
||||
void GMainWindow::OnQLaunch() {
|
||||
if (!Settings::values.qlaunch_enabled.GetValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::QLaunch);
|
||||
auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
|
||||
if (!bis_system) {
|
||||
QMessageBox::warning(this, tr("No firmware available"),
|
||||
tr("Please install firmware to use the Home Menu."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto qlaunch_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
|
||||
if (!qlaunch_nca) {
|
||||
QMessageBox::warning(this, tr("Home Menu"),
|
||||
tr("QLaunch applet not found. Please reinstall firmware."));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto filename = QString::fromStdString(qlaunch_nca->GetFullPath());
|
||||
UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
|
||||
BootGame(filename, SystemAppletParameters(QLaunchId, Service::AM::AppletId::QLaunch));
|
||||
}
|
||||
|
||||
void GMainWindow::OnCaptureScreenshot() {
|
||||
if (emu_thread == nullptr || !emu_thread->IsRunning() || !render_window->IsLoadingComplete()) {
|
||||
return;
|
||||
@@ -6110,6 +6140,22 @@ Service::AM::FrontendAppletParameters GMainWindow::LibraryAppletParameters(
|
||||
};
|
||||
}
|
||||
|
||||
Service::AM::FrontendAppletParameters GMainWindow::SystemAppletParameters(
|
||||
u64 program_id, Service::AM::AppletId applet_id) {
|
||||
return Service::AM::FrontendAppletParameters{
|
||||
.program_id = program_id,
|
||||
.applet_id = applet_id,
|
||||
.applet_type = Service::AM::AppletType::SystemApplet,
|
||||
};
|
||||
}
|
||||
|
||||
void GMainWindow::SetupHomeMenuCallback() {
|
||||
system->GetAppletManager().SetHomeMenuRequestCallback([this]() {
|
||||
// Use Qt's thread-safe invocation to call OnQLaunch from the main thread
|
||||
QMetaObject::invokeMethod(this, "OnQLaunch", Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void VolumeButton::wheelEvent(QWheelEvent* event) {
|
||||
|
||||
int num_degrees = event->angleDelta().y() / 8;
|
||||
|
||||
@@ -201,6 +201,8 @@ private:
|
||||
Core::PerfStatsResults last_perf_stats{};
|
||||
Service::AM::FrontendAppletParameters ApplicationAppletParameters();
|
||||
Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id, Service::AM::AppletId applet_id);
|
||||
Service::AM::FrontendAppletParameters SystemAppletParameters(u64 program_id, Service::AM::AppletId applet_id);
|
||||
void SetupHomeMenuCallback();
|
||||
std::unique_ptr<FileSys::ManualContentProvider> autoloader_provider;
|
||||
u64 current_title_id{0};
|
||||
private slots:
|
||||
@@ -288,6 +290,7 @@ private slots:
|
||||
void OnCabinet(Service::NFP::CabinetMode mode);
|
||||
void OnMiiEdit();
|
||||
void OnOpenControllerMenu();
|
||||
void OnQLaunch();
|
||||
void OnCaptureScreenshot();
|
||||
void OnCheckFirmwareDecryption();
|
||||
void OnLanguageChanged(const QString& locale);
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
<addaction name="action_Install_Firmware"/>
|
||||
<addaction name="action_Verify_installed_contents"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Load_Home_Menu"/>
|
||||
<addaction name="menu_cabinet_applet"/>
|
||||
<addaction name="action_Load_Album"/>
|
||||
<addaction name="action_Load_Mii_Edit"/>
|
||||
@@ -487,6 +488,11 @@
|
||||
<string>Open &Mii Editor</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Load_Home_Menu">
|
||||
<property name="text">
|
||||
<string>Open &Home Menu</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Configure_Tas">
|
||||
<property name="text">
|
||||
<string>&Configure TAS...</string>
|
||||
|
||||
@@ -169,6 +169,9 @@ struct Values {
|
||||
Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode",
|
||||
Category::LibraryApplet};
|
||||
|
||||
// System Applet
|
||||
Setting<bool> qlaunch_enabled{linkage, true, "qlaunch_enabled", Category::System};
|
||||
|
||||
// Audio
|
||||
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
|
||||
Category::Audio, Specialization::RuntimeList};
|
||||
|
||||
@@ -467,6 +467,8 @@ add_library(core STATIC
|
||||
hle/service/am/service/application_creator.h
|
||||
hle/service/am/service/application_functions.cpp
|
||||
hle/service/am/service/application_functions.h
|
||||
hle/service/am/service/application_observer.cpp
|
||||
hle/service/am/service/application_observer.h
|
||||
hle/service/am/service/application_proxy.cpp
|
||||
hle/service/am/service/application_proxy.h
|
||||
hle/service/am/service/application_proxy_service.cpp
|
||||
@@ -509,6 +511,8 @@ add_library(core STATIC
|
||||
hle/service/am/service/system_applet_proxy.h
|
||||
hle/service/am/service/system_application_proxy.cpp
|
||||
hle/service/am/service/system_application_proxy.h
|
||||
hle/service/am/service/system_process_common_functions.cpp
|
||||
hle/service/am/service/system_process_common_functions.h
|
||||
hle/service/am/service/window_controller.cpp
|
||||
hle/service/am/service/window_controller.h
|
||||
hle/service/am/window_system.cpp
|
||||
|
||||
@@ -335,4 +335,11 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
|
||||
applet->process->Run();
|
||||
}
|
||||
|
||||
void AppletManager::SetHomeMenuRequestCallback(std::function<void()> callback) {
|
||||
std::unique_lock lk{m_lock};
|
||||
if (m_window_system) {
|
||||
m_window_system->SetHomeMenuRequestCallback(std::move(callback));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
@@ -46,6 +47,7 @@ public:
|
||||
|
||||
public:
|
||||
void SetWindowSystem(WindowSystem* window_system);
|
||||
void SetHomeMenuRequestCallback(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
|
||||
@@ -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 "core/core.h"
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "core/hle/service/am/service/overlay_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/system_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/system_application_proxy.h"
|
||||
#include "core/hle/service/am/service/system_process_common_functions.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
@@ -22,12 +23,15 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
|
||||
{110, D<&IAllSystemAppletProxiesService::OpenHomeMenuProxy>, "OpenHomeMenuProxy"},
|
||||
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
|
||||
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
|
||||
{300, D<&IAllSystemAppletProxiesService::OpenOverlayAppletProxy>, "OpenOverlayAppletProxy"},
|
||||
{350, D<&IAllSystemAppletProxiesService::OpenSystemApplicationProxy>, "OpenSystemApplicationProxy"},
|
||||
{400, D<&IAllSystemAppletProxiesService::CreateSelfLibraryAppletCreatorForDevelop>, "CreateSelfLibraryAppletCreatorForDevelop"},
|
||||
{410, D<&IAllSystemAppletProxiesService::GetSystemAppletControllerForDebug>, "GetSystemAppletControllerForDebug"},
|
||||
{450, D<&IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions>, "GetSystemProcessCommonFunctions"},
|
||||
{460, D<&IAllSystemAppletProxiesService::Cmd460>, "Cmd460"},
|
||||
{1000, D<&IAllSystemAppletProxiesService::GetDebugFunctions>, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -52,6 +56,21 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenHomeMenuProxy(
|
||||
Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
LOG_ERROR(Service_AM, "Home menu applet doesn't exist for process_id={}", pid.pid);
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
|
||||
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle,
|
||||
@@ -130,6 +149,18 @@ Result IAllSystemAppletProxiesService::GetSystemAppletControllerForDebug() {
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions(
|
||||
Out<SharedPointer<ISystemProcessCommonFunctions>> out_system_process_common_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_system_process_common_functions = std::make_shared<ISystemProcessCommonFunctions>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::Cmd460() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::GetDebugFunctions(
|
||||
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
@@ -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
|
||||
@@ -19,6 +19,7 @@ class ILibraryAppletProxy;
|
||||
class IOverlayAppletProxy;
|
||||
class ISystemAppletProxy;
|
||||
class ISystemApplicationProxy;
|
||||
class ISystemProcessCommonFunctions;
|
||||
class WindowSystem;
|
||||
|
||||
class IAllSystemAppletProxiesService final
|
||||
@@ -31,6 +32,9 @@ private:
|
||||
Result OpenSystemAppletProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy,
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result OpenHomeMenuProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy,
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result OpenLibraryAppletProxy(Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy,
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle,
|
||||
@@ -49,6 +53,9 @@ private:
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result GetSystemAppletControllerForDebug();
|
||||
Result GetSystemProcessCommonFunctions(
|
||||
Out<SharedPointer<ISystemProcessCommonFunctions>> out_system_process_common_functions);
|
||||
Result Cmd460();
|
||||
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// 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/am/am_types.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
@@ -28,10 +30,24 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
|
||||
{70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"},
|
||||
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
|
||||
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
|
||||
{82, nullptr, "SetBlockingCaptureButtonInEntireSystem"},
|
||||
{90, nullptr, "OpenNamedChannelAsParent"},
|
||||
{91, nullptr, "OpenNamedChannelAsChild"},
|
||||
{100, nullptr, "SetApplicationCoreUsageMode"},
|
||||
{160, nullptr, "GetNotificationReceiverService"},
|
||||
{161, nullptr, "GetNotificationSenderService"},
|
||||
{300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
|
||||
{310, D<&IAppletCommonFunctions::IsSystemAppletHomeMenu>, "IsSystemAppletHomeMenu"},
|
||||
{311, D<&IAppletCommonFunctions::Cmd311>, "Cmd311"},
|
||||
{320, D<&IAppletCommonFunctions::SetGpuTimeSliceBoost>, "SetGpuTimeSliceBoost"},
|
||||
{321, D<&IAppletCommonFunctions::SetGpuTimeSliceBoostDueToApplication>, "SetGpuTimeSliceBoostDueToApplication"},
|
||||
{322, D<&IAppletCommonFunctions::Cmd322>, "Cmd322"},
|
||||
{330, D<&IAppletCommonFunctions::Cmd330>, "Cmd330"},
|
||||
{340, D<&IAppletCommonFunctions::Cmd340>, "Cmd340"},
|
||||
{341, D<&IAppletCommonFunctions::Cmd341>, "Cmd341"},
|
||||
{342, D<&IAppletCommonFunctions::Cmd342>, "Cmd342"},
|
||||
{350, D<&IAppletCommonFunctions::Cmd350>, "Cmd350"},
|
||||
{360, D<&IAppletCommonFunctions::Cmd360>, "Cmd360"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -67,4 +83,60 @@ Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::IsSystemAppletHomeMenu(Out<bool> out_is_home_menu) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
|
||||
*out_is_home_menu = applet->applet_id == AppletId::QLaunch;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd311() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::SetGpuTimeSliceBoost(u64 boost) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, boost={} [19.0.0+]", boost);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::SetGpuTimeSliceBoostDueToApplication(u64 boost) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, boost={} [19.0.0+]", boost);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd322() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd330() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd340() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd341() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd342() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd350() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Cmd360() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -20,6 +20,17 @@ private:
|
||||
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
|
||||
Result SetCpuBoostRequestPriority(s32 priority);
|
||||
Result GetCurrentApplicationId(Out<u64> out_application_id);
|
||||
Result IsSystemAppletHomeMenu(Out<bool> out_is_home_menu);
|
||||
Result Cmd311();
|
||||
Result SetGpuTimeSliceBoost(u64 boost);
|
||||
Result SetGpuTimeSliceBoostDueToApplication(u64 boost);
|
||||
Result Cmd322();
|
||||
Result Cmd330();
|
||||
Result Cmd340();
|
||||
Result Cmd341();
|
||||
Result Cmd342();
|
||||
Result Cmd350();
|
||||
Result Cmd360();
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
@@ -47,6 +47,8 @@ IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_pt
|
||||
{190, nullptr, "PushToNotificationStorageChannel"},
|
||||
{200, nullptr, "RequestApplicationSoftReset"},
|
||||
{201, nullptr, "RestartApplicationTimer"},
|
||||
{300, D<&IApplicationAccessor::Cmd300>, "Cmd300"},
|
||||
{301, D<&IApplicationAccessor::Cmd301>, "Cmd301"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -156,4 +158,14 @@ Result IApplicationAccessor::ReportApplicationExitTimeout() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationAccessor::Cmd300() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationAccessor::Cmd301() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -35,6 +35,8 @@ private:
|
||||
Result CheckRightsEnvironmentAvailable(Out<bool> out_is_available);
|
||||
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
|
||||
Result ReportApplicationExitTimeout();
|
||||
Result Cmd300();
|
||||
Result Cmd301();
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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/settings.h"
|
||||
@@ -69,6 +69,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
|
||||
{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
|
||||
{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
|
||||
{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
|
||||
{112, D<&IApplicationFunctions::Cmd112>, "Cmd112"},
|
||||
{113, D<&IApplicationFunctions::Cmd113>, "Cmd113"},
|
||||
{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
|
||||
{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
|
||||
{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
|
||||
@@ -88,7 +90,10 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"},
|
||||
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"},
|
||||
{220, D<&IApplicationFunctions::Cmd220>, "Cmd220"},
|
||||
{300, nullptr, "RequestToLaunchApplication"},
|
||||
{310, D<&IApplicationFunctions::Cmd310>, "Cmd310"},
|
||||
{320, D<&IApplicationFunctions::Cmd320>, "Cmd320"},
|
||||
{301, nullptr, "RequestToLaunchApplicationWithUserAndArguments"},
|
||||
{310, nullptr, "RequestToLaunchApplicationWithArgumentsAndUserSelectionAndError"},
|
||||
{330, D<&IApplicationFunctions::Unknown330>, "Unknown330"}, // [20.2.0+]
|
||||
@@ -532,4 +537,29 @@ Result IApplicationFunctions::Unknown330() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::Cmd112() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::Cmd113() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::Cmd220() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::Cmd310() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::Cmd320() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -79,6 +79,11 @@ private:
|
||||
Result PrepareForJit();
|
||||
Result GetLaunchRequiredVersionUpgrade(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result Unknown330(); // [20.2.0+]
|
||||
Result Cmd112();
|
||||
Result Cmd113();
|
||||
Result Cmd220();
|
||||
Result Cmd310();
|
||||
Result Cmd320();
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
25
src/core/hle/service/am/service/application_observer.cpp
Normal file
25
src/core/hle/service/am/service/application_observer.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/application_observer.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationObserver::IApplicationObserver(Core::System& system_)
|
||||
: ServiceFramework{system_, "IApplicationObserver"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{20, nullptr, "Unknown20"},
|
||||
{30, nullptr, "Unknown30"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationObserver::~IApplicationObserver() = default;
|
||||
|
||||
} // namespace Service::AM
|
||||
16
src/core/hle/service/am/service/application_observer.h
Normal file
16
src/core/hle/service/am/service/application_observer.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IApplicationObserver final : public ServiceFramework<IApplicationObserver> {
|
||||
public:
|
||||
explicit IApplicationObserver(Core::System& system_);
|
||||
~IApplicationObserver() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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/settings.h"
|
||||
@@ -82,13 +82,13 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
|
||||
{1001, nullptr, "GetScreenShotPermission"},
|
||||
{1010, nullptr, "GetNextProgramArgumentInfo"},
|
||||
{1011, nullptr, "GetPreviousProgramArgumentInfo"},
|
||||
{1020, nullptr, "GetGpuErrorDetectedSystemEvent"},
|
||||
{1020, D<&ICommonStateGetter::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
|
||||
{1021, nullptr, "SetDelayTimeToAbortOnGpuError"},
|
||||
{1030, nullptr, "GetFriendInvitationStorageChannelEvent"},
|
||||
{1030, D<&ICommonStateGetter::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
|
||||
{1031, nullptr, "TryPopFromFriendInvitationStorageChannel"},
|
||||
{1040, nullptr, "GetNotificationStorageChannelEvent"},
|
||||
{1040, D<&ICommonStateGetter::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
|
||||
{1041, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{1050, nullptr, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{1050, D<&ICommonStateGetter::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{1060, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{1061, nullptr, "GetLastForegroundCaptureImageEx"},
|
||||
{1062, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
@@ -297,4 +297,32 @@ Result ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnab
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::GetGpuErrorDetectedSystemEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->gpu_error_detected_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::GetFriendInvitationStorageChannelEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->friend_invitation_storage_channel_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::GetNotificationStorageChannelEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->notification_storage_channel_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::GetHealthWarningDisappearedSystemEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->health_warning_disappeared_system_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -53,6 +53,10 @@ private:
|
||||
OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
|
||||
Result GetSettingsPlatformRegion(Out<Set::PlatformRegion> out_settings_platform_region);
|
||||
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
|
||||
Result GetGpuErrorDetectedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetFriendInvitationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
|
||||
|
||||
@@ -31,7 +31,13 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
|
||||
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
|
||||
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
|
||||
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
|
||||
{410, nullptr, "CreateGeneralStorageForDebug"},
|
||||
{411, nullptr, "ReadGeneralStorageForDebug"},
|
||||
{412, nullptr, "WriteGeneralStorageForDebug"},
|
||||
{430, nullptr, "Cmd430"},
|
||||
{431, nullptr, "Cmd431"},
|
||||
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
|
||||
{910, nullptr, "Cmd910"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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 "core/hle/service/am/service/cradle_firmware_updater.h"
|
||||
@@ -10,7 +10,8 @@ namespace Service::AM {
|
||||
|
||||
IGlobalStateController::IGlobalStateController(Core::System& system_)
|
||||
: ServiceFramework{system_, "IGlobalStateController"},
|
||||
m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context} {
|
||||
m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context},
|
||||
m_accumulated_suspended_tick_changed_event{m_context} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IGlobalStateController::RequestToEnterSleep>, "RequestToEnterSleep"},
|
||||
@@ -35,7 +36,7 @@ IGlobalStateController::IGlobalStateController(Core::System& system_)
|
||||
{60, nullptr, "SetWirelessPriorityMode"},
|
||||
{61, nullptr, "GetWirelessPriorityMode"},
|
||||
{62, nullptr, "GetAccumulatedSuspendedTickValue"},
|
||||
{63, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{63, D<&IGlobalStateController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{64, nullptr, "SetAlarmTimeChangeEvent"},
|
||||
{65, nullptr, "GetWakeupCount"},
|
||||
{66, nullptr, "GetHomeButtonInputProtectionStartTime"},
|
||||
@@ -130,4 +131,11 @@ Result IGlobalStateController::UpdateDefaultDisplayResolution() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IGlobalStateController::GetAccumulatedSuspendedTickChangedEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_accumulated_suspended_tick_changed_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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
|
||||
@@ -33,9 +33,11 @@ private:
|
||||
Result GetHdcpAuthenticationFailedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result OpenCradleFirmwareUpdater(
|
||||
Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater);
|
||||
Result GetAccumulatedSuspendedTickChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
Event m_hdcp_authentication_failed_event;
|
||||
Event m_accumulated_suspended_tick_changed_event;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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 "core/hle/result.h"
|
||||
@@ -31,6 +31,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Ap
|
||||
{41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
|
||||
{50, D<&IHomeMenuFunctions::LaunchSystemApplet>, "LaunchSystemApplet"},
|
||||
{51, D<&IHomeMenuFunctions::LaunchStarter>, "LaunchStarter"},
|
||||
{60, D<&IHomeMenuFunctions::Cmd60>, "Cmd60"},
|
||||
{61, D<&IHomeMenuFunctions::Cmd61>, "Cmd61"},
|
||||
{100, D<&IHomeMenuFunctions::PopRequestLaunchApplicationForDebug>, "PopRequestLaunchApplicationForDebug"},
|
||||
{110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
|
||||
{200, D<&IHomeMenuFunctions::LaunchDevMenu>, "LaunchDevMenu"},
|
||||
@@ -149,4 +151,14 @@ Result IHomeMenuFunctions::SetLastApplicationExitReason(s32 exit_reason) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IHomeMenuFunctions::Cmd60() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IHomeMenuFunctions::Cmd61() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [19.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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
|
||||
@@ -39,6 +39,8 @@ private:
|
||||
Out<bool> out_is_force_terminate_application_disabled_for_debug);
|
||||
Result LaunchDevMenu();
|
||||
Result SetLastApplicationExitReason(s32 exit_reason);
|
||||
Result Cmd60();
|
||||
Result Cmd61();
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 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"
|
||||
@@ -74,9 +74,12 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
|
||||
{160, nullptr, "SetCpuBoostRequestPriority"},
|
||||
{170, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
{180, nullptr, "GetOperationModeSystemInfo"},
|
||||
{200, nullptr, "GetSettingsPlatformRegion"},
|
||||
{210, nullptr, "ActivateMigrationService"},
|
||||
{211, nullptr, "DeactivateMigrationService"},
|
||||
{200, D<&ISelfController::Cmd200>, "Cmd200"},
|
||||
{210, D<&ISelfController::Cmd210>, "Cmd210"},
|
||||
{211, D<&ISelfController::Cmd211>, "Cmd211"},
|
||||
{220, D<&ISelfController::Cmd220>, "Cmd220"},
|
||||
{221, D<&ISelfController::Cmd221>, "Cmd221"},
|
||||
{230, D<&ISelfController::Cmd230>, "Cmd230"},
|
||||
{300, nullptr, "SendMessage"},
|
||||
{301, nullptr, "ReceiveMessage"},
|
||||
{400, nullptr, "CreateAlbumAccessorApplicationAlbumEntry"},
|
||||
@@ -424,4 +427,34 @@ Result ISelfController::SetRecordVolumeMuted(bool muted) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd200() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd210() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd211() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd220() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd221() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Cmd230() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called [20.0.0+]");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -63,6 +63,12 @@ private:
|
||||
Result SetAlbumImageTakenNotificationEnabled(bool enabled);
|
||||
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
|
||||
Result SetRecordVolumeMuted(bool muted);
|
||||
Result Cmd200();
|
||||
Result Cmd210();
|
||||
Result Cmd211();
|
||||
Result Cmd220();
|
||||
Result Cmd221();
|
||||
Result Cmd230();
|
||||
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/application_observer.h"
|
||||
#include "core/hle/service/am/service/system_process_common_functions.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ISystemProcessCommonFunctions::ISystemProcessCommonFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "ISystemProcessCommonFunctions"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ISystemProcessCommonFunctions::GetApplicationObserver>, "GetApplicationObserver"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ISystemProcessCommonFunctions::~ISystemProcessCommonFunctions() = default;
|
||||
|
||||
Result ISystemProcessCommonFunctions::GetApplicationObserver(
|
||||
Out<SharedPointer<IApplicationObserver>> out_observer) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_observer = std::make_shared<IApplicationObserver>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IApplicationObserver;
|
||||
|
||||
class ISystemProcessCommonFunctions final
|
||||
: public ServiceFramework<ISystemProcessCommonFunctions> {
|
||||
public:
|
||||
explicit ISystemProcessCommonFunctions(Core::System& system_);
|
||||
~ISystemProcessCommonFunctions() override;
|
||||
|
||||
private:
|
||||
Result GetApplicationObserver(Out<SharedPointer<IApplicationObserver>> out_observer);
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -139,8 +139,11 @@ void WindowSystem::OnExitRequested() {
|
||||
void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
// If we don't have a home menu, nothing to do.
|
||||
// If we don't have a home menu, request frontend to launch QLaunch.
|
||||
if (!m_home_menu) {
|
||||
if (m_home_menu_request_callback && type == ButtonPressDuration::ShortPressing) {
|
||||
m_home_menu_request_callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -312,4 +315,9 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground) {
|
||||
}
|
||||
}
|
||||
|
||||
void WindowSystem::SetHomeMenuRequestCallback(HomeMenuRequestCallback callback) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
m_home_menu_request_callback = std::move(callback);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -24,6 +25,8 @@ enum class ButtonPressDuration {
|
||||
LongPressing,
|
||||
};
|
||||
|
||||
using HomeMenuRequestCallback = std::function<void()>;
|
||||
|
||||
class WindowSystem {
|
||||
public:
|
||||
explicit WindowSystem(Core::System& system);
|
||||
@@ -52,6 +55,9 @@ public:
|
||||
void OnCaptureButtonPressed(ButtonPressDuration type) {}
|
||||
void OnPowerButtonPressed(ButtonPressDuration type) {}
|
||||
|
||||
public:
|
||||
void SetHomeMenuRequestCallback(HomeMenuRequestCallback callback);
|
||||
|
||||
private:
|
||||
void PruneTerminatedAppletsLocked();
|
||||
bool LockHomeMenuIntoForegroundLocked();
|
||||
@@ -78,6 +84,9 @@ private:
|
||||
|
||||
// Applet map by aruid.
|
||||
std::map<u64, std::shared_ptr<Applet>> m_applets{};
|
||||
|
||||
// Callback for requesting home menu launch from frontend.
|
||||
HomeMenuRequestCallback m_home_menu_request_callback{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -303,6 +303,94 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{3013, nullptr, "IsGameCardEnabled"},
|
||||
{3014, nullptr, "IsLocalContentShareEnabled"},
|
||||
{3050, nullptr, "ListAssignELicenseTaskResult"},
|
||||
// [20.0.0+]
|
||||
{4000, nullptr, "Cmd4000"},
|
||||
{4004, nullptr, "Cmd4004"},
|
||||
{4006, nullptr, "Cmd4006"},
|
||||
{4007, nullptr, "Cmd4007"},
|
||||
{4008, nullptr, "Cmd4008"},
|
||||
{4009, nullptr, "Cmd4009"},
|
||||
{4010, nullptr, "Cmd4010"},
|
||||
{4011, nullptr, "Cmd4011"},
|
||||
{4012, nullptr, "Cmd4012"},
|
||||
{4013, nullptr, "Cmd4013"},
|
||||
{4015, nullptr, "Cmd4015"},
|
||||
{4017, nullptr, "Cmd4017"},
|
||||
{4019, nullptr, "Cmd4019"},
|
||||
{4020, nullptr, "Cmd4020"},
|
||||
{4021, nullptr, "Cmd4021"},
|
||||
{4022, D<&IApplicationManagerInterface::Cmd4022>, "Cmd4022"},
|
||||
{4023, D<&IApplicationManagerInterface::Cmd4023>, "Cmd4023"},
|
||||
{4024, nullptr, "Cmd4024"},
|
||||
{4025, nullptr, "Cmd4025"},
|
||||
{4026, nullptr, "Cmd4026"},
|
||||
{4027, nullptr, "Cmd4027"},
|
||||
{4028, nullptr, "Cmd4028"},
|
||||
{4029, nullptr, "Cmd4029"},
|
||||
{4030, nullptr, "Cmd4030"},
|
||||
{4031, nullptr, "Cmd4031"},
|
||||
{4032, nullptr, "Cmd4032"},
|
||||
{4033, nullptr, "Cmd4033"},
|
||||
{4034, nullptr, "Cmd4034"},
|
||||
{4035, nullptr, "Cmd4035"},
|
||||
{4037, nullptr, "Cmd4037"},
|
||||
{4038, nullptr, "Cmd4038"},
|
||||
{4039, nullptr, "Cmd4039"},
|
||||
{4040, nullptr, "Cmd4040"},
|
||||
{4041, nullptr, "Cmd4041"},
|
||||
{4042, nullptr, "Cmd4042"},
|
||||
{4043, nullptr, "Cmd4043"},
|
||||
{4044, nullptr, "Cmd4044"},
|
||||
{4045, nullptr, "Cmd4045"},
|
||||
{4046, nullptr, "Cmd4046"},
|
||||
{4049, nullptr, "Cmd4049"},
|
||||
{4050, nullptr, "Cmd4050"},
|
||||
{4051, nullptr, "Cmd4051"},
|
||||
{4052, nullptr, "Cmd4052"},
|
||||
{4053, nullptr, "Cmd4053"},
|
||||
{4054, nullptr, "Cmd4054"},
|
||||
{4055, nullptr, "Cmd4055"},
|
||||
{4056, nullptr, "Cmd4056"},
|
||||
{4057, nullptr, "Cmd4057"},
|
||||
{4058, nullptr, "Cmd4058"},
|
||||
{4059, nullptr, "Cmd4059"},
|
||||
{4060, nullptr, "Cmd4060"},
|
||||
{4061, nullptr, "Cmd4061"},
|
||||
{4062, nullptr, "Cmd4062"},
|
||||
{4063, nullptr, "Cmd4063"},
|
||||
{4064, nullptr, "Cmd4064"},
|
||||
{4065, nullptr, "Cmd4065"},
|
||||
{4066, nullptr, "Cmd4066"},
|
||||
{4067, nullptr, "Cmd4067"},
|
||||
{4068, nullptr, "Cmd4068"},
|
||||
{4069, nullptr, "Cmd4069"},
|
||||
{4070, nullptr, "Cmd4070"},
|
||||
{4071, nullptr, "Cmd4071"},
|
||||
{4072, nullptr, "Cmd4072"},
|
||||
{4073, nullptr, "Cmd4073"},
|
||||
{4074, nullptr, "Cmd4074"},
|
||||
{4075, nullptr, "Cmd4075"},
|
||||
{4076, nullptr, "Cmd4076"},
|
||||
{4077, nullptr, "Cmd4077"},
|
||||
{4078, nullptr, "Cmd4078"},
|
||||
{4079, nullptr, "Cmd4079"},
|
||||
{4080, nullptr, "Cmd4080"},
|
||||
{4081, nullptr, "Cmd4081"},
|
||||
{4083, nullptr, "Cmd4083"},
|
||||
{4084, nullptr, "Cmd4084"},
|
||||
{4085, nullptr, "Cmd4085"},
|
||||
{4086, nullptr, "Cmd4086"},
|
||||
{4087, nullptr, "Cmd4087"},
|
||||
{4088, D<&IApplicationManagerInterface::Cmd4088>, "Cmd4088"},
|
||||
{4089, nullptr, "Cmd4089"},
|
||||
{4090, nullptr, "Cmd4090"},
|
||||
{4091, nullptr, "Cmd4091"},
|
||||
{4092, nullptr, "Cmd4092"},
|
||||
{4093, nullptr, "Cmd4093"},
|
||||
{4094, nullptr, "Cmd4094"},
|
||||
{4095, nullptr, "Cmd4095"},
|
||||
{4096, nullptr, "Cmd4096"},
|
||||
{4097, nullptr, "Cmd4097"},
|
||||
{9999, nullptr, "GetApplicationCertificate"},
|
||||
};
|
||||
// clang-format on
|
||||
@@ -516,4 +604,24 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> o
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationManagerInterface::Cmd4022(Out<u64> out_result) {
|
||||
LOG_DEBUG(Service_NS, "(STUBBED) called [20.0.0+]");
|
||||
// Return 0 to indicate no pending operations / ready state
|
||||
*out_result = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationManagerInterface::Cmd4023(Out<u64> out_result) {
|
||||
LOG_DEBUG(Service_NS, "(STUBBED) called [20.0.0+]");
|
||||
// Return 0 to indicate no pending operations / ready state
|
||||
*out_result = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationManagerInterface::Cmd4088(Out<u64> out_result) {
|
||||
LOG_DEBUG(Service_NS, "(STUBBED) called [20.0.0+]");
|
||||
*out_result = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::NS
|
||||
|
||||
@@ -50,6 +50,11 @@ public:
|
||||
Result CheckApplicationLaunchVersion(u64 application_id);
|
||||
Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
|
||||
|
||||
// [20.0.0+] Stub functions for QLaunch compatibility
|
||||
Result Cmd4022(Out<u64> out_result);
|
||||
Result Cmd4023(Out<u64> out_result);
|
||||
Result Cmd4088(Out<u64> out_result);
|
||||
|
||||
private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Event record_update_system_event;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace Service::PCTL {
|
||||
IParentalControlService::IParentalControlService(Core::System& system_, Capability capability_)
|
||||
: ServiceFramework{system_, "IParentalControlService"}, capability{capability_},
|
||||
service_context{system_, "IParentalControlService"}, synchronization_event{service_context},
|
||||
unlinked_event{service_context}, request_suspension_event{service_context} {
|
||||
unlinked_event{service_context}, request_suspension_event{service_context},
|
||||
extended_play_timer_event{service_context} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, D<&IParentalControlService::Initialize>, "Initialize"},
|
||||
@@ -77,11 +78,12 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
|
||||
{1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
|
||||
{1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
|
||||
{1454, nullptr, "GetPlayTimerRemainingTime"},
|
||||
{1454, D<&IParentalControlService::GetPlayTimerRemainingTime>, "GetPlayTimerRemainingTime"},
|
||||
{1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
|
||||
{1456, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"},
|
||||
{1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
|
||||
{1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
|
||||
{1459, D<&IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo>, "GetPlayTimerRemainingTimeDisplayInfo"}, // [20.0.0+]
|
||||
{1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
|
||||
{1472, nullptr, "CancelNetworkRequest"},
|
||||
{1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
|
||||
@@ -117,6 +119,14 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{2014, nullptr, "FinishSynchronizeParentalControlSettings"},
|
||||
{2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
|
||||
{2016, nullptr, "RequestUpdateExemptionListAsync"},
|
||||
// [18.0.0+]
|
||||
{1475, D<&IParentalControlService::GetExtendedPlayTimerEvent>, "GetExtendedPlayTimerEvent"},
|
||||
{1954, nullptr, "IsBedtimeAlarmEnabled"},
|
||||
{1955, nullptr, "GetBedtimeAlarmTime"},
|
||||
{1956, nullptr, "GetBedtimeAlarmTimeHour"},
|
||||
{1957, nullptr, "GetBedtimeAlarmTimeMinute"},
|
||||
{145601, D<&IParentalControlService::GetPlayTimerSettingsVer2>, "GetPlayTimerSettingsVer2"},
|
||||
{195101, nullptr, "SetPlayTimerSettingsForDebugVer2"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -377,6 +387,28 @@ Result IParentalControlService::GetPlayTimerSettings(
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerRemainingTime(Out<s64> out_remaining_time) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
// Return 0 indicating no time restriction (unlimited playtime remaining)
|
||||
*out_remaining_time = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo(
|
||||
Out<PlayTimerRemainingTimeDisplayInfo> out_display_info) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called [20.0.0+]");
|
||||
// Return default values indicating no time restriction
|
||||
*out_display_info = {};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerSettingsVer2(
|
||||
Out<PlayTimerSettingsVer2> out_play_timer_settings) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called [18.0.0+]");
|
||||
*out_play_timer_settings = {};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
@@ -384,6 +416,13 @@ Result IParentalControlService::GetPlayTimerEventToRequestSuspension(
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetExtendedPlayTimerEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(Service_PCTL, "called [18.0.0+]");
|
||||
*out_event = extended_play_timer_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled) {
|
||||
*out_play_timer_alarm_disabled = false;
|
||||
LOG_INFO(Service_PCTL, "called, is_play_timer_alarm_disabled={}",
|
||||
|
||||
@@ -47,8 +47,13 @@ private:
|
||||
Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
|
||||
Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
|
||||
Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
|
||||
Result GetPlayTimerRemainingTime(Out<s64> out_remaining_time);
|
||||
Result GetPlayTimerRemainingTimeDisplayInfo(
|
||||
Out<PlayTimerRemainingTimeDisplayInfo> out_display_info);
|
||||
Result GetPlayTimerSettingsVer2(Out<PlayTimerSettingsVer2> out_play_timer_settings);
|
||||
Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
|
||||
Result GetExtendedPlayTimerEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
|
||||
Result SetStereoVisionRestriction(bool stereo_vision_restriction);
|
||||
@@ -81,6 +86,7 @@ private:
|
||||
Event synchronization_event;
|
||||
Event unlinked_event;
|
||||
Event request_suspension_event;
|
||||
Event extended_play_timer_event;
|
||||
};
|
||||
|
||||
} // namespace Service::PCTL
|
||||
|
||||
@@ -40,4 +40,28 @@ struct PlayTimerSettings {
|
||||
};
|
||||
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
|
||||
|
||||
// This is nn::pctl::PlayTimerSettingsVer2 [18.0.0+]
|
||||
// Extended version with bedtime alarm settings
|
||||
struct PlayTimerSettingsVer2 {
|
||||
PlayTimerSettings base_settings;
|
||||
bool bedtime_alarm_enabled;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u32 bedtime_alarm_hour;
|
||||
u32 bedtime_alarm_minute;
|
||||
INSERT_PADDING_BYTES(4);
|
||||
};
|
||||
static_assert(sizeof(PlayTimerSettingsVer2) == 0x44, "PlayTimerSettingsVer2 has incorrect size.");
|
||||
|
||||
// This is nn::pctl::PlayTimerRemainingTimeDisplayInfo [20.0.0+]
|
||||
struct PlayTimerRemainingTimeDisplayInfo {
|
||||
s64 remaining_time_ns; // Remaining time in nanoseconds
|
||||
u32 display_hours; // Hours to display
|
||||
u32 display_minutes; // Minutes to display
|
||||
bool is_restricted; // Whether play time is restricted
|
||||
bool alarm_active; // Whether the alarm is active
|
||||
INSERT_PADDING_BYTES(6);
|
||||
};
|
||||
static_assert(sizeof(PlayTimerRemainingTimeDisplayInfo) == 0x18,
|
||||
"PlayTimerRemainingTimeDisplayInfo has incorrect size.");
|
||||
|
||||
} // namespace Service::PCTL
|
||||
|
||||
@@ -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