61 changed files with 4093 additions and 3482 deletions
-
45src/core/CMakeLists.txt
-
2677src/core/hle/service/am/am.cpp
-
454src/core/hle/service/am/am.h
-
14src/core/hle/service/am/am_results.h
-
258src/core/hle/service/am/applet_ae.cpp
-
47src/core/hle/service/am/applet_common_functions.cpp
-
19src/core/hle/service/am/applet_common_functions.h
-
68src/core/hle/service/am/applet_message_queue.cpp
-
75src/core/hle/service/am/applet_message_queue.h
-
100src/core/hle/service/am/applet_oe.cpp
-
6src/core/hle/service/am/applets/applet_cabinet.cpp
-
1src/core/hle/service/am/applets/applet_controller.cpp
-
1src/core/hle/service/am/applets/applet_error.cpp
-
1src/core/hle/service/am/applets/applet_general_backend.cpp
-
1src/core/hle/service/am/applets/applet_mii_edit.cpp
-
1src/core/hle/service/am/applets/applet_profile_select.cpp
-
1src/core/hle/service/am/applets/applet_software_keyboard.cpp
-
1src/core/hle/service/am/applets/applet_web_browser.cpp
-
6src/core/hle/service/am/applets/applets.cpp
-
25src/core/hle/service/am/application_creator.cpp
-
16src/core/hle/service/am/application_creator.h
-
610src/core/hle/service/am/application_functions.cpp
-
63src/core/hle/service/am/application_functions.h
-
114src/core/hle/service/am/application_proxy.cpp
-
32src/core/hle/service/am/application_proxy.h
-
91src/core/hle/service/am/audio_controller.cpp
-
36src/core/hle/service/am/audio_controller.h
-
288src/core/hle/service/am/common_state_getter.cpp
-
78src/core/hle/service/am/common_state_getter.h
-
44src/core/hle/service/am/debug_functions.cpp
-
16src/core/hle/service/am/debug_functions.h
-
97src/core/hle/service/am/display_controller.cpp
-
24src/core/hle/service/am/display_controller.h
-
34src/core/hle/service/am/global_state_controller.cpp
-
16src/core/hle/service/am/global_state_controller.h
-
57src/core/hle/service/am/home_menu_functions.cpp
-
25src/core/hle/service/am/home_menu_functions.h
-
178src/core/hle/service/am/library_applet_accessor.cpp
-
34src/core/hle/service/am/library_applet_accessor.h
-
145src/core/hle/service/am/library_applet_creator.cpp
-
22src/core/hle/service/am/library_applet_creator.h
-
142src/core/hle/service/am/library_applet_proxy.cpp
-
35src/core/hle/service/am/library_applet_proxy.h
-
382src/core/hle/service/am/library_applet_self_accessor.cpp
-
38src/core/hle/service/am/library_applet_self_accessor.h
-
71src/core/hle/service/am/lock_accessor.cpp
-
28src/core/hle/service/am/lock_accessor.h
-
73src/core/hle/service/am/process_winding_controller.cpp
-
20src/core/hle/service/am/process_winding_controller.h
-
438src/core/hle/service/am/self_controller.cpp
-
72src/core/hle/service/am/self_controller.h
-
60src/core/hle/service/am/storage.cpp
-
42src/core/hle/service/am/storage.h
-
82src/core/hle/service/am/storage_accessor.cpp
-
24src/core/hle/service/am/storage_accessor.h
-
135src/core/hle/service/am/system_applet_proxy.cpp
-
34src/core/hle/service/am/system_applet_proxy.h
-
55src/core/hle/service/am/window_controller.cpp
-
21src/core/hle/service/am/window_controller.h
-
1src/yuzu/configuration/configure_input.cpp
-
1src/yuzu/main.cpp
2677
src/core/hle/service/am/am.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,14 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/result.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2}; |
|||
constexpr Result ResultNoMessages{ErrorModule::AM, 3}; |
|||
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,47 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applet_common_functions.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) |
|||
: ServiceFramework{system_, "IAppletCommonFunctions"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "SetTerminateResult"}, |
|||
{10, nullptr, "ReadThemeStorage"}, |
|||
{11, nullptr, "WriteThemeStorage"}, |
|||
{20, nullptr, "PushToAppletBoundChannel"}, |
|||
{21, nullptr, "TryPopFromAppletBoundChannel"}, |
|||
{40, nullptr, "GetDisplayLogicalResolution"}, |
|||
{42, nullptr, "SetDisplayMagnification"}, |
|||
{50, nullptr, "SetHomeButtonDoubleClickEnabled"}, |
|||
{51, nullptr, "GetHomeButtonDoubleClickEnabled"}, |
|||
{52, nullptr, "IsHomeButtonShortPressedBlocked"}, |
|||
{60, nullptr, "IsVrModeCurtainRequired"}, |
|||
{61, nullptr, "IsSleepRequiredByHighTemperature"}, |
|||
{62, nullptr, "IsSleepRequiredByLowBattery"}, |
|||
{70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"}, |
|||
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"}, |
|||
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"}, |
|||
{90, nullptr, "OpenNamedChannelAsParent"}, |
|||
{91, nullptr, "OpenNamedChannelAsChild"}, |
|||
{100, nullptr, "SetApplicationCoreUsageMode"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IAppletCommonFunctions::~IAppletCommonFunctions() = default; |
|||
|
|||
void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,19 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> { |
|||
public: |
|||
explicit IAppletCommonFunctions(Core::System& system_); |
|||
~IAppletCommonFunctions() override; |
|||
|
|||
private: |
|||
void SetCpuBoostRequestPriority(HLERequestContext& ctx); |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,68 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applet_message_queue.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
AppletMessageQueue::AppletMessageQueue(Core::System& system) |
|||
: service_context{system, "AppletMessageQueue"} { |
|||
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); |
|||
on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged"); |
|||
} |
|||
|
|||
AppletMessageQueue::~AppletMessageQueue() { |
|||
service_context.CloseEvent(on_new_message); |
|||
service_context.CloseEvent(on_operation_mode_changed); |
|||
} |
|||
|
|||
Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() { |
|||
return on_new_message->GetReadableEvent(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() { |
|||
return on_operation_mode_changed->GetReadableEvent(); |
|||
} |
|||
|
|||
void AppletMessageQueue::PushMessage(AppletMessage msg) { |
|||
messages.push(msg); |
|||
on_new_message->Signal(); |
|||
} |
|||
|
|||
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { |
|||
if (messages.empty()) { |
|||
on_new_message->Clear(); |
|||
return AppletMessage::None; |
|||
} |
|||
auto msg = messages.front(); |
|||
messages.pop(); |
|||
if (messages.empty()) { |
|||
on_new_message->Clear(); |
|||
} |
|||
return msg; |
|||
} |
|||
|
|||
std::size_t AppletMessageQueue::GetMessageCount() const { |
|||
return messages.size(); |
|||
} |
|||
|
|||
void AppletMessageQueue::RequestExit() { |
|||
PushMessage(AppletMessage::Exit); |
|||
} |
|||
|
|||
void AppletMessageQueue::RequestResume() { |
|||
PushMessage(AppletMessage::Resume); |
|||
} |
|||
|
|||
void AppletMessageQueue::FocusStateChanged() { |
|||
PushMessage(AppletMessage::FocusStateChanged); |
|||
} |
|||
|
|||
void AppletMessageQueue::OperationModeChanged() { |
|||
PushMessage(AppletMessage::OperationModeChanged); |
|||
PushMessage(AppletMessage::PerformanceModeChanged); |
|||
on_operation_mode_changed->Signal(); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,75 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <queue> |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KReadableEvent; |
|||
} // namespace Kernel |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class AppletMessageQueue { |
|||
public: |
|||
// This is nn::am::AppletMessage |
|||
enum class AppletMessage : u32 { |
|||
None = 0, |
|||
ChangeIntoForeground = 1, |
|||
ChangeIntoBackground = 2, |
|||
Exit = 4, |
|||
ApplicationExited = 6, |
|||
FocusStateChanged = 15, |
|||
Resume = 16, |
|||
DetectShortPressingHomeButton = 20, |
|||
DetectLongPressingHomeButton = 21, |
|||
DetectShortPressingPowerButton = 22, |
|||
DetectMiddlePressingPowerButton = 23, |
|||
DetectLongPressingPowerButton = 24, |
|||
RequestToPrepareSleep = 25, |
|||
FinishedSleepSequence = 26, |
|||
SleepRequiredByHighTemperature = 27, |
|||
SleepRequiredByLowBattery = 28, |
|||
AutoPowerDown = 29, |
|||
OperationModeChanged = 30, |
|||
PerformanceModeChanged = 31, |
|||
DetectReceivingCecSystemStandby = 32, |
|||
SdCardRemoved = 33, |
|||
LaunchApplicationRequested = 50, |
|||
RequestToDisplay = 51, |
|||
ShowApplicationLogo = 55, |
|||
HideApplicationLogo = 56, |
|||
ForceHideApplicationLogo = 57, |
|||
FloatingApplicationDetected = 60, |
|||
DetectShortPressingCaptureButton = 90, |
|||
AlbumScreenShotTaken = 92, |
|||
AlbumRecordingSaved = 93, |
|||
}; |
|||
|
|||
explicit AppletMessageQueue(Core::System& system); |
|||
~AppletMessageQueue(); |
|||
|
|||
Kernel::KReadableEvent& GetMessageReceiveEvent(); |
|||
Kernel::KReadableEvent& GetOperationModeChangedEvent(); |
|||
void PushMessage(AppletMessage msg); |
|||
AppletMessage PopMessage(); |
|||
std::size_t GetMessageCount() const; |
|||
void RequestExit(); |
|||
void RequestResume(); |
|||
void FocusStateChanged(); |
|||
void OperationModeChanged(); |
|||
|
|||
private: |
|||
KernelHelpers::ServiceContext service_context; |
|||
|
|||
Kernel::KEvent* on_new_message; |
|||
Kernel::KEvent* on_operation_mode_changed; |
|||
|
|||
std::queue<AppletMessage> messages; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,25 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/application_creator.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IApplicationCreator::IApplicationCreator(Core::System& system_) |
|||
: ServiceFramework{system_, "IApplicationCreator"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "CreateApplication"}, |
|||
{1, nullptr, "PopLaunchRequestedApplication"}, |
|||
{10, nullptr, "CreateSystemApplication"}, |
|||
{100, nullptr, "PopFloatingApplicationForDevelopment"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IApplicationCreator::~IApplicationCreator() = default; |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,16 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { |
|||
public: |
|||
explicit IApplicationCreator(Core::System& system_); |
|||
~IApplicationCreator() override; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,610 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/settings.h"
|
|||
#include "common/uuid.h"
|
|||
#include "core/file_sys/control_metadata.h"
|
|||
#include "core/file_sys/patch_manager.h"
|
|||
#include "core/file_sys/registered_cache.h"
|
|||
#include "core/file_sys/savedata_factory.h"
|
|||
#include "core/hle/service/acc/profile_manager.h"
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/application_functions.h"
|
|||
#include "core/hle/service/am/storage.h"
|
|||
#include "core/hle/service/filesystem/filesystem.h"
|
|||
#include "core/hle/service/filesystem/save_data_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/ns/ns.h"
|
|||
#include "core/hle/service/sm/sm.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
enum class LaunchParameterKind : u32 { |
|||
UserChannel = 1, |
|||
AccountPreselectedUser = 2, |
|||
}; |
|||
|
|||
constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; |
|||
|
|||
struct LaunchParameterAccountPreselectedUser { |
|||
u32_le magic; |
|||
u32_le is_account_selected; |
|||
Common::UUID current_user; |
|||
INSERT_PADDING_BYTES(0x70); |
|||
}; |
|||
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |
|||
|
|||
IApplicationFunctions::IApplicationFunctions(Core::System& system_) |
|||
: ServiceFramework{system_, "IApplicationFunctions"}, |
|||
service_context{system, "IApplicationFunctions"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, |
|||
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, |
|||
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, |
|||
{12, nullptr, "CreateApplicationAndRequestToStart"}, |
|||
{13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"}, |
|||
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"}, |
|||
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"}, |
|||
{20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, |
|||
{21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, |
|||
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, |
|||
{23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, |
|||
{24, nullptr, "GetLaunchStorageInfoForDebug"}, |
|||
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, |
|||
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, |
|||
{27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"}, |
|||
{28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"}, |
|||
{29, nullptr, "GetCacheStorageMax"}, |
|||
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, |
|||
{31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, |
|||
{32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, |
|||
{33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, |
|||
{34, nullptr, "SelectApplicationLicense"}, |
|||
{35, nullptr, "GetDeviceSaveDataSizeMax"}, |
|||
{36, nullptr, "GetLimitedApplicationLicense"}, |
|||
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"}, |
|||
{40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, |
|||
{50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, |
|||
{60, nullptr, "SetMediaPlaybackStateForApplication"}, |
|||
{65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"}, |
|||
{66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"}, |
|||
{67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"}, |
|||
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, |
|||
{70, nullptr, "RequestToShutdown"}, |
|||
{71, nullptr, "RequestToReboot"}, |
|||
{72, nullptr, "RequestToSleep"}, |
|||
{80, nullptr, "ExitAndRequestToShowThanksMessage"}, |
|||
{90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, |
|||
{100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, |
|||
{101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"}, |
|||
{102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, |
|||
{110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, |
|||
{111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, |
|||
{120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"}, |
|||
{121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"}, |
|||
{122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"}, |
|||
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, |
|||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, |
|||
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, |
|||
{131, nullptr, "SetDelayTimeToAbortOnGpuError"}, |
|||
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, |
|||
{141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"}, |
|||
{150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"}, |
|||
{151, nullptr, "TryPopFromNotificationStorageChannel"}, |
|||
{160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"}, |
|||
{170, nullptr, "SetHdcpAuthenticationActivated"}, |
|||
{180, nullptr, "GetLaunchRequiredVersion"}, |
|||
{181, nullptr, "UpgradeLaunchRequiredVersion"}, |
|||
{190, nullptr, "SendServerMaintenanceOverlayNotification"}, |
|||
{200, nullptr, "GetLastApplicationExitReason"}, |
|||
{500, nullptr, "StartContinuousRecordingFlushForDebug"}, |
|||
{1000, nullptr, "CreateMovieMaker"}, |
|||
{1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
gpu_error_detected_event = |
|||
service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent"); |
|||
friend_invitation_storage_channel_event = |
|||
service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent"); |
|||
notification_storage_channel_event = |
|||
service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent"); |
|||
health_warning_disappeared_system_event = |
|||
service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent"); |
|||
} |
|||
|
|||
IApplicationFunctions::~IApplicationFunctions() { |
|||
service_context.CloseEvent(gpu_error_detected_event); |
|||
service_context.CloseEvent(friend_invitation_storage_channel_event); |
|||
service_context.CloseEvent(notification_storage_channel_event); |
|||
service_context.CloseEvent(health_warning_disappeared_system_event); |
|||
} |
|||
|
|||
void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto is_visible = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto kind = rp.PopEnum<LaunchParameterKind>(); |
|||
|
|||
LOG_INFO(Service_AM, "called, kind={:08X}", kind); |
|||
|
|||
if (kind == LaunchParameterKind::UserChannel) { |
|||
auto channel = system.GetUserChannel(); |
|||
if (channel.empty()) { |
|||
LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
return; |
|||
} |
|||
|
|||
auto data = channel.back(); |
|||
channel.pop_back(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(system, std::move(data)); |
|||
} else if (kind == LaunchParameterKind::AccountPreselectedUser && |
|||
!launch_popped_account_preselect) { |
|||
// TODO: Verify this is hw-accurate
|
|||
LaunchParameterAccountPreselectedUser params{}; |
|||
|
|||
params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC; |
|||
params.is_account_selected = 1; |
|||
|
|||
Account::ProfileManager profile_manager{}; |
|||
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); |
|||
ASSERT(uuid.has_value() && uuid->IsValid()); |
|||
params.current_user = *uuid; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |
|||
std::memcpy(buffer.data(), ¶ms, buffer.size()); |
|||
|
|||
rb.PushIpcInterface<IStorage>(system, std::move(buffer)); |
|||
launch_popped_account_preselect = true; |
|||
} else { |
|||
LOG_ERROR(Service_AM, "Unknown launch parameter kind."); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
} |
|||
} |
|||
|
|||
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
u128 user_id = rp.PopRaw<u128>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); |
|||
|
|||
FileSys::SaveDataAttribute attribute{}; |
|||
attribute.title_id = system.GetApplicationProcessProgramID(); |
|||
attribute.user_id = user_id; |
|||
attribute.type = FileSys::SaveDataType::SaveData; |
|||
|
|||
FileSys::VirtualDir save_data{}; |
|||
const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( |
|||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(res); |
|||
rb.Push<u64>(0); |
|||
} |
|||
|
|||
void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) { |
|||
// Takes an input u32 Result, no output.
|
|||
// For example, in some cases official apps use this with error 0x2A2 then
|
|||
// uses svcBreak.
|
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
u32 result = rp.Pop<u32>(); |
|||
LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
std::array<u8, 0x10> version_string{}; |
|||
|
|||
const auto res = [this] { |
|||
const auto title_id = system.GetApplicationProcessProgramID(); |
|||
|
|||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
|||
system.GetContentProvider()}; |
|||
auto metadata = pm.GetControlMetadata(); |
|||
if (metadata.first != nullptr) { |
|||
return metadata; |
|||
} |
|||
|
|||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
|||
system.GetFileSystemController(), |
|||
system.GetContentProvider()}; |
|||
return pm_update.GetControlMetadata(); |
|||
}(); |
|||
|
|||
if (res.first != nullptr) { |
|||
const auto& version = res.first->GetVersionString(); |
|||
std::copy(version.begin(), version.end(), version_string.begin()); |
|||
} else { |
|||
static constexpr char default_version[]{"1.0.0"}; |
|||
std::memcpy(version_string.data(), default_version, sizeof(default_version)); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(version_string); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) { |
|||
// TODO(bunnei): This should be configurable
|
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
// Get supported languages from NACP, if possible
|
|||
// Default to 0 (all languages supported)
|
|||
u32 supported_languages = 0; |
|||
|
|||
const auto res = [this] { |
|||
const auto title_id = system.GetApplicationProcessProgramID(); |
|||
|
|||
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), |
|||
system.GetContentProvider()}; |
|||
auto metadata = pm.GetControlMetadata(); |
|||
if (metadata.first != nullptr) { |
|||
return metadata; |
|||
} |
|||
|
|||
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id), |
|||
system.GetFileSystemController(), |
|||
system.GetContentProvider()}; |
|||
return pm_update.GetControlMetadata(); |
|||
}(); |
|||
|
|||
if (res.first != nullptr) { |
|||
supported_languages = res.first->GetSupportedLanguages(); |
|||
} |
|||
|
|||
// Call IApplicationManagerInterface implementation.
|
|||
auto& service_manager = system.ServiceManager(); |
|||
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2"); |
|||
auto app_man = ns_am2->GetApplicationManagerInterface(); |
|||
|
|||
// Get desired application language
|
|||
u8 desired_language{}; |
|||
const auto res_lang = |
|||
app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages); |
|||
if (res_lang != ResultSuccess) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(res_lang); |
|||
return; |
|||
} |
|||
|
|||
// Convert to settings language code.
|
|||
u64 language_code{}; |
|||
const auto res_code = |
|||
app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language); |
|||
if (res_code != ResultSuccess) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(res_code); |
|||
return; |
|||
} |
|||
|
|||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(language_code); |
|||
} |
|||
|
|||
void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
constexpr bool gameplay_recording_supported = false; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(gameplay_recording_supported); |
|||
} |
|||
|
|||
void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
|
|||
} |
|||
|
|||
void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
// Returns a 128-bit UUID
|
|||
rb.Push<u64>(0); |
|||
rb.Push<u64>(0); |
|||
} |
|||
|
|||
void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { |
|||
struct Parameters { |
|||
FileSys::SaveDataType type; |
|||
u128 user_id; |
|||
u64 new_normal_size; |
|||
u64 new_journal_size; |
|||
}; |
|||
static_assert(sizeof(Parameters) == 40); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>(); |
|||
|
|||
LOG_DEBUG(Service_AM, |
|||
"called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, " |
|||
"new_journal={:016X}", |
|||
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); |
|||
|
|||
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( |
|||
type, system.GetApplicationProcessProgramID(), user_id, |
|||
{new_normal_size, new_journal_size}); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
// The following value is used upon failure to help the system recover.
|
|||
// Since we always succeed, this should be 0.
|
|||
rb.Push<u64>(0); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { |
|||
struct Parameters { |
|||
FileSys::SaveDataType type; |
|||
u128 user_id; |
|||
}; |
|||
static_assert(sizeof(Parameters) == 24); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
const auto [type, user_id] = rp.PopRaw<Parameters>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], |
|||
user_id[0]); |
|||
|
|||
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( |
|||
type, system.GetApplicationProcessProgramID(), user_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(size.normal); |
|||
rb.Push(size.journal); |
|||
} |
|||
|
|||
void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) { |
|||
struct InputParameters { |
|||
u16 index; |
|||
s64 size; |
|||
s64 journal_size; |
|||
}; |
|||
static_assert(sizeof(InputParameters) == 24); |
|||
|
|||
struct OutputParameters { |
|||
u32 storage_target; |
|||
u64 required_size; |
|||
}; |
|||
static_assert(sizeof(OutputParameters) == 16); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
const auto params = rp.PopRaw<InputParameters>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}", |
|||
params.index, params.size, params.journal_size); |
|||
|
|||
const OutputParameters resp{ |
|||
.storage_target = 1, |
|||
.required_size = 0, |
|||
}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(resp); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
constexpr u64 size_max_normal = 0xFFFFFFF; |
|||
constexpr u64 size_max_journal = 0xFFFFFFF; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(size_max_normal); |
|||
rb.Push(size_max_journal); |
|||
} |
|||
|
|||
void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(0); |
|||
} |
|||
|
|||
void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(0); |
|||
} |
|||
|
|||
void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
[[maybe_unused]] const auto unk_1 = rp.Pop<u32>(); |
|||
[[maybe_unused]] const auto unk_2 = rp.Pop<u32>(); |
|||
const auto program_index = rp.Pop<u64>(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
system.ExecuteProgram(program_index); |
|||
} |
|||
|
|||
void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
system.GetUserChannel().clear(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
const auto storage = rp.PopIpcInterface<IStorage>().lock(); |
|||
if (storage) { |
|||
system.GetUserChannel().push_back(storage->GetData()); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<s32>(previous_program_index); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,63 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { |
|||
public: |
|||
explicit IApplicationFunctions(Core::System& system_); |
|||
~IApplicationFunctions() override; |
|||
|
|||
private: |
|||
void PopLaunchParameter(HLERequestContext& ctx); |
|||
void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx); |
|||
void EnsureSaveData(HLERequestContext& ctx); |
|||
void SetTerminateResult(HLERequestContext& ctx); |
|||
void GetDisplayVersion(HLERequestContext& ctx); |
|||
void GetDesiredLanguage(HLERequestContext& ctx); |
|||
void IsGamePlayRecordingSupported(HLERequestContext& ctx); |
|||
void InitializeGamePlayRecording(HLERequestContext& ctx); |
|||
void SetGamePlayRecordingState(HLERequestContext& ctx); |
|||
void NotifyRunning(HLERequestContext& ctx); |
|||
void GetPseudoDeviceId(HLERequestContext& ctx); |
|||
void ExtendSaveData(HLERequestContext& ctx); |
|||
void GetSaveDataSize(HLERequestContext& ctx); |
|||
void CreateCacheStorage(HLERequestContext& ctx); |
|||
void GetSaveDataSizeMax(HLERequestContext& ctx); |
|||
void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); |
|||
void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx); |
|||
void BeginBlockingHomeButton(HLERequestContext& ctx); |
|||
void EndBlockingHomeButton(HLERequestContext& ctx); |
|||
void EnableApplicationCrashReport(HLERequestContext& ctx); |
|||
void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx); |
|||
void SetApplicationCopyrightImage(HLERequestContext& ctx); |
|||
void SetApplicationCopyrightVisibility(HLERequestContext& ctx); |
|||
void QueryApplicationPlayStatistics(HLERequestContext& ctx); |
|||
void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx); |
|||
void ExecuteProgram(HLERequestContext& ctx); |
|||
void ClearUserChannel(HLERequestContext& ctx); |
|||
void UnpopToUserChannel(HLERequestContext& ctx); |
|||
void GetPreviousProgramIndex(HLERequestContext& ctx); |
|||
void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx); |
|||
void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx); |
|||
void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx); |
|||
void GetNotificationStorageChannelEvent(HLERequestContext& ctx); |
|||
void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx); |
|||
void PrepareForJit(HLERequestContext& ctx); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
|
|||
bool launch_popped_account_preselect = false; |
|||
s32 previous_program_index{-1}; |
|||
Kernel::KEvent* gpu_error_detected_event; |
|||
Kernel::KEvent* friend_invitation_storage_channel_event; |
|||
Kernel::KEvent* notification_storage_channel_event; |
|||
Kernel::KEvent* health_warning_disappeared_system_event; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,114 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applet_common_functions.h"
|
|||
#include "core/hle/service/am/application_functions.h"
|
|||
#include "core/hle/service/am/application_proxy.h"
|
|||
#include "core/hle/service/am/audio_controller.h"
|
|||
#include "core/hle/service/am/common_state_getter.h"
|
|||
#include "core/hle/service/am/debug_functions.h"
|
|||
#include "core/hle/service/am/display_controller.h"
|
|||
#include "core/hle/service/am/library_applet_creator.h"
|
|||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
|||
#include "core/hle/service/am/process_winding_controller.h"
|
|||
#include "core/hle/service/am/self_controller.h"
|
|||
#include "core/hle/service/am/window_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_) |
|||
: ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, |
|||
msg_queue{std::move(msg_queue_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
|||
{1, &IApplicationProxy::GetSelfController, "GetSelfController"}, |
|||
{2, &IApplicationProxy::GetWindowController, "GetWindowController"}, |
|||
{3, &IApplicationProxy::GetAudioController, "GetAudioController"}, |
|||
{4, &IApplicationProxy::GetDisplayController, "GetDisplayController"}, |
|||
{10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"}, |
|||
{11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, |
|||
{20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, |
|||
{1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
void IApplicationProxy::GetAudioController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioController>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDisplayController>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IProcessWindingController>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDebugFunctions>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetWindowController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IWindowController>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetSelfController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ISelfController>(system, nvnflinger); |
|||
} |
|||
|
|||
void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |
|||
} |
|||
|
|||
void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletCreator>(system); |
|||
} |
|||
|
|||
void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IApplicationFunctions>(system); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,32 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/am/applet_message_queue.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { |
|||
public: |
|||
explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_); |
|||
|
|||
private: |
|||
void GetAudioController(HLERequestContext& ctx); |
|||
void GetDisplayController(HLERequestContext& ctx); |
|||
void GetProcessWindingController(HLERequestContext& ctx); |
|||
void GetDebugFunctions(HLERequestContext& ctx); |
|||
void GetWindowController(HLERequestContext& ctx); |
|||
void GetSelfController(HLERequestContext& ctx); |
|||
void GetCommonStateGetter(HLERequestContext& ctx); |
|||
void GetLibraryAppletCreator(HLERequestContext& ctx); |
|||
void GetApplicationFunctions(HLERequestContext& ctx); |
|||
|
|||
Nvnflinger::Nvnflinger& nvnflinger; |
|||
std::shared_ptr<AppletMessageQueue> msg_queue; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,91 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/audio_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IAudioController::IAudioController(Core::System& system_) |
|||
: ServiceFramework{system_, "IAudioController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, |
|||
{1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"}, |
|||
{2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"}, |
|||
{3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"}, |
|||
{4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IAudioController::~IAudioController() = default; |
|||
|
|||
void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const float main_applet_volume_tmp = rp.Pop<float>(); |
|||
const float library_applet_volume_tmp = rp.Pop<float>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}", |
|||
main_applet_volume_tmp, library_applet_volume_tmp); |
|||
|
|||
// Ensure the volume values remain within the 0-100% range
|
|||
main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume); |
|||
library_applet_volume = |
|||
std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume); |
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(main_applet_volume); |
|||
} |
|||
|
|||
void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume); |
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(library_applet_volume); |
|||
} |
|||
|
|||
void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) { |
|||
struct Parameters { |
|||
float volume; |
|||
s64 fade_time_ns; |
|||
}; |
|||
static_assert(sizeof(Parameters) == 16); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
const auto parameters = rp.PopRaw<Parameters>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume, |
|||
parameters.fade_time_ns); |
|||
|
|||
main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume); |
|||
fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const float transparent_volume_rate_tmp = rp.Pop<float>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp); |
|||
|
|||
// Clamp volume range to 0-100%.
|
|||
transparent_volume_rate = |
|||
std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,36 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IAudioController final : public ServiceFramework<IAudioController> { |
|||
public: |
|||
explicit IAudioController(Core::System& system_); |
|||
~IAudioController() override; |
|||
|
|||
private: |
|||
void SetExpectedMasterVolume(HLERequestContext& ctx); |
|||
void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx); |
|||
void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx); |
|||
void ChangeMainAppletMasterVolume(HLERequestContext& ctx); |
|||
void SetTransparentAudioRate(HLERequestContext& ctx); |
|||
|
|||
static constexpr float min_allowed_volume = 0.0f; |
|||
static constexpr float max_allowed_volume = 1.0f; |
|||
|
|||
float main_applet_volume{0.25f}; |
|||
float library_applet_volume{max_allowed_volume}; |
|||
float transparent_volume_rate{min_allowed_volume}; |
|||
|
|||
// Volume transition fade time in nanoseconds. |
|||
// e.g. If the main applet volume was 0% and was changed to 50% |
|||
// with a fade of 50ns, then over the course of 50ns, |
|||
// the volume will gradually fade up to 50% |
|||
std::chrono::nanoseconds fade_time_ns{0}; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,288 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/settings.h"
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/common_state_getter.h"
|
|||
#include "core/hle/service/am/lock_accessor.h"
|
|||
#include "core/hle/service/apm/apm_controller.h"
|
|||
#include "core/hle/service/apm/apm_interface.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/pm/pm.h"
|
|||
#include "core/hle/service/sm/sm.h"
|
|||
#include "core/hle/service/vi/vi.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ICommonStateGetter::ICommonStateGetter(Core::System& system_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_) |
|||
: ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)}, |
|||
service_context{system_, "ICommonStateGetter"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, |
|||
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, |
|||
{2, nullptr, "GetThisAppletKind"}, |
|||
{3, nullptr, "AllowToEnterSleep"}, |
|||
{4, nullptr, "DisallowToEnterSleep"}, |
|||
{5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"}, |
|||
{6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"}, |
|||
{7, nullptr, "GetCradleStatus"}, |
|||
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"}, |
|||
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"}, |
|||
{10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"}, |
|||
{11, nullptr, "ReleaseSleepLock"}, |
|||
{12, nullptr, "ReleaseSleepLockTransiently"}, |
|||
{13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"}, |
|||
{14, nullptr, "GetWakeupCount"}, |
|||
{20, nullptr, "PushToGeneralChannel"}, |
|||
{30, nullptr, "GetHomeButtonReaderLockAccessor"}, |
|||
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, |
|||
{32, nullptr, "GetWriterLockAccessorEx"}, |
|||
{40, nullptr, "GetCradleFwVersion"}, |
|||
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, |
|||
{51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, |
|||
{52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, |
|||
{53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"}, |
|||
{54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"}, |
|||
{55, nullptr, "IsInControllerFirmwareUpdateSection"}, |
|||
{59, nullptr, "SetVrPositionForDebug"}, |
|||
{60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, |
|||
{61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, |
|||
{62, nullptr, "GetHdcpAuthenticationState"}, |
|||
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, |
|||
{64, nullptr, "SetTvPowerStateMatchingMode"}, |
|||
{65, nullptr, "GetApplicationIdByContentActionName"}, |
|||
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, |
|||
{67, nullptr, "CancelCpuBoostMode"}, |
|||
{68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"}, |
|||
{80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"}, |
|||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"}, |
|||
{91, nullptr, "GetCurrentPerformanceConfiguration"}, |
|||
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, |
|||
{110, nullptr, "OpenMyGpuErrorHandler"}, |
|||
{120, nullptr, "GetAppletLaunchedHistory"}, |
|||
{200, nullptr, "GetOperationModeSystemInfo"}, |
|||
{300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, |
|||
{400, nullptr, "ActivateMigrationService"}, |
|||
{401, nullptr, "DeactivateMigrationService"}, |
|||
{500, nullptr, "DisableSleepTillShutdown"}, |
|||
{501, nullptr, "SuppressDisablingSleepTemporarily"}, |
|||
{502, nullptr, "IsSleepEnabled"}, |
|||
{503, nullptr, "IsDisablingSleepSuppressed"}, |
|||
{900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent"); |
|||
|
|||
// Configure applets to be in foreground state
|
|||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); |
|||
msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |
|||
} |
|||
|
|||
ICommonStateGetter::~ICommonStateGetter() { |
|||
service_context.CloseEvent(sleep_lock_event); |
|||
}; |
|||
|
|||
void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
|
|||
} |
|||
|
|||
void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent()); |
|||
} |
|||
|
|||
void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
const auto message = msg_queue->PopMessage(); |
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
|
|||
if (message == AppletMessageQueue::AppletMessage::None) { |
|||
LOG_ERROR(Service_AM, "Message queue is empty"); |
|||
rb.Push(AM::ResultNoMessages); |
|||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message); |
|||
return; |
|||
} |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum<AppletMessageQueue::AppletMessage>(message); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<u8>(FocusState::InFocus)); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) { |
|||
const bool use_docked_mode{Settings::IsDockedMode()}; |
|||
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode()); |
|||
} |
|||
|
|||
void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
// Sleep lock is acquired immediately.
|
|||
sleep_lock_event->Signal(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto unknown = rp.Pop<u32>(); |
|||
|
|||
LOG_INFO(Service_AM, "called, unknown={}", unknown); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILockAccessor>(system); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(sleep_lock_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(vr_mode_state); |
|||
} |
|||
|
|||
void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
vr_mode_state = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}", |
|||
is_lcd_backlight_off_enabled); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
if (Settings::IsDockedMode()) { |
|||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); |
|||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); |
|||
} else { |
|||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); |
|||
rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); |
|||
} |
|||
} |
|||
|
|||
void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS"); |
|||
|
|||
const auto& sm = system.ServiceManager(); |
|||
const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys"); |
|||
ASSERT(apm_sys != nullptr); |
|||
|
|||
apm_sys->SetCpuBoostMode(ctx); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(0); |
|||
} |
|||
|
|||
void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto system_button{rp.PopEnum<SystemButtonType>()}; |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(SysPlatformRegion::Global); |
|||
} |
|||
|
|||
void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled( |
|||
HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,78 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
#include "core/hle/service/am/applet_message_queue.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { |
|||
public: |
|||
explicit ICommonStateGetter(Core::System& system_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_); |
|||
~ICommonStateGetter() override; |
|||
|
|||
private: |
|||
// This is nn::oe::FocusState |
|||
enum class FocusState : u8 { |
|||
InFocus = 1, |
|||
NotInFocus = 2, |
|||
Background = 3, |
|||
}; |
|||
|
|||
// This is nn::oe::OperationMode |
|||
enum class OperationMode : u8 { |
|||
Handheld = 0, |
|||
Docked = 1, |
|||
}; |
|||
|
|||
// This is nn::am::service::SystemButtonType |
|||
enum class SystemButtonType { |
|||
None, |
|||
HomeButtonShortPressing, |
|||
HomeButtonLongPressing, |
|||
PowerButtonShortPressing, |
|||
PowerButtonLongPressing, |
|||
ShutdownSystem, |
|||
CaptureButtonShortPressing, |
|||
CaptureButtonLongPressing, |
|||
}; |
|||
|
|||
enum class SysPlatformRegion : s32 { |
|||
Global = 1, |
|||
Terra = 2, |
|||
}; |
|||
|
|||
void GetEventHandle(HLERequestContext& ctx); |
|||
void ReceiveMessage(HLERequestContext& ctx); |
|||
void GetCurrentFocusState(HLERequestContext& ctx); |
|||
void RequestToAcquireSleepLock(HLERequestContext& ctx); |
|||
void GetAcquiredSleepLockEvent(HLERequestContext& ctx); |
|||
void GetReaderLockAccessorEx(HLERequestContext& ctx); |
|||
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); |
|||
void GetOperationMode(HLERequestContext& ctx); |
|||
void GetPerformanceMode(HLERequestContext& ctx); |
|||
void GetBootMode(HLERequestContext& ctx); |
|||
void IsVrModeEnabled(HLERequestContext& ctx); |
|||
void SetVrModeEnabled(HLERequestContext& ctx); |
|||
void SetLcdBacklighOffEnabled(HLERequestContext& ctx); |
|||
void BeginVrModeEx(HLERequestContext& ctx); |
|||
void EndVrModeEx(HLERequestContext& ctx); |
|||
void GetDefaultDisplayResolution(HLERequestContext& ctx); |
|||
void SetCpuBoostMode(HLERequestContext& ctx); |
|||
void GetBuiltInDisplayType(HLERequestContext& ctx); |
|||
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); |
|||
void GetSettingsPlatformRegion(HLERequestContext& ctx); |
|||
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); |
|||
|
|||
std::shared_ptr<AppletMessageQueue> msg_queue; |
|||
bool vr_mode_state{}; |
|||
Kernel::KEvent* sleep_lock_event; |
|||
KernelHelpers::ServiceContext service_context; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,44 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/debug_functions.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IDebugFunctions::IDebugFunctions(Core::System& system_) |
|||
: ServiceFramework{system_, "IDebugFunctions"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "NotifyMessageToHomeMenuForDebug"}, |
|||
{1, nullptr, "OpenMainApplication"}, |
|||
{10, nullptr, "PerformSystemButtonPressing"}, |
|||
{20, nullptr, "InvalidateTransitionLayer"}, |
|||
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, |
|||
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"}, |
|||
{40, nullptr, "GetAppletResourceUsageInfo"}, |
|||
{50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"}, |
|||
{51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"}, |
|||
{100, nullptr, "SetCpuBoostModeForApplet"}, |
|||
{101, nullptr, "CancelCpuBoostModeForApplet"}, |
|||
{110, nullptr, "PushToAppletBoundChannelForDebug"}, |
|||
{111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, |
|||
{120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, |
|||
{121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"}, |
|||
{122, nullptr, "AlarmSettingNotificationPushAppEventNotify"}, |
|||
{130, nullptr, "FriendInvitationSetApplicationParameter"}, |
|||
{131, nullptr, "FriendInvitationClearApplicationParameter"}, |
|||
{132, nullptr, "FriendInvitationPushApplicationParameter"}, |
|||
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"}, |
|||
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"}, |
|||
{300, nullptr, "TerminateAllRunningApplicationsForDebug"}, |
|||
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IDebugFunctions::~IDebugFunctions() = default; |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,16 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { |
|||
public: |
|||
explicit IDebugFunctions(Core::System& system_); |
|||
~IDebugFunctions() override; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,97 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/display_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IDisplayController::IDisplayController(Core::System& system_) |
|||
: ServiceFramework{system_, "IDisplayController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "GetLastForegroundCaptureImage"}, |
|||
{1, nullptr, "UpdateLastForegroundCaptureImage"}, |
|||
{2, nullptr, "GetLastApplicationCaptureImage"}, |
|||
{3, nullptr, "GetCallerAppletCaptureImage"}, |
|||
{4, nullptr, "UpdateCallerAppletCaptureImage"}, |
|||
{5, nullptr, "GetLastForegroundCaptureImageEx"}, |
|||
{6, nullptr, "GetLastApplicationCaptureImageEx"}, |
|||
{7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"}, |
|||
{8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"}, |
|||
{9, nullptr, "CopyBetweenCaptureBuffers"}, |
|||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"}, |
|||
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, |
|||
{12, nullptr, "AcquireLastForegroundCaptureBuffer"}, |
|||
{13, nullptr, "ReleaseLastForegroundCaptureBuffer"}, |
|||
{14, nullptr, "AcquireCallerAppletCaptureBuffer"}, |
|||
{15, nullptr, "ReleaseCallerAppletCaptureBuffer"}, |
|||
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, |
|||
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, |
|||
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, |
|||
{20, nullptr, "ClearCaptureBuffer"}, |
|||
{21, nullptr, "ClearAppletTransitionBuffer"}, |
|||
{22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, |
|||
{23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, |
|||
{24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"}, |
|||
{25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"}, |
|||
{26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"}, |
|||
{27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"}, |
|||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IDisplayController::~IDisplayController() = default; |
|||
|
|||
void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(1u); |
|||
rb.Push(1); |
|||
} |
|||
|
|||
void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(1U); |
|||
rb.Push(1); |
|||
} |
|||
|
|||
void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(1U); |
|||
rb.Push(1); |
|||
} |
|||
|
|||
void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,24 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IDisplayController final : public ServiceFramework<IDisplayController> { |
|||
public: |
|||
explicit IDisplayController(Core::System& system_); |
|||
~IDisplayController() override; |
|||
|
|||
private: |
|||
void GetCallerAppletCaptureImageEx(HLERequestContext& ctx); |
|||
void TakeScreenShotOfOwnLayer(HLERequestContext& ctx); |
|||
void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); |
|||
void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx); |
|||
void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); |
|||
void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx); |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,34 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/global_state_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IGlobalStateController::IGlobalStateController(Core::System& system_) |
|||
: ServiceFramework{system_, "IGlobalStateController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "RequestToEnterSleep"}, |
|||
{1, nullptr, "EnterSleep"}, |
|||
{2, nullptr, "StartSleepSequence"}, |
|||
{3, nullptr, "StartShutdownSequence"}, |
|||
{4, nullptr, "StartRebootSequence"}, |
|||
{9, nullptr, "IsAutoPowerDownRequested"}, |
|||
{10, nullptr, "LoadAndApplyIdlePolicySettings"}, |
|||
{11, nullptr, "NotifyCecSettingsChanged"}, |
|||
{12, nullptr, "SetDefaultHomeButtonLongPressTime"}, |
|||
{13, nullptr, "UpdateDefaultDisplayResolution"}, |
|||
{14, nullptr, "ShouldSleepOnBoot"}, |
|||
{15, nullptr, "GetHdcpAuthenticationFailedEvent"}, |
|||
{30, nullptr, "OpenCradleFirmwareUpdater"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IGlobalStateController::~IGlobalStateController() = default; |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,16 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { |
|||
public: |
|||
explicit IGlobalStateController(Core::System& system_); |
|||
~IGlobalStateController() override; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,57 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/home_menu_functions.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_) |
|||
: ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system, |
|||
"IHomeMenuFunctions"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, |
|||
{11, nullptr, "LockForeground"}, |
|||
{12, nullptr, "UnlockForeground"}, |
|||
{20, nullptr, "PopFromGeneralChannel"}, |
|||
{21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, |
|||
{30, nullptr, "GetHomeButtonWriterLockAccessor"}, |
|||
{31, nullptr, "GetWriterLockAccessorEx"}, |
|||
{40, nullptr, "IsSleepEnabled"}, |
|||
{41, nullptr, "IsRebootEnabled"}, |
|||
{50, nullptr, "LaunchSystemApplet"}, |
|||
{51, nullptr, "LaunchStarter"}, |
|||
{100, nullptr, "PopRequestLaunchApplicationForDebug"}, |
|||
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"}, |
|||
{200, nullptr, "LaunchDevMenu"}, |
|||
{1000, nullptr, "SetLastApplicationExitReason"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
pop_from_general_channel_event = |
|||
service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent"); |
|||
} |
|||
|
|||
IHomeMenuFunctions::~IHomeMenuFunctions() { |
|||
service_context.CloseEvent(pop_from_general_channel_event); |
|||
} |
|||
|
|||
void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent()); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,25 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { |
|||
public: |
|||
explicit IHomeMenuFunctions(Core::System& system_); |
|||
~IHomeMenuFunctions() override; |
|||
|
|||
private: |
|||
void RequestToGetForeground(HLERequestContext& ctx); |
|||
void GetPopFromGeneralChannelEvent(HLERequestContext& ctx); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
|
|||
Kernel::KEvent* pop_from_general_channel_event; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,178 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/library_applet_accessor.h"
|
|||
#include "core/hle/service/am/storage.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_, |
|||
std::shared_ptr<Applets::Applet> applet_) |
|||
: ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, |
|||
{1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"}, |
|||
{10, &ILibraryAppletAccessor::Start, "Start"}, |
|||
{20, &ILibraryAppletAccessor::RequestExit, "RequestExit"}, |
|||
{25, nullptr, "Terminate"}, |
|||
{30, &ILibraryAppletAccessor::GetResult, "GetResult"}, |
|||
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, |
|||
{60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"}, |
|||
{100, &ILibraryAppletAccessor::PushInData, "PushInData"}, |
|||
{101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, |
|||
{102, nullptr, "PushExtraStorage"}, |
|||
{103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"}, |
|||
{104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"}, |
|||
{105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"}, |
|||
{106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"}, |
|||
{110, nullptr, "NeedsToExitProcess"}, |
|||
{120, nullptr, "GetLibraryAppletInfo"}, |
|||
{150, nullptr, "RequestForAppletToGetForeground"}, |
|||
{160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(applet->TransactionComplete()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(applet->GetStatus()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::Start(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
ASSERT(applet != nullptr); |
|||
|
|||
applet->Initialize(); |
|||
applet->Execute(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
ASSERT(applet != nullptr); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(applet->RequestExit()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock()); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
auto storage = applet->GetBroker().PopNormalDataToGame(); |
|||
if (storage == nullptr) { |
|||
LOG_DEBUG(Service_AM, |
|||
"storage is a nullptr. There is no data in the current normal channel"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(std::move(storage)); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::RequestParser rp{ctx}; |
|||
applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock()); |
|||
|
|||
ASSERT(applet->IsInitialized()); |
|||
applet->ExecuteInteractive(); |
|||
applet->Execute(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
auto storage = applet->GetBroker().PopInteractiveDataToGame(); |
|||
if (storage == nullptr) { |
|||
LOG_DEBUG(Service_AM, |
|||
"storage is a nullptr. There is no data in the current interactive channel"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(std::move(storage)); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); |
|||
} |
|||
|
|||
void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
// We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
|
|||
// actually used anywhere
|
|||
constexpr u64 handle = 0xdeadbeef; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(handle); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,34 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/am/applets/applets.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
|||
public: |
|||
explicit ILibraryAppletAccessor(Core::System& system_, |
|||
std::shared_ptr<Applets::Applet> applet_); |
|||
|
|||
private: |
|||
void GetAppletStateChangedEvent(HLERequestContext& ctx); |
|||
void IsCompleted(HLERequestContext& ctx); |
|||
void GetResult(HLERequestContext& ctx); |
|||
void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx); |
|||
void Start(HLERequestContext& ctx); |
|||
void RequestExit(HLERequestContext& ctx); |
|||
void PushInData(HLERequestContext& ctx); |
|||
void PopOutData(HLERequestContext& ctx); |
|||
void PushInteractiveInData(HLERequestContext& ctx); |
|||
void PopInteractiveOutData(HLERequestContext& ctx); |
|||
void GetPopOutDataEvent(HLERequestContext& ctx); |
|||
void GetPopInteractiveOutDataEvent(HLERequestContext& ctx); |
|||
void GetIndirectLayerConsumerHandle(HLERequestContext& ctx); |
|||
|
|||
std::shared_ptr<Applets::Applet> applet; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,145 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/kernel/k_transfer_memory.h"
|
|||
#include "core/hle/service/am/applets/applets.h"
|
|||
#include "core/hle/service/am/library_applet_accessor.h"
|
|||
#include "core/hle/service/am/library_applet_creator.h"
|
|||
#include "core/hle/service/am/storage.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) |
|||
: ServiceFramework{system_, "ILibraryAppletCreator"} { |
|||
static const FunctionInfo functions[] = { |
|||
{0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, |
|||
{1, nullptr, "TerminateAllLibraryApplets"}, |
|||
{2, nullptr, "AreAnyLibraryAppletsLeft"}, |
|||
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, |
|||
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, |
|||
{12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"}, |
|||
}; |
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
ILibraryAppletCreator::~ILibraryAppletCreator() = default; |
|||
|
|||
void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto applet_id = rp.PopRaw<Applets::AppletId>(); |
|||
const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, |
|||
applet_mode); |
|||
|
|||
const auto& applet_manager{system.GetAppletManager()}; |
|||
const auto applet = applet_manager.GetApplet(applet_id, applet_mode); |
|||
|
|||
if (applet == nullptr) { |
|||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); |
|||
} |
|||
|
|||
void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const s64 size{rp.Pop<s64>()}; |
|||
|
|||
LOG_DEBUG(Service_AM, "called, size={}", size); |
|||
|
|||
if (size <= 0) { |
|||
LOG_ERROR(Service_AM, "size is less than or equal to 0"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u8> buffer(size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(system, std::move(buffer)); |
|||
} |
|||
|
|||
void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
struct Parameters { |
|||
u8 permissions; |
|||
s64 size; |
|||
}; |
|||
|
|||
const auto parameters{rp.PopRaw<Parameters>()}; |
|||
const auto handle{ctx.GetCopyHandle(0)}; |
|||
|
|||
LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions, |
|||
parameters.size, handle); |
|||
|
|||
if (parameters.size <= 0) { |
|||
LOG_ERROR(Service_AM, "size is less than or equal to 0"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); |
|||
|
|||
if (transfer_mem.IsNull()) { |
|||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u8> memory(transfer_mem->GetSize()); |
|||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(system, std::move(memory)); |
|||
} |
|||
|
|||
void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const s64 size{rp.Pop<s64>()}; |
|||
const auto handle{ctx.GetCopyHandle(0)}; |
|||
|
|||
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle); |
|||
|
|||
if (size <= 0) { |
|||
LOG_ERROR(Service_AM, "size is less than or equal to 0"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle); |
|||
|
|||
if (transfer_mem.IsNull()) { |
|||
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u8> memory(transfer_mem->GetSize()); |
|||
ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size()); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(system, std::move(memory)); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,22 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { |
|||
public: |
|||
explicit ILibraryAppletCreator(Core::System& system_); |
|||
~ILibraryAppletCreator() override; |
|||
|
|||
private: |
|||
void CreateLibraryApplet(HLERequestContext& ctx); |
|||
void CreateStorage(HLERequestContext& ctx); |
|||
void CreateTransferMemoryStorage(HLERequestContext& ctx); |
|||
void CreateHandleStorage(HLERequestContext& ctx); |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,142 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applet_common_functions.h"
|
|||
#include "core/hle/service/am/audio_controller.h"
|
|||
#include "core/hle/service/am/common_state_getter.h"
|
|||
#include "core/hle/service/am/debug_functions.h"
|
|||
#include "core/hle/service/am/display_controller.h"
|
|||
#include "core/hle/service/am/global_state_controller.h"
|
|||
#include "core/hle/service/am/home_menu_functions.h"
|
|||
#include "core/hle/service/am/library_applet_creator.h"
|
|||
#include "core/hle/service/am/library_applet_proxy.h"
|
|||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
|||
#include "core/hle/service/am/process_winding_controller.h"
|
|||
#include "core/hle/service/am/self_controller.h"
|
|||
#include "core/hle/service/am/window_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_) |
|||
: ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, |
|||
msg_queue{std::move(msg_queue_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
|||
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, |
|||
{2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, |
|||
{3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, |
|||
{4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, |
|||
{10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"}, |
|||
{11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, |
|||
{20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"}, |
|||
{21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, |
|||
{22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, |
|||
{23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, |
|||
{1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ISelfController>(system, nvnflinger); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IWindowController>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioController>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDisplayController>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IProcessWindingController>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletCreator>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAppletCommonFunctions>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IHomeMenuFunctions>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IGlobalStateController>(system); |
|||
} |
|||
|
|||
void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDebugFunctions>(system); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,35 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/am/applet_message_queue.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { |
|||
public: |
|||
explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_); |
|||
|
|||
private: |
|||
void GetCommonStateGetter(HLERequestContext& ctx); |
|||
void GetSelfController(HLERequestContext& ctx); |
|||
void GetWindowController(HLERequestContext& ctx); |
|||
void GetAudioController(HLERequestContext& ctx); |
|||
void GetDisplayController(HLERequestContext& ctx); |
|||
void GetProcessWindingController(HLERequestContext& ctx); |
|||
void GetLibraryAppletCreator(HLERequestContext& ctx); |
|||
void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx); |
|||
void GetAppletCommonFunctions(HLERequestContext& ctx); |
|||
void GetHomeMenuFunctions(HLERequestContext& ctx); |
|||
void GetGlobalStateController(HLERequestContext& ctx); |
|||
void GetDebugFunctions(HLERequestContext& ctx); |
|||
|
|||
Nvnflinger::Nvnflinger& nvnflinger; |
|||
std::shared_ptr<AppletMessageQueue> msg_queue; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,382 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/core_timing.h"
|
|||
#include "core/hle/service/acc/profile_manager.h"
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
|||
#include "core/hle/service/am/applets/applet_controller.h"
|
|||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
|||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
|||
#include "core/hle/service/am/applets/applets.h"
|
|||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
|||
#include "core/hle/service/am/storage.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "hid_core/hid_types.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) |
|||
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"}, |
|||
{1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"}, |
|||
{2, nullptr, "PopInteractiveInData"}, |
|||
{3, nullptr, "PushInteractiveOutData"}, |
|||
{5, nullptr, "GetPopInDataEvent"}, |
|||
{6, nullptr, "GetPopInteractiveInDataEvent"}, |
|||
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"}, |
|||
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"}, |
|||
{12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"}, |
|||
{13, nullptr, "CanUseApplicationCore"}, |
|||
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"}, |
|||
{15, nullptr, "GetMainAppletApplicationControlProperty"}, |
|||
{16, nullptr, "GetMainAppletStorageId"}, |
|||
{17, nullptr, "GetCallerAppletIdentityInfoStack"}, |
|||
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, |
|||
{19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, |
|||
{20, nullptr, "PopExtraStorage"}, |
|||
{25, nullptr, "GetPopExtraStorageEvent"}, |
|||
{30, nullptr, "UnpopInData"}, |
|||
{31, nullptr, "UnpopExtraStorage"}, |
|||
{40, nullptr, "GetIndirectLayerProducerHandle"}, |
|||
{50, nullptr, "ReportVisibleError"}, |
|||
{51, nullptr, "ReportVisibleErrorWithErrorContext"}, |
|||
{60, nullptr, "GetMainAppletApplicationDesiredLanguage"}, |
|||
{70, nullptr, "GetCurrentApplicationId"}, |
|||
{80, nullptr, "RequestExitToSelf"}, |
|||
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"}, |
|||
{100, nullptr, "CreateGameMovieTrimmer"}, |
|||
{101, nullptr, "ReserveResourceForMovieOperation"}, |
|||
{102, nullptr, "UnreserveResourceForMovieOperation"}, |
|||
{110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"}, |
|||
{120, nullptr, "GetLaunchStorageInfoForDebug"}, |
|||
{130, nullptr, "GetGpuErrorDetectedSystemEvent"}, |
|||
{140, nullptr, "SetApplicationMemoryReservation"}, |
|||
{150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, |
|||
}; |
|||
// clang-format on
|
|||
RegisterHandlers(functions); |
|||
|
|||
switch (system.GetAppletManager().GetCurrentAppletId()) { |
|||
case Applets::AppletId::Cabinet: |
|||
PushInShowCabinetData(); |
|||
break; |
|||
case Applets::AppletId::MiiEdit: |
|||
PushInShowMiiEditData(); |
|||
break; |
|||
case Applets::AppletId::PhotoViewer: |
|||
PushInShowAlbum(); |
|||
break; |
|||
case Applets::AppletId::SoftwareKeyboard: |
|||
PushInShowSoftwareKeyboard(); |
|||
break; |
|||
case Applets::AppletId::Controller: |
|||
PushInShowController(); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default; |
|||
|
|||
void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_AM, "called"); |
|||
|
|||
if (queue_data.empty()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultNoDataInChannel); |
|||
return; |
|||
} |
|||
|
|||
auto data = queue_data.front(); |
|||
queue_data.pop_front(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorage>(system, std::move(data)); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
system.Exit(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) { |
|||
struct LibraryAppletInfo { |
|||
Applets::AppletId applet_id; |
|||
Applets::LibraryAppletMode library_applet_mode; |
|||
}; |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
const LibraryAppletInfo applet_info{ |
|||
.applet_id = system.GetAppletManager().GetCurrentAppletId(), |
|||
.library_applet_mode = Applets::LibraryAppletMode::AllForeground, |
|||
}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(applet_info); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) { |
|||
struct AppletIdentityInfo { |
|||
Applets::AppletId applet_id; |
|||
INSERT_PADDING_BYTES(0x4); |
|||
u64 application_id; |
|||
}; |
|||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
const AppletIdentityInfo applet_info{ |
|||
.applet_id = Applets::AppletId::QLaunch, |
|||
.application_id = 0x0100000000001000ull, |
|||
}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(applet_info); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) { |
|||
struct AppletIdentityInfo { |
|||
Applets::AppletId applet_id; |
|||
INSERT_PADDING_BYTES(0x4); |
|||
u64 application_id; |
|||
}; |
|||
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size."); |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
const AppletIdentityInfo applet_info{ |
|||
.applet_id = Applets::AppletId::QLaunch, |
|||
.application_id = 0x0100000000001000ull, |
|||
}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(applet_info); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(0); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { |
|||
const Service::Account::ProfileManager manager{}; |
|||
bool is_empty{true}; |
|||
s32 user_count{-1}; |
|||
|
|||
LOG_INFO(Service_AM, "called"); |
|||
|
|||
if (manager.GetUserCount() > 0) { |
|||
is_empty = false; |
|||
user_count = static_cast<s32>(manager.GetUserCount()); |
|||
ctx.WriteBuffer(manager.GetAllUsers()); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(is_empty); |
|||
rb.Push(user_count); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(0); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushInShowAlbum() { |
|||
const Applets::CommonArguments arguments{ |
|||
.arguments_version = Applets::CommonArgumentVersion::Version3, |
|||
.size = Applets::CommonArgumentSize::Version3, |
|||
.library_version = 1, |
|||
.theme_color = Applets::ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> settings_data{2}; |
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
queue_data.emplace_back(std::move(argument_data)); |
|||
queue_data.emplace_back(std::move(settings_data)); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushInShowController() { |
|||
const Applets::CommonArguments common_args = { |
|||
.arguments_version = Applets::CommonArgumentVersion::Version3, |
|||
.size = Applets::CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8), |
|||
.theme_color = Applets::ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
Applets::ControllerSupportArgNew user_args = { |
|||
.header = {.player_count_min = 1, |
|||
.player_count_max = 4, |
|||
.enable_take_over_connection = true, |
|||
.enable_left_justify = false, |
|||
.enable_permit_joy_dual = true, |
|||
.enable_single_mode = false, |
|||
.enable_identification_color = false}, |
|||
.identification_colors = {}, |
|||
.enable_explain_text = false, |
|||
.explain_text = {}, |
|||
}; |
|||
|
|||
Applets::ControllerSupportArgPrivate private_args = { |
|||
.arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), |
|||
.arg_size = sizeof(Applets::ControllerSupportArgNew), |
|||
.is_home_menu = true, |
|||
.flag_1 = true, |
|||
.mode = Applets::ControllerSupportMode::ShowControllerSupport, |
|||
.caller = Applets::ControllerSupportCaller:: |
|||
Application, // switchbrew: Always zero except with
|
|||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
|||
// which sets this to the input param
|
|||
.style_set = Core::HID::NpadStyleSet::None, |
|||
.joy_hold_type = 0, |
|||
}; |
|||
std::vector<u8> common_args_data(sizeof(common_args)); |
|||
std::vector<u8> private_args_data(sizeof(private_args)); |
|||
std::vector<u8> user_args_data(sizeof(user_args)); |
|||
|
|||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); |
|||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); |
|||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); |
|||
|
|||
queue_data.emplace_back(std::move(common_args_data)); |
|||
queue_data.emplace_back(std::move(private_args_data)); |
|||
queue_data.emplace_back(std::move(user_args_data)); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushInShowCabinetData() { |
|||
const Applets::CommonArguments arguments{ |
|||
.arguments_version = Applets::CommonArgumentVersion::Version3, |
|||
.size = Applets::CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1), |
|||
.theme_color = Applets::ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
const Applets::StartParamForAmiiboSettings amiibo_settings{ |
|||
.param_1 = 0, |
|||
.applet_mode = system.GetAppletManager().GetCabinetMode(), |
|||
.flags = Applets::CabinetFlags::None, |
|||
.amiibo_settings_1 = 0, |
|||
.device_handle = 0, |
|||
.tag_info{}, |
|||
.register_info{}, |
|||
.amiibo_settings_3{}, |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> settings_data(sizeof(amiibo_settings)); |
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); |
|||
queue_data.emplace_back(std::move(argument_data)); |
|||
queue_data.emplace_back(std::move(settings_data)); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { |
|||
struct MiiEditV3 { |
|||
Applets::MiiEditAppletInputCommon common; |
|||
Applets::MiiEditAppletInputV3 input; |
|||
}; |
|||
static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); |
|||
|
|||
MiiEditV3 mii_arguments{ |
|||
.common = |
|||
{ |
|||
.version = Applets::MiiEditAppletVersion::Version3, |
|||
.applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, |
|||
}, |
|||
.input{}, |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(mii_arguments)); |
|||
std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); |
|||
|
|||
queue_data.emplace_back(std::move(argument_data)); |
|||
} |
|||
|
|||
void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { |
|||
const Applets::CommonArguments arguments{ |
|||
.arguments_version = Applets::CommonArgumentVersion::Version3, |
|||
.size = Applets::CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), |
|||
.theme_color = Applets::ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
std::vector<char16_t> initial_string(0); |
|||
|
|||
const Applets::SwkbdConfigCommon swkbd_config{ |
|||
.type = Applets::SwkbdType::Qwerty, |
|||
.ok_text{}, |
|||
.left_optional_symbol_key{}, |
|||
.right_optional_symbol_key{}, |
|||
.use_prediction = false, |
|||
.key_disable_flags{}, |
|||
.initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, |
|||
.header_text{}, |
|||
.sub_text{}, |
|||
.guide_text{}, |
|||
.max_text_length = 500, |
|||
.min_text_length = 0, |
|||
.password_mode = Applets::SwkbdPasswordMode::Disabled, |
|||
.text_draw_type = Applets::SwkbdTextDrawType::Box, |
|||
.enable_return_button = true, |
|||
.use_utf8 = false, |
|||
.use_blur_background = true, |
|||
.initial_string_offset{}, |
|||
.initial_string_length = static_cast<u32>(initial_string.size()), |
|||
.user_dictionary_offset{}, |
|||
.user_dictionary_entries{}, |
|||
.use_text_check = false, |
|||
}; |
|||
|
|||
Applets::SwkbdConfigNew swkbd_config_new{}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); |
|||
std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); |
|||
|
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); |
|||
std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, |
|||
sizeof(Applets::SwkbdConfigNew)); |
|||
std::memcpy(work_buffer.data(), initial_string.data(), |
|||
swkbd_config.initial_string_length * sizeof(char16_t)); |
|||
|
|||
queue_data.emplace_back(std::move(argument_data)); |
|||
queue_data.emplace_back(std::move(swkbd_data)); |
|||
queue_data.emplace_back(std::move(work_buffer)); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,38 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <deque> |
|||
#include <vector> |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> { |
|||
public: |
|||
explicit ILibraryAppletSelfAccessor(Core::System& system_); |
|||
~ILibraryAppletSelfAccessor() override; |
|||
|
|||
private: |
|||
void PopInData(HLERequestContext& ctx); |
|||
void PushOutData(HLERequestContext& ctx); |
|||
void GetLibraryAppletInfo(HLERequestContext& ctx); |
|||
void GetMainAppletIdentityInfo(HLERequestContext& ctx); |
|||
void ExitProcessAndReturn(HLERequestContext& ctx); |
|||
void GetCallerAppletIdentityInfo(HLERequestContext& ctx); |
|||
void GetDesirableKeyboardLayout(HLERequestContext& ctx); |
|||
void GetMainAppletAvailableUsers(HLERequestContext& ctx); |
|||
void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); |
|||
|
|||
void PushInShowAlbum(); |
|||
void PushInShowCabinetData(); |
|||
void PushInShowMiiEditData(); |
|||
void PushInShowSoftwareKeyboard(); |
|||
void PushInShowController(); |
|||
|
|||
std::deque<std::vector<u8>> queue_data; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,71 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/lock_accessor.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ILockAccessor::ILockAccessor(Core::System& system_) |
|||
: ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{1, &ILockAccessor::TryLock, "TryLock"}, |
|||
{2, &ILockAccessor::Unlock, "Unlock"}, |
|||
{3, &ILockAccessor::GetEvent, "GetEvent"}, |
|||
{4,&ILockAccessor::IsLocked, "IsLocked"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); |
|||
} |
|||
|
|||
ILockAccessor::~ILockAccessor() { |
|||
service_context.CloseEvent(lock_event); |
|||
}; |
|||
|
|||
void ILockAccessor::TryLock(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto return_handle = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle); |
|||
|
|||
// TODO: When return_handle is true this function should return the lock handle
|
|||
|
|||
is_locked = true; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(is_locked); |
|||
} |
|||
|
|||
void ILockAccessor::Unlock(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_AM, "called"); |
|||
|
|||
is_locked = false; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ILockAccessor::GetEvent(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_AM, "called"); |
|||
|
|||
lock_event->Signal(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(lock_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void ILockAccessor::IsLocked(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u8>(is_locked); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,28 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ILockAccessor final : public ServiceFramework<ILockAccessor> { |
|||
public: |
|||
explicit ILockAccessor(Core::System& system_); |
|||
~ILockAccessor() override; |
|||
|
|||
private: |
|||
void TryLock(HLERequestContext& ctx); |
|||
void Unlock(HLERequestContext& ctx); |
|||
void GetEvent(HLERequestContext& ctx); |
|||
void IsLocked(HLERequestContext& ctx); |
|||
|
|||
bool is_locked{}; |
|||
|
|||
Kernel::KEvent* lock_event; |
|||
KernelHelpers::ServiceContext service_context; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,73 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applets/applets.h"
|
|||
#include "core/hle/service/am/library_applet_accessor.h"
|
|||
#include "core/hle/service/am/process_winding_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IProcessWindingController::IProcessWindingController(Core::System& system_) |
|||
: ServiceFramework{system_, "IProcessWindingController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"}, |
|||
{11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"}, |
|||
{21, nullptr, "PushContext"}, |
|||
{22, nullptr, "PopContext"}, |
|||
{23, nullptr, "CancelWindingReservation"}, |
|||
{30, nullptr, "WindAndDoReserved"}, |
|||
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, |
|||
{41, nullptr, "ReserveToStartAndWait"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IProcessWindingController::~IProcessWindingController() = default; |
|||
|
|||
void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
struct AppletProcessLaunchReason { |
|||
u8 flag; |
|||
INSERT_PADDING_BYTES(3); |
|||
}; |
|||
static_assert(sizeof(AppletProcessLaunchReason) == 0x4, |
|||
"AppletProcessLaunchReason is an invalid size"); |
|||
|
|||
AppletProcessLaunchReason reason{ |
|||
.flag = 0, |
|||
}; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushRaw(reason); |
|||
} |
|||
|
|||
void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) { |
|||
const auto applet_id = system.GetAppletManager().GetCurrentAppletId(); |
|||
const auto applet_mode = Applets::LibraryAppletMode::AllForeground; |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id, |
|||
applet_mode); |
|||
|
|||
const auto& applet_manager{system.GetAppletManager()}; |
|||
const auto applet = applet_manager.GetApplet(applet_id, applet_mode); |
|||
|
|||
if (applet == nullptr) { |
|||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultUnknown); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,20 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { |
|||
public: |
|||
explicit IProcessWindingController(Core::System& system_); |
|||
~IProcessWindingController() override; |
|||
|
|||
private: |
|||
void GetLaunchReason(HLERequestContext& ctx); |
|||
void OpenCallingLibraryApplet(HLERequestContext& ctx); |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,438 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applets/applets.h"
|
|||
#include "core/hle/service/am/self_controller.h"
|
|||
#include "core/hle/service/caps/caps_su.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
|||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
|||
#include "core/hle/service/sm/sm.h"
|
|||
#include "core/hle/service/vi/vi_results.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) |
|||
: ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, |
|||
service_context{system, "ISelfController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ISelfController::Exit, "Exit"}, |
|||
{1, &ISelfController::LockExit, "LockExit"}, |
|||
{2, &ISelfController::UnlockExit, "UnlockExit"}, |
|||
{3, &ISelfController::EnterFatalSection, "EnterFatalSection"}, |
|||
{4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"}, |
|||
{9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, |
|||
{10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, |
|||
{11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"}, |
|||
{12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"}, |
|||
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, |
|||
{14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, |
|||
{15, nullptr, "SetScreenShotAppletIdentityInfo"}, |
|||
{16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, |
|||
{17, nullptr, "SetControllerFirmwareUpdateSection"}, |
|||
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, |
|||
{19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, |
|||
{20, nullptr, "SetDesirableKeyboardLayout"}, |
|||
{21, nullptr, "GetScreenShotProgramId"}, |
|||
{40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, |
|||
{41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"}, |
|||
{42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"}, |
|||
{43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"}, |
|||
{44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, |
|||
{45, nullptr, "SetManagedDisplayLayerSeparationMode"}, |
|||
{46, nullptr, "SetRecordingLayerCompositionEnabled"}, |
|||
{50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, |
|||
{51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"}, |
|||
{60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, |
|||
{61, nullptr, "SetMediaPlaybackState"}, |
|||
{62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"}, |
|||
{63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"}, |
|||
{64, nullptr, "SetInputDetectionSourceSet"}, |
|||
{65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"}, |
|||
{66, nullptr, "GetCurrentIlluminance"}, |
|||
{67, nullptr, "IsIlluminanceAvailable"}, |
|||
{68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"}, |
|||
{69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"}, |
|||
{70, nullptr, "ReportMultimediaError"}, |
|||
{71, nullptr, "GetCurrentIlluminanceEx"}, |
|||
{72, nullptr, "SetInputDetectionPolicy"}, |
|||
{80, nullptr, "SetWirelessPriorityMode"}, |
|||
{90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"}, |
|||
{91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, |
|||
{100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, |
|||
{110, nullptr, "SetApplicationAlbumUserData"}, |
|||
{120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, |
|||
{130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"}, |
|||
{1000, nullptr, "GetDebugStorageChannel"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
|
|||
launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent"); |
|||
|
|||
// This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
|
|||
// called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
|
|||
// ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
|
|||
// suspended if the event has previously been created by a call to
|
|||
// GetAccumulatedSuspendedTickChangedEvent.
|
|||
|
|||
accumulated_suspended_tick_changed_event = |
|||
service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent"); |
|||
accumulated_suspended_tick_changed_event->Signal(); |
|||
} |
|||
|
|||
ISelfController::~ISelfController() { |
|||
service_context.CloseEvent(launchable_event); |
|||
service_context.CloseEvent(accumulated_suspended_tick_changed_event); |
|||
} |
|||
|
|||
void ISelfController::Exit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
system.Exit(); |
|||
} |
|||
|
|||
void ISelfController::LockExit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
system.SetExitLocked(true); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::UnlockExit(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
system.SetExitLocked(false); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
|
|||
if (system.GetExitRequested()) { |
|||
system.Exit(); |
|||
} |
|||
} |
|||
|
|||
void ISelfController::EnterFatalSection(HLERequestContext& ctx) { |
|||
++num_fatal_sections_entered; |
|||
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::LeaveFatalSection(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called."); |
|||
|
|||
// Entry and exit of fatal sections must be balanced.
|
|||
if (num_fatal_sections_entered == 0) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(Result{ErrorModule::AM, 512}); |
|||
return; |
|||
} |
|||
|
|||
--num_fatal_sections_entered; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
launchable_event->Signal(); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(launchable_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto permission = rp.PopEnum<ScreenshotPermission>(); |
|||
LOG_DEBUG(Service_AM, "called, permission={}", permission); |
|||
|
|||
screenshot_permission = permission; |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
bool flag = rp.Pop<bool>(); |
|||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
bool flag = rp.Pop<bool>(); |
|||
LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) { |
|||
// Takes 3 input u8s with each field located immediately after the previous
|
|||
// u8, these are bool flags. No output.
|
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
struct FocusHandlingModeParams { |
|||
u8 unknown0; |
|||
u8 unknown1; |
|||
u8 unknown2; |
|||
}; |
|||
const auto flags = rp.PopRaw<FocusHandlingModeParams>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}", |
|||
flags.unknown0, flags.unknown1, flags.unknown2); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) { |
|||
// Takes 3 input u8s with each field located immediately after the previous
|
|||
// u8, these are bool flags. No output.
|
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
bool enabled = rp.Pop<bool>(); |
|||
LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
|||
// create the layer in the Default display.
|
|||
const auto display_id = nvnflinger.OpenDisplay("Default"); |
|||
const auto layer_id = nvnflinger.CreateLayer(*display_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(*layer_id); |
|||
} |
|||
|
|||
void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); |
|||
} |
|||
|
|||
void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 6}; |
|||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); |
|||
rb.Push<s64>(system_shared_buffer_id); |
|||
rb.Push<s64>(system_shared_layer_id); |
|||
} |
|||
|
|||
void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess())); |
|||
rb.Push<s64>(system_shared_buffer_id); |
|||
} |
|||
|
|||
Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) { |
|||
if (buffer_sharing_enabled) { |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) { |
|||
return VI::ResultOperationFailed; |
|||
} |
|||
|
|||
const auto display_id = nvnflinger.OpenDisplay("Default"); |
|||
const auto result = nvnflinger.GetSystemBufferManager().Initialize( |
|||
&system_shared_buffer_id, &system_shared_layer_id, *display_id); |
|||
|
|||
if (result.IsSuccess()) { |
|||
buffer_sharing_enabled = true; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
|||
// create the layer in the Default display.
|
|||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
|||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
|||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
|||
// side effects.
|
|||
// TODO: Support multiple layers
|
|||
const auto display_id = nvnflinger.OpenDisplay("Default"); |
|||
const auto layer_id = nvnflinger.CreateLayer(*display_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(*layer_id); |
|||
} |
|||
|
|||
void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::ApproveToDisplay(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
idle_time_detection_extension = rp.Pop<u32>(); |
|||
LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", |
|||
idle_time_detection_extension); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u32>(idle_time_detection_extension); |
|||
} |
|||
|
|||
void ISelfController::ReportUserIsActive(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
is_auto_sleep_disabled = rp.Pop<bool>(); |
|||
|
|||
// On the system itself, if the previous state of is_auto_sleep_disabled
|
|||
// differed from the current value passed in, it'd signify the internal
|
|||
// window manager to update (and also increment some statistics like update counts)
|
|||
//
|
|||
// It'd also indicate this change to an idle handling context.
|
|||
//
|
|||
// However, given we're emulating this behavior, most of this can be ignored
|
|||
// and it's sufficient to simply set the member variable for querying via
|
|||
// IsAutoSleepDisabled().
|
|||
|
|||
LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called."); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(is_auto_sleep_disabled); |
|||
} |
|||
|
|||
void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called."); |
|||
|
|||
// This command returns the total number of system ticks since ISelfController creation
|
|||
// where the game was suspended. Since Yuzu doesn't implement game suspension, this command
|
|||
// can just always return 0 ticks.
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u64>(0); |
|||
} |
|||
|
|||
void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called."); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
// This service call sets an internal flag whether a notification is shown when an image is
|
|||
// captured. Currently we do not support capturing images via the capture button, so this can be
|
|||
// stubbed for now.
|
|||
const bool album_image_taken_notification_enabled = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}", |
|||
album_image_taken_notification_enabled); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); |
|||
|
|||
LOG_INFO(Service_AM, "called, report_option={}", report_option); |
|||
|
|||
const auto screenshot_service = |
|||
system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( |
|||
"caps:su"); |
|||
|
|||
if (screenshot_service) { |
|||
screenshot_service->CaptureAndSaveScreenshot(report_option); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const auto is_record_volume_muted = rp.Pop<bool>(); |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,72 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ISelfController final : public ServiceFramework<ISelfController> { |
|||
public: |
|||
explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_); |
|||
~ISelfController() override; |
|||
|
|||
private: |
|||
void Exit(HLERequestContext& ctx); |
|||
void LockExit(HLERequestContext& ctx); |
|||
void UnlockExit(HLERequestContext& ctx); |
|||
void EnterFatalSection(HLERequestContext& ctx); |
|||
void LeaveFatalSection(HLERequestContext& ctx); |
|||
void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx); |
|||
void SetScreenShotPermission(HLERequestContext& ctx); |
|||
void SetOperationModeChangedNotification(HLERequestContext& ctx); |
|||
void SetPerformanceModeChangedNotification(HLERequestContext& ctx); |
|||
void SetFocusHandlingMode(HLERequestContext& ctx); |
|||
void SetRestartMessageEnabled(HLERequestContext& ctx); |
|||
void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx); |
|||
void SetAlbumImageOrientation(HLERequestContext& ctx); |
|||
void IsSystemBufferSharingEnabled(HLERequestContext& ctx); |
|||
void GetSystemSharedBufferHandle(HLERequestContext& ctx); |
|||
void GetSystemSharedLayerHandle(HLERequestContext& ctx); |
|||
void CreateManagedDisplayLayer(HLERequestContext& ctx); |
|||
void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx); |
|||
void SetHandlesRequestToDisplay(HLERequestContext& ctx); |
|||
void ApproveToDisplay(HLERequestContext& ctx); |
|||
void SetIdleTimeDetectionExtension(HLERequestContext& ctx); |
|||
void GetIdleTimeDetectionExtension(HLERequestContext& ctx); |
|||
void ReportUserIsActive(HLERequestContext& ctx); |
|||
void SetAutoSleepDisabled(HLERequestContext& ctx); |
|||
void IsAutoSleepDisabled(HLERequestContext& ctx); |
|||
void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx); |
|||
void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx); |
|||
void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx); |
|||
void SaveCurrentScreenshot(HLERequestContext& ctx); |
|||
void SetRecordVolumeMuted(HLERequestContext& ctx); |
|||
|
|||
Result EnsureBufferSharingEnabled(Kernel::KProcess* process); |
|||
|
|||
enum class ScreenshotPermission : u32 { |
|||
Inherit = 0, |
|||
Enable = 1, |
|||
Disable = 2, |
|||
}; |
|||
|
|||
Nvnflinger::Nvnflinger& nvnflinger; |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
|
|||
Kernel::KEvent* launchable_event; |
|||
Kernel::KEvent* accumulated_suspended_tick_changed_event; |
|||
|
|||
u32 idle_time_detection_extension = 0; |
|||
u64 num_fatal_sections_entered = 0; |
|||
u64 system_shared_buffer_id = 0; |
|||
u64 system_shared_layer_id = 0; |
|||
bool is_auto_sleep_disabled = false; |
|||
bool buffer_sharing_enabled = false; |
|||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,60 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/storage.h"
|
|||
#include "core/hle/service/am/storage_accessor.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IStorageImpl::~IStorageImpl() = default; |
|||
|
|||
class StorageDataImpl final : public IStorageImpl { |
|||
public: |
|||
explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {} |
|||
|
|||
std::vector<u8>& GetData() override { |
|||
return buffer; |
|||
} |
|||
|
|||
const std::vector<u8>& GetData() const override { |
|||
return buffer; |
|||
} |
|||
|
|||
std::size_t GetSize() const override { |
|||
return buffer.size(); |
|||
} |
|||
|
|||
private: |
|||
std::vector<u8> buffer; |
|||
}; |
|||
|
|||
IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer) |
|||
: ServiceFramework{system_, "IStorage"}, |
|||
impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { |
|||
Register(); |
|||
} |
|||
|
|||
void IStorage::Register() { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IStorage::Open, "Open"}, |
|||
{1, nullptr, "OpenTransferStorage"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IStorage::~IStorage() = default; |
|||
|
|||
void IStorage::Open(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IStorageAccessor>(system, *this); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,42 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IStorageImpl { |
|||
public: |
|||
virtual ~IStorageImpl(); |
|||
virtual std::vector<u8>& GetData() = 0; |
|||
virtual const std::vector<u8>& GetData() const = 0; |
|||
virtual std::size_t GetSize() const = 0; |
|||
}; |
|||
|
|||
class IStorage final : public ServiceFramework<IStorage> { |
|||
public: |
|||
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer); |
|||
~IStorage() override; |
|||
|
|||
std::vector<u8>& GetData() { |
|||
return impl->GetData(); |
|||
} |
|||
|
|||
const std::vector<u8>& GetData() const { |
|||
return impl->GetData(); |
|||
} |
|||
|
|||
std::size_t GetSize() const { |
|||
return impl->GetSize(); |
|||
} |
|||
|
|||
private: |
|||
void Register(); |
|||
void Open(HLERequestContext& ctx); |
|||
|
|||
std::shared_ptr<IStorageImpl> impl; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,82 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/storage_accessor.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_) |
|||
: ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &IStorageAccessor::GetSize, "GetSize"}, |
|||
{10, &IStorageAccessor::Write, "Write"}, |
|||
{11, &IStorageAccessor::Read, "Read"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IStorageAccessor::~IStorageAccessor() = default; |
|||
|
|||
void IStorageAccessor::GetSize(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
|
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<u64>(backing.GetSize())); |
|||
} |
|||
|
|||
void IStorageAccessor::Write(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const u64 offset{rp.Pop<u64>()}; |
|||
const auto data{ctx.ReadBuffer()}; |
|||
const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; |
|||
|
|||
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); |
|||
|
|||
if (offset > backing.GetSize()) { |
|||
LOG_ERROR(Service_AM, |
|||
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", |
|||
backing.GetSize(), size, offset); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultInvalidOffset); |
|||
return; |
|||
} |
|||
|
|||
std::memcpy(backing.GetData().data() + offset, data.data(), size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IStorageAccessor::Read(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
|
|||
const u64 offset{rp.Pop<u64>()}; |
|||
const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; |
|||
|
|||
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); |
|||
|
|||
if (offset > backing.GetSize()) { |
|||
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", |
|||
backing.GetSize(), size, offset); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(AM::ResultInvalidOffset); |
|||
return; |
|||
} |
|||
|
|||
ctx.WriteBuffer(backing.GetData().data() + offset, size); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,24 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/am/storage.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { |
|||
public: |
|||
explicit IStorageAccessor(Core::System& system_, IStorage& backing_); |
|||
~IStorageAccessor() override; |
|||
|
|||
private: |
|||
void GetSize(HLERequestContext& ctx); |
|||
void Write(HLERequestContext& ctx); |
|||
void Read(HLERequestContext& ctx); |
|||
|
|||
IStorage& backing; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,135 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/applet_common_functions.h"
|
|||
#include "core/hle/service/am/application_creator.h"
|
|||
#include "core/hle/service/am/audio_controller.h"
|
|||
#include "core/hle/service/am/common_state_getter.h"
|
|||
#include "core/hle/service/am/debug_functions.h"
|
|||
#include "core/hle/service/am/display_controller.h"
|
|||
#include "core/hle/service/am/global_state_controller.h"
|
|||
#include "core/hle/service/am/home_menu_functions.h"
|
|||
#include "core/hle/service/am/library_applet_creator.h"
|
|||
#include "core/hle/service/am/library_applet_self_accessor.h"
|
|||
#include "core/hle/service/am/process_winding_controller.h"
|
|||
#include "core/hle/service/am/self_controller.h"
|
|||
#include "core/hle/service/am/system_applet_proxy.h"
|
|||
#include "core/hle/service/am/window_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_) |
|||
: ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, |
|||
msg_queue{std::move(msg_queue_)} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, |
|||
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"}, |
|||
{2, &ISystemAppletProxy::GetWindowController, "GetWindowController"}, |
|||
{3, &ISystemAppletProxy::GetAudioController, "GetAudioController"}, |
|||
{4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"}, |
|||
{10, nullptr, "GetProcessWindingController"}, |
|||
{11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"}, |
|||
{20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"}, |
|||
{21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"}, |
|||
{22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"}, |
|||
{23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"}, |
|||
{1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ISelfController>(system, nvnflinger); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IWindowController>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAudioController>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDisplayController>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<ILibraryAppletCreator>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IHomeMenuFunctions>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IGlobalStateController>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IApplicationCreator>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IAppletCommonFunctions>(system); |
|||
} |
|||
|
|||
void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_AM, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushIpcInterface<IDebugFunctions>(system); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,34 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/am/applet_message_queue.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { |
|||
public: |
|||
explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, |
|||
std::shared_ptr<AppletMessageQueue> msg_queue_, |
|||
Core::System& system_); |
|||
|
|||
private: |
|||
void GetCommonStateGetter(HLERequestContext& ctx); |
|||
void GetSelfController(HLERequestContext& ctx); |
|||
void GetWindowController(HLERequestContext& ctx); |
|||
void GetAudioController(HLERequestContext& ctx); |
|||
void GetDisplayController(HLERequestContext& ctx); |
|||
void GetLibraryAppletCreator(HLERequestContext& ctx); |
|||
void GetHomeMenuFunctions(HLERequestContext& ctx); |
|||
void GetGlobalStateController(HLERequestContext& ctx); |
|||
void GetApplicationCreator(HLERequestContext& ctx); |
|||
void GetAppletCommonFunctions(HLERequestContext& ctx); |
|||
void GetDebugFunctions(HLERequestContext& ctx); |
|||
|
|||
Nvnflinger::Nvnflinger& nvnflinger; |
|||
std::shared_ptr<AppletMessageQueue> msg_queue; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,55 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/window_controller.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
IWindowController::IWindowController(Core::System& system_) |
|||
: ServiceFramework{system_, "IWindowController"} { |
|||
// clang-format off
|
|||
static const FunctionInfo functions[] = { |
|||
{0, nullptr, "CreateWindow"}, |
|||
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, |
|||
{2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"}, |
|||
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, |
|||
{11, nullptr, "ReleaseForegroundRights"}, |
|||
{12, nullptr, "RejectToChangeIntoBackground"}, |
|||
{20, nullptr, "SetAppletWindowVisibility"}, |
|||
{21, nullptr, "SetAppletGpuTimeSlice"}, |
|||
}; |
|||
// clang-format on
|
|||
|
|||
RegisterHandlers(functions); |
|||
} |
|||
|
|||
IWindowController::~IWindowController() = default; |
|||
|
|||
void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) { |
|||
const u64 process_id = system.ApplicationProcess()->GetProcessId(); |
|||
|
|||
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u64>(process_id); |
|||
} |
|||
|
|||
void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) { |
|||
const u64 process_id = 0; |
|||
|
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 4}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push<u64>(process_id); |
|||
} |
|||
|
|||
void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) { |
|||
LOG_WARNING(Service_AM, "(STUBBED) called"); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,21 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class IWindowController final : public ServiceFramework<IWindowController> { |
|||
public: |
|||
explicit IWindowController(Core::System& system_); |
|||
~IWindowController() override; |
|||
|
|||
private: |
|||
void GetAppletResourceUserId(HLERequestContext& ctx); |
|||
void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx); |
|||
void AcquireForegroundRights(HLERequestContext& ctx); |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue