diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/am/am.cpp | 208 | ||||
-rw-r--r-- | src/core/hle/service/am/am.h | 21 | ||||
-rw-r--r-- | src/core/hle/service/am/applet_ae.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applets.cpp | 72 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/applets.h | 19 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/controller.cpp | 252 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/controller.h | 135 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.cpp | 64 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/am/applets/web_browser.cpp | 19 | ||||
-rw-r--r-- | src/core/hle/service/am/spsm.cpp | 16 |
11 files changed, 694 insertions, 117 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 557608e76..63421b963 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -10,6 +10,7 @@ #include "core/core.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/ipc_helpers.h" #include "core/hle/kernel/kernel.h" @@ -43,20 +44,15 @@ namespace Service::AM { -constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2}; -constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 0x3}; -constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7}; +constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 2}; +constexpr ResultCode ERR_NO_MESSAGES{ErrorModule::AM, 3}; +constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 503}; enum class LaunchParameterKind : u32 { ApplicationSpecific = 1, AccountPreselectedUser = 2, }; -enum class VrMode : u8 { - Disabled = 0, - Enabled = 1, -}; - constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; struct LaunchParameterAccountPreselectedUser { @@ -73,6 +69,7 @@ IWindowController::IWindowController(Core::System& system_) static const FunctionInfo functions[] = { {0, nullptr, "CreateWindow"}, {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, + {2, nullptr, "GetAppletResourceUserIdOfCallerApplet"}, {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, {11, nullptr, "ReleaseForegroundRights"}, {12, nullptr, "RejectToChangeIntoBackground"}, @@ -194,8 +191,8 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" {5, nullptr, "GetLastForegroundCaptureImageEx"}, {6, nullptr, "GetLastApplicationCaptureImageEx"}, {7, nullptr, "GetCallerAppletCaptureImageEx"}, - {8, nullptr, "TakeScreenShotOfOwnLayer"}, // 2.0.0+ - {9, nullptr, "CopyBetweenCaptureBuffers"}, // 5.0.0+ + {8, nullptr, "TakeScreenShotOfOwnLayer"}, + {9, nullptr, "CopyBetweenCaptureBuffers"}, {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, @@ -205,17 +202,14 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, - // 2.0.0+ {20, nullptr, "ClearCaptureBuffer"}, {21, nullptr, "ClearAppletTransitionBuffer"}, - // 4.0.0+ {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, {24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"}, {25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"}, {26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"}, {27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"}, - // 6.0.0+ {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, }; // clang-format on @@ -230,11 +224,12 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { static const FunctionInfo functions[] = { {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, {1, nullptr, "OpenMainApplication"}, - {10, nullptr, "EmulateButtonEvent"}, + {10, nullptr, "PerformSystemButtonPressing"}, {20, nullptr, "InvalidateTransitionLayer"}, {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, {40, nullptr, "GetAppletResourceUsageInfo"}, {100, nullptr, "SetCpuBoostModeForApplet"}, + {101, nullptr, "CancelCpuBoostModeForApplet"}, {110, nullptr, "PushToAppletBoundChannelForDebug"}, {111, nullptr, "TryPopFromAppletBoundChannelForDebug"}, {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"}, @@ -271,12 +266,14 @@ ISelfController::ISelfController(Core::System& system, {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, {17, nullptr, "SetControllerFirmwareUpdateSection"}, {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, - {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"}, + {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, {20, nullptr, "SetDesirableKeyboardLayout"}, {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, {41, nullptr, "IsSystemBufferSharingEnabled"}, {42, nullptr, "GetSystemSharedLayerHandle"}, {43, nullptr, "GetSystemSharedBufferHandle"}, + {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"}, + {45, nullptr, "SetManagedDisplayLayerSeparationMode"}, {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"}, {51, nullptr, "ApproveToDisplay"}, {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"}, @@ -381,7 +378,11 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& } void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + 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(RESULT_SUCCESS); @@ -445,7 +446,7 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& rb.Push(RESULT_SUCCESS); } -void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { +void ISelfController::SetAlbumImageOrientation(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -465,6 +466,24 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) rb.Push(*layer_id); } +void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::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 = nvflinger->OpenDisplay("Default"); + const auto layer_id = nvflinger->CreateLayer(*display_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(*layer_id); +} + void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -609,6 +628,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system, {20, nullptr, "PushToGeneralChannel"}, {30, nullptr, "GetHomeButtonReaderLockAccessor"}, {31, nullptr, "GetReaderLockAccessorEx"}, + {32, nullptr, "GetWriterLockAccessorEx"}, {40, nullptr, "GetCradleFwVersion"}, {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, @@ -623,11 +643,15 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system, {64, nullptr, "SetTvPowerStateMatchingMode"}, {65, nullptr, "GetApplicationIdByContentActionName"}, {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"}, + {67, nullptr, "CancelCpuBoostMode"}, {80, nullptr, "PerformSystemButtonPressingIfInFocus"}, {90, nullptr, "SetPerformanceConfigurationChangedNotification"}, {91, nullptr, "GetCurrentPerformanceConfiguration"}, + {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, {200, nullptr, "GetOperationModeSystemInfo"}, {300, nullptr, "GetSettingsPlatformRegion"}, + {400, nullptr, "ActivateMigrationService"}, + {401, nullptr, "DeactivateMigrationService"}, }; // clang-format on @@ -678,27 +702,21 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.PushEnum(VrMode::Disabled); + rb.Push(vr_mode_state); } void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto is_vr_mode_enabled = rp.Pop<bool>(); + vr_mode_state = rp.Pop<bool>(); - LOG_WARNING(Service_AM, "(STUBBED) called. is_vr_mode_enabled={}", is_vr_mode_enabled); + LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off"); IPC::ResponseBuilder rb{ctx, 2}; - if (!is_vr_mode_enabled) { - rb.Push(RESULT_SUCCESS); - } else { - // TODO: Find better error code for this - UNIMPLEMENTED_MSG("is_vr_mode_enabled={}", is_vr_mode_enabled); - rb.Push(RESULT_UNKNOWN); - } + rb.Push(RESULT_SUCCESS); } void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) { @@ -733,16 +751,16 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - if (Settings::values.use_docked_mode) { + if (Settings::values.use_docked_mode.GetValue()) { rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * - static_cast<u32>(Settings::values.resolution_factor)); + static_cast<u32>(Settings::values.resolution_factor.GetValue())); rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * - static_cast<u32>(Settings::values.resolution_factor)); + static_cast<u32>(Settings::values.resolution_factor.GetValue())); } else { rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * - static_cast<u32>(Settings::values.resolution_factor)); + static_cast<u32>(Settings::values.resolution_factor.GetValue())); rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * - static_cast<u32>(Settings::values.resolution_factor)); + static_cast<u32>(Settings::values.resolution_factor.GetValue())); } } @@ -806,7 +824,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { - const bool use_docked_mode{Settings::values.use_docked_mode}; + const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()}; LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); IPC::ResponseBuilder rb{ctx, 3}; @@ -835,6 +853,7 @@ public: {25, nullptr, "Terminate"}, {30, &ILibraryAppletAccessor::GetResult, "GetResult"}, {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"}, + {60, nullptr, "PresetLibraryAppletGpuTimeSliceZero"}, {100, &ILibraryAppletAccessor::PushInData, "PushInData"}, {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"}, {102, nullptr, "PushExtraStorage"}, @@ -845,7 +864,7 @@ public: {110, nullptr, "NeedsToExitProcess"}, {120, nullptr, "GetLibraryAppletInfo"}, {150, nullptr, "RequestForAppletToGetForeground"}, - {160, nullptr, "GetIndirectLayerConsumerHandle"}, + {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, }; // clang-format on @@ -903,7 +922,7 @@ private: void PopOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - const auto storage = applet->GetBroker().PopNormalDataToGame(); + auto storage = applet->GetBroker().PopNormalDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current normal channel"); @@ -934,7 +953,7 @@ private: void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - const auto storage = applet->GetBroker().PopInteractiveDataToGame(); + auto storage = applet->GetBroker().PopInteractiveDataToGame(); if (storage == nullptr) { LOG_ERROR(Service_AM, "storage is a nullptr. There is no data in the current interactive channel"); @@ -964,6 +983,18 @@ private: rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); } + void GetIndirectLayerConsumerHandle(Kernel::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(RESULT_SUCCESS); + rb.Push(handle); + } + std::shared_ptr<Applets::Applet> applet; }; @@ -1135,10 +1166,12 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {24, nullptr, "GetLaunchStorageInfoForDebug"}, {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, + {27, nullptr, "CreateCacheStorage"}, {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, + {34, nullptr, "SelectApplicationLicense"}, {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"}, {60, nullptr, "SetMediaPlaybackStateForApplication"}, @@ -1148,6 +1181,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {68, nullptr, "RequestFlushGamePlayingMovieForDebug"}, {70, nullptr, "RequestToShutdown"}, {71, nullptr, "RequestToReboot"}, + {72, nullptr, "RequestToSleep"}, {80, nullptr, "ExitAndRequestToShowThanksMessage"}, {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"}, {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"}, @@ -1158,13 +1192,17 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, + {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, + {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, - {140, nullptr, "GetFriendInvitationStorageChannelEvent"}, + {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, {141, nullptr, "TryPopFromFriendInvitationStorageChannel"}, {150, nullptr, "GetNotificationStorageChannelEvent"}, {151, nullptr, "TryPopFromNotificationStorageChannel"}, {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, {170, nullptr, "SetHdcpAuthenticationActivated"}, + {180, nullptr, "GetLaunchRequiredVersion"}, + {181, nullptr, "UpgradeLaunchRequiredVersion"}, {500, nullptr, "StartContinuousRecordingFlushForDebug"}, {1000, nullptr, "CreateMovieMaker"}, {1001, nullptr, "PrepareForJit"}, @@ -1176,6 +1214,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) auto& kernel = system.Kernel(); gpu_error_detected_event = Kernel::WritableEvent::CreateEventPair( kernel, "IApplicationFunctions:GpuErrorDetectedSystemEvent"); + + friend_invitation_storage_channel_event = Kernel::WritableEvent::CreateEventPair( + kernel, "IApplicationFunctions:FriendInvitationStorageChannelEvent"); } IApplicationFunctions::~IApplicationFunctions() = default; @@ -1307,12 +1348,12 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); - FileSys::SaveDataDescriptor descriptor{}; - descriptor.title_id = system.CurrentProcess()->GetTitleID(); - descriptor.user_id = user_id; - descriptor.type = FileSys::SaveDataType::SaveData; + FileSys::SaveDataAttribute attribute{}; + attribute.title_id = system.CurrentProcess()->GetTitleID(); + attribute.user_id = user_id; + attribute.type = FileSys::SaveDataType::SaveData; const auto res = system.GetFileSystemController().CreateSaveData( - FileSys::SaveDataSpaceId::NandUser, descriptor); + FileSys::SaveDataSpaceId::NandUser, attribute); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(res.Code()); @@ -1333,12 +1374,37 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { } void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "called"); + + std::array<u8, 0x10> version_string{}; + + const auto res = [this] { + const auto title_id = system.CurrentProcess()->GetTitleID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto res = pm.GetControlMetadata(); + if (res.first != nullptr) { + return res; + } + + 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 { + constexpr char default_version[]{"1.0.0"}; + std::memcpy(version_string.data(), default_version, sizeof(default_version)); + } IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(1); - rb.Push<u64>(0); + rb.PushRaw(version_string); } void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { @@ -1348,9 +1414,23 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { // Get supported languages from NACP, if possible // Default to 0 (all languages supported) u32 supported_languages = 0; - FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; - const auto res = pm.GetControlMetadata(); + const auto res = [this] { + const auto title_id = system.CurrentProcess()->GetTitleID(); + + const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + auto res = pm.GetControlMetadata(); + if (res.first != nullptr) { + return res; + } + + 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(); } @@ -1482,6 +1562,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque rb.Push<u32>(0); } +void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<s32>(previous_program_index); +} + void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); @@ -1490,6 +1578,14 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon rb.PushCopyObjects(gpu_error_detected_event.readable); } +void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_AM, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); @@ -1504,14 +1600,15 @@ void InstallInterfaces(SM::ServiceManager& service_manager, std::make_shared<TCAP>()->InstallAsService(service_manager); } -IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { +IHomeMenuFunctions::IHomeMenuFunctions(Kernel::KernelCore& kernel) + : ServiceFramework("IHomeMenuFunctions"), kernel(kernel) { // clang-format off static const FunctionInfo functions[] = { {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, {11, nullptr, "LockForeground"}, {12, nullptr, "UnlockForeground"}, {20, nullptr, "PopFromGeneralChannel"}, - {21, nullptr, "GetPopFromGeneralChannelEvent"}, + {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"}, {30, nullptr, "GetHomeButtonWriterLockAccessor"}, {31, nullptr, "GetWriterLockAccessorEx"}, {100, nullptr, "PopRequestLaunchApplicationForDebug"}, @@ -1521,6 +1618,9 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" // clang-format on RegisterHandlers(functions); + + pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair( + kernel, "IHomeMenuFunctions:PopFromGeneralChannelEvent"); } IHomeMenuFunctions::~IHomeMenuFunctions() = default; @@ -1532,6 +1632,14 @@ void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) rb.Push(RESULT_SUCCESS); } +void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(pop_from_general_channel_event.readable); +} + IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { // clang-format off static const FunctionInfo functions[] = { diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 53cfce10f..bcc06affe 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -138,8 +138,9 @@ private: void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx); void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx); - void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx); + void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); + void CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx); void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); @@ -148,6 +149,12 @@ private: void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); + enum class ScreenshotPermission : u32 { + Inherit = 0, + Enable = 1, + Disable = 2, + }; + Core::System& system; std::shared_ptr<NVFlinger::NVFlinger> nvflinger; Kernel::EventPair launchable_event; @@ -156,6 +163,7 @@ private: u32 idle_time_detection_extension = 0; u64 num_fatal_sections_entered = 0; bool is_auto_sleep_disabled = false; + ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit; }; class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { @@ -191,6 +199,7 @@ private: Core::System& system; std::shared_ptr<AppletMessageQueue> msg_queue; + bool vr_mode_state{}; }; class IStorageImpl { @@ -279,21 +288,29 @@ private: void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); + void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); + void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); bool launch_popped_application_specific = false; bool launch_popped_account_preselect = false; + s32 previous_program_index{-1}; Kernel::EventPair gpu_error_detected_event; + Kernel::EventPair friend_invitation_storage_channel_event; Core::System& system; }; class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { public: - IHomeMenuFunctions(); + explicit IHomeMenuFunctions(Kernel::KernelCore& kernel); ~IHomeMenuFunctions() override; private: void RequestToGetForeground(Kernel::HLERequestContext& ctx); + void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); + + Kernel::EventPair pop_from_general_channel_event; + Kernel::KernelCore& kernel; }; class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index e454b77d8..be23ca747 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -3,8 +3,8 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/process.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/nvflinger/nvflinger.h" @@ -202,7 +202,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IHomeMenuFunctions>(); + rb.PushIpcInterface<IHomeMenuFunctions>(system.Kernel()); } void GetGlobalStateController(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index c3261f3e6..2b626bb40 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,6 +5,7 @@ #include <cstring> #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/profile_select.h" @@ -15,6 +16,7 @@ #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applets/controller.h" #include "core/hle/service/am/applets/error.h" #include "core/hle/service/am/applets/general_backend.h" #include "core/hle/service/am/applets/profile_select.h" @@ -140,14 +142,14 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, +AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, + ErrorApplet error, ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser, - ECommerceApplet e_commerce) - : parental_controls{std::move(parental_controls)}, error{std::move(error)}, - photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, - software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, - e_commerce{std::move(e_commerce)} {} + SoftwareKeyboard software_keyboard, WebBrowser web_browser) + : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)}, + parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)}, + profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)}, + web_browser{std::move(web_browser)} {} AppletFrontendSet::~AppletFrontendSet() = default; @@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { } void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { - if (set.parental_controls != nullptr) - frontend.parental_controls = std::move(set.parental_controls); - if (set.error != nullptr) + if (set.controller != nullptr) { + frontend.controller = std::move(set.controller); + } + + if (set.e_commerce != nullptr) { + frontend.e_commerce = std::move(set.e_commerce); + } + + if (set.error != nullptr) { frontend.error = std::move(set.error); - if (set.photo_viewer != nullptr) + } + + if (set.parental_controls != nullptr) { + frontend.parental_controls = std::move(set.parental_controls); + } + + if (set.photo_viewer != nullptr) { frontend.photo_viewer = std::move(set.photo_viewer); - if (set.profile_select != nullptr) + } + + if (set.profile_select != nullptr) { frontend.profile_select = std::move(set.profile_select); - if (set.software_keyboard != nullptr) + } + + if (set.software_keyboard != nullptr) { frontend.software_keyboard = std::move(set.software_keyboard); - if (set.web_browser != nullptr) + } + + if (set.web_browser != nullptr) { frontend.web_browser = std::move(set.web_browser); - if (set.e_commerce != nullptr) - frontend.e_commerce = std::move(set.e_commerce); + } } void AppletManager::SetDefaultAppletFrontendSet() { @@ -186,15 +205,24 @@ void AppletManager::SetDefaultAppletFrontendSet() { } void AppletManager::SetDefaultAppletsIfMissing() { - if (frontend.parental_controls == nullptr) { - frontend.parental_controls = - std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + if (frontend.controller == nullptr) { + frontend.controller = + std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager()); + } + + if (frontend.e_commerce == nullptr) { + frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); } if (frontend.error == nullptr) { frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); } + if (frontend.parental_controls == nullptr) { + frontend.parental_controls = + std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); + } + if (frontend.photo_viewer == nullptr) { frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); } @@ -211,10 +239,6 @@ void AppletManager::SetDefaultAppletsIfMissing() { if (frontend.web_browser == nullptr) { frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); } - - if (frontend.e_commerce == nullptr) { - frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>(); - } } void AppletManager::ClearAll() { @@ -225,6 +249,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { switch (id) { case AppletId::Auth: return std::make_shared<Auth>(system, *frontend.parental_controls); + case AppletId::Controller: + return std::make_shared<Controller>(system, *frontend.controller); case AppletId::Error: return std::make_shared<Error>(system, *frontend.error); case AppletId::ProfileSelect: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index e75be86a2..a1f4cf897 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -17,6 +17,7 @@ class System; } namespace Core::Frontend { +class ControllerApplet; class ECommerceApplet; class ErrorApplet; class ParentalControlsApplet; @@ -155,19 +156,20 @@ protected: }; struct AppletFrontendSet { - using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; + using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; + using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>; using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; + using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; - using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>; AppletFrontendSet(); - AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, - PhotoViewer photo_viewer, ProfileSelect profile_select, - SoftwareKeyboard software_keyboard, WebBrowser web_browser, - ECommerceApplet e_commerce); + AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error, + ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, + ProfileSelect profile_select, SoftwareKeyboard software_keyboard, + WebBrowser web_browser); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -176,13 +178,14 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; - ParentalControlsApplet parental_controls; + ControllerApplet controller; + ECommerceApplet e_commerce; ErrorApplet error; + ParentalControlsApplet parental_controls; PhotoViewer photo_viewer; ProfileSelect profile_select; SoftwareKeyboard software_keyboard; WebBrowser web_browser; - ECommerceApplet e_commerce; }; class AppletManager { diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp new file mode 100644 index 000000000..3ca63f020 --- /dev/null +++ b/src/core/hle/service/am/applets/controller.cpp @@ -0,0 +1,252 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <cstring> + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/controller.h" +#include "core/hle/result.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/controller.h" +#include "core/hle/service/hid/controllers/npad.h" + +namespace Service::AM::Applets { + +// This error code (0x183ACA) is thrown when the applet fails to initialize. +[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101}; +// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2. +[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102}; + +static Core::Frontend::ControllerParameters ConvertToFrontendParameters( + ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, + std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { + HID::Controller_NPad::NpadStyleSet npad_style_set; + npad_style_set.raw = private_arg.style_set; + + return { + .min_players = std::max(s8(1), header.player_count_min), + .max_players = header.player_count_max, + .keep_controllers_connected = header.enable_take_over_connection, + .enable_single_mode = header.enable_single_mode, + .enable_border_color = header.enable_identification_color, + .border_colors = identification_colors, + .enable_explain_text = enable_text, + .explain_text = text, + .allow_pro_controller = npad_style_set.pro_controller == 1, + .allow_handheld = npad_style_set.handheld == 1, + .allow_dual_joycons = npad_style_set.joycon_dual == 1, + .allow_left_joycon = npad_style_set.joycon_left == 1, + .allow_right_joycon = npad_style_set.joycon_right == 1, + }; +} + +Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) + : Applet{system_.Kernel()}, frontend(frontend_) {} + +Controller::~Controller() = default; + +void Controller::Initialize() { + Applet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Controller Applet."); + + LOG_DEBUG(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + controller_applet_version = ControllerAppletVersion{common_args.library_version}; + + const auto private_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(private_arg_storage != nullptr); + + const auto& private_arg = private_arg_storage->GetData(); + ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); + + std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size()); + ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), + "Unknown ControllerSupportArgPrivate revision={} with size={}", + controller_applet_version, controller_private_arg.arg_private_size); + + // Some games such as Cave Story+ set invalid values for the ControllerSupportMode. + // Defer to arg_size to set the ControllerSupportMode. + if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) { + switch (controller_private_arg.arg_size) { + case sizeof(ControllerSupportArgOld): + case sizeof(ControllerSupportArgNew): + controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; + break; + case sizeof(ControllerUpdateFirmwareArg): + controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate; + break; + default: + UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}", + controller_private_arg.mode, controller_private_arg.arg_size); + controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport; + break; + } + } + + // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller. + // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem. + if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) { + if (controller_private_arg.flag_1 && + controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) { + controller_private_arg.caller = ControllerSupportCaller::System; + } else { + controller_private_arg.caller = ControllerSupportCaller::Application; + } + } + + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: + case ControllerSupportMode::ShowControllerStrapGuide: { + const auto user_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(user_arg_storage != nullptr); + + const auto& user_arg = user_arg_storage->GetData(); + switch (controller_applet_version) { + case ControllerAppletVersion::Version3: + case ControllerAppletVersion::Version4: + case ControllerAppletVersion::Version5: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); + std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size()); + break; + case ControllerAppletVersion::Version7: + ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size()); + break; + default: + UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", + controller_applet_version, controller_private_arg.arg_size); + ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); + std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); + break; + } + break; + } + case ControllerSupportMode::ShowControllerFirmwareUpdate: { + const auto update_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(update_arg_storage != nullptr); + + const auto& update_arg = update_arg_storage->GetData(); + ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg)); + + std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size()); + break; + } + default: { + UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); + break; + } + } +} + +bool Controller::TransactionComplete() const { + return complete; +} + +ResultCode Controller::GetStatus() const { + return status; +} + +void Controller::ExecuteInteractive() { + UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); +} + +void Controller::Execute() { + switch (controller_private_arg.mode) { + case ControllerSupportMode::ShowControllerSupport: { + const auto parameters = [this] { + switch (controller_applet_version) { + case ControllerAppletVersion::Version3: + case ControllerAppletVersion::Version4: + case ControllerAppletVersion::Version5: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_old.header, + controller_user_arg_old.enable_explain_text, + std::vector<IdentificationColor>( + controller_user_arg_old.identification_colors.begin(), + controller_user_arg_old.identification_colors.end()), + std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(), + controller_user_arg_old.explain_text.end())); + case ControllerAppletVersion::Version7: + default: + return ConvertToFrontendParameters( + controller_private_arg, controller_user_arg_new.header, + controller_user_arg_new.enable_explain_text, + std::vector<IdentificationColor>( + controller_user_arg_new.identification_colors.begin(), + controller_user_arg_new.identification_colors.end()), + std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(), + controller_user_arg_new.explain_text.end())); + } + }(); + + is_single_mode = parameters.enable_single_mode; + + LOG_DEBUG(Service_HID, + "Controller Parameters: min_players={}, max_players={}, " + "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, " + "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, " + "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}", + parameters.min_players, parameters.max_players, + parameters.keep_controllers_connected, parameters.enable_single_mode, + parameters.enable_border_color, parameters.enable_explain_text, + parameters.allow_pro_controller, parameters.allow_handheld, + parameters.allow_dual_joycons, parameters.allow_left_joycon, + parameters.allow_right_joycon); + + frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters); + break; + } + case ControllerSupportMode::ShowControllerStrapGuide: + case ControllerSupportMode::ShowControllerFirmwareUpdate: + UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented", + controller_private_arg.mode); + [[fallthrough]]; + default: { + ConfigurationComplete(); + break; + } + } +} + +void Controller::ConfigurationComplete() { + ControllerSupportResultInfo result_info{}; + + const auto& players = Settings::values.players.GetValue(); + + // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. + // Otherwise, only count connected players from P1-P8. + result_info.player_count = + is_single_mode ? 1 + : static_cast<s8>(std::count_if( + players.begin(), players.end() - 2, + [](Settings::PlayerInput player) { return player.connected; })); + + result_info.selected_id = HID::Controller_NPad::IndexToNPad( + std::distance(players.begin(), + std::find_if(players.begin(), players.end(), + [](Settings::PlayerInput player) { return player.connected; }))); + + result_info.result = 0; + + LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}", + result_info.player_count, result_info.selected_id, result_info.result); + + complete = true; + out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); + std::memcpy(out_data.data(), &result_info, out_data.size()); + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data))); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h new file mode 100644 index 000000000..a7a1f2b65 --- /dev/null +++ b/src/core/hle/service/am/applets/controller.h @@ -0,0 +1,135 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <vector> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Core { +class System; +} + +namespace Service::AM::Applets { + +using IdentificationColor = std::array<u8, 4>; +using ExplainText = std::array<char, 0x81>; + +enum class ControllerAppletVersion : u32_le { + Version3 = 0x3, // 1.0.0 - 2.3.0 + Version4 = 0x4, // 3.0.0 - 5.1.0 + Version5 = 0x5, // 6.0.0 - 7.0.1 + Version7 = 0x7, // 8.0.0+ +}; + +enum class ControllerSupportMode : u8 { + ShowControllerSupport, + ShowControllerStrapGuide, + ShowControllerFirmwareUpdate, + + MaxControllerSupportMode, +}; + +enum class ControllerSupportCaller : u8 { + Application, + System, + + MaxControllerSupportCaller, +}; + +struct ControllerSupportArgPrivate { + u32 arg_private_size{}; + u32 arg_size{}; + bool flag_0{}; + bool flag_1{}; + ControllerSupportMode mode{}; + ControllerSupportCaller caller{}; + u32 style_set{}; + u32 joy_hold_type{}; +}; +static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, + "ControllerSupportArgPrivate has incorrect size."); + +struct ControllerSupportArgHeader { + s8 player_count_min{}; + s8 player_count_max{}; + bool enable_take_over_connection{}; + bool enable_left_justify{}; + bool enable_permit_joy_dual{}; + bool enable_single_mode{}; + bool enable_identification_color{}; +}; +static_assert(sizeof(ControllerSupportArgHeader) == 0x7, + "ControllerSupportArgHeader has incorrect size."); + +// LibraryAppletVersion 0x3, 0x4, 0x5 +struct ControllerSupportArgOld { + ControllerSupportArgHeader header{}; + std::array<IdentificationColor, 4> identification_colors{}; + bool enable_explain_text{}; + std::array<ExplainText, 4> explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgOld) == 0x21C, + "ControllerSupportArgOld has incorrect size."); + +// LibraryAppletVersion 0x7 +struct ControllerSupportArgNew { + ControllerSupportArgHeader header{}; + std::array<IdentificationColor, 8> identification_colors{}; + bool enable_explain_text{}; + std::array<ExplainText, 8> explain_text{}; +}; +static_assert(sizeof(ControllerSupportArgNew) == 0x430, + "ControllerSupportArgNew has incorrect size."); + +struct ControllerUpdateFirmwareArg { + bool enable_force_update{}; + INSERT_PADDING_BYTES(3); +}; +static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4, + "ControllerUpdateFirmwareArg has incorrect size."); + +struct ControllerSupportResultInfo { + s8 player_count{}; + INSERT_PADDING_BYTES(3); + u32 selected_id{}; + u32 result{}; +}; +static_assert(sizeof(ControllerSupportResultInfo) == 0xC, + "ControllerSupportResultInfo has incorrect size."); + +class Controller final : public Applet { +public: + explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_); + ~Controller() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void ConfigurationComplete(); + +private: + const Core::Frontend::ControllerApplet& frontend; + + ControllerAppletVersion controller_applet_version; + ControllerSupportArgPrivate controller_private_arg; + ControllerSupportArgOld controller_user_arg_old; + ControllerSupportArgNew controller_user_arg_new; + ControllerUpdateFirmwareArg controller_update_arg; + bool complete{false}; + ResultCode status{RESULT_SUCCESS}; + bool is_single_mode{false}; + std::vector<u8> out_data; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 54e63c138..bdeb0737a 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -13,11 +13,23 @@ namespace Service::AM::Applets { +namespace { +enum class Request : u32 { + Finalize = 0x4, + SetUserWordInfo = 0x6, + SetCustomizeDic = 0x7, + Calc = 0xa, + SetCustomizedDictionaries = 0xb, + UnsetCustomizedDictionaries = 0xc, + UnknownD = 0xd, + UnknownE = 0xe, +}; +constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8; constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; constexpr std::size_t DEFAULT_MAX_LENGTH = 500; constexpr bool INTERACTIVE_STATUS_OK = false; - +} // Anonymous namespace static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( KeyboardConfig config, std::u16string initial_text) { Core::Frontend::SoftwareKeyboardParameters params{}; @@ -30,7 +42,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( config.sub_text.size()); params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(), config.guide_text.size()); - params.initial_text = initial_text; + params.initial_text = std::move(initial_text); params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit; params.password = static_cast<bool>(config.is_password); params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position); @@ -47,6 +59,7 @@ SoftwareKeyboard::~SoftwareKeyboard() = default; void SoftwareKeyboard::Initialize() { complete = false; + is_inline = false; initial_text.clear(); final_data.clear(); @@ -56,11 +69,16 @@ void SoftwareKeyboard::Initialize() { ASSERT(keyboard_config_storage != nullptr); const auto& keyboard_config = keyboard_config_storage->GetData(); + if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) { + is_inline = true; + return; + } + ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); const auto work_buffer_storage = broker.PopNormalDataToApplet(); - ASSERT(work_buffer_storage != nullptr); + ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; }); const auto& work_buffer = work_buffer_storage->GetData(); if (config.initial_string_size == 0) @@ -87,16 +105,31 @@ void SoftwareKeyboard::ExecuteInteractive() { const auto storage = broker.PopInteractiveDataToApplet(); ASSERT(storage != nullptr); const auto data = storage->GetData(); - const auto status = static_cast<bool>(data[0]); - - if (status == INTERACTIVE_STATUS_OK) { - complete = true; + if (!is_inline) { + const auto status = static_cast<bool>(data[0]); + if (status == INTERACTIVE_STATUS_OK) { + complete = true; + } else { + std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; + std::memcpy(string.data(), data.data() + 4, string.size() * 2); + frontend.SendTextCheckDialog( + Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), + [this] { broker.SignalStateChanged(); }); + } } else { - std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; - std::memcpy(string.data(), data.data() + 4, string.size() * 2); - frontend.SendTextCheckDialog( - Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), - [this] { broker.SignalStateChanged(); }); + Request request{}; + std::memcpy(&request, data.data(), sizeof(Request)); + + switch (request) { + case Request::Calc: { + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{1})); + broker.SignalStateChanged(); + break; + } + default: + UNIMPLEMENTED_MSG("Request {:X} is not implemented", request); + break; + } } } @@ -108,9 +141,10 @@ void SoftwareKeyboard::Execute() { } const auto parameters = ConvertToFrontendParameters(config, initial_text); - - frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); }, - parameters); + if (!is_inline) { + frontend.RequestText( + [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters); + } } void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h index ef4801fc6..5a3824b5a 100644 --- a/src/core/hle/service/am/applets/software_keyboard.h +++ b/src/core/hle/service/am/applets/software_keyboard.h @@ -78,6 +78,7 @@ private: KeyboardConfig config; std::u16string initial_text; bool complete = false; + bool is_inline = false; std::vector<u8> final_data; }; diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 9f30e167d..efe595c4f 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -293,8 +293,8 @@ void WebBrowser::Finalize() { broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data))); broker.SignalStateChanged(); - if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { - FileUtil::DeleteDirRecursively(temporary_dir); + if (!temporary_dir.empty() && Common::FS::IsDirectory(temporary_dir)) { + Common::FS::DeleteDirRecursively(temporary_dir); } } @@ -452,10 +452,10 @@ void WebBrowser::InitializeOffline() { }; temporary_dir = - FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" + - WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], - FileUtil::DirectorySeparator::PlatformDefault); - FileUtil::DeleteDirRecursively(temporary_dir); + Common::FS::SanitizePath(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) + + "web_applet_" + WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], + Common::FS::DirectorySeparator::PlatformDefault); + Common::FS::DeleteDirRecursively(temporary_dir); u64 title_id = 0; // 0 corresponds to current process ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8); @@ -492,8 +492,8 @@ void WebBrowser::InitializeOffline() { } filename = - FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, - FileUtil::DirectorySeparator::PlatformDefault); + Common::FS::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, + Common::FS::DirectorySeparator::PlatformDefault); } void WebBrowser::ExecuteShop() { @@ -551,7 +551,8 @@ void WebBrowser::ExecuteShop() { } void WebBrowser::ExecuteOffline() { - frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); + frontend.OpenPageLocal( + filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); } } // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp index 003ee8667..f27729ce7 100644 --- a/src/core/hle/service/am/spsm.cpp +++ b/src/core/hle/service/am/spsm.cpp @@ -10,17 +10,17 @@ SPSM::SPSM() : ServiceFramework{"spsm"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetState"}, - {1, nullptr, "SleepSystemAndWaitAwake"}, - {2, nullptr, "Unknown1"}, - {3, nullptr, "Unknown2"}, + {1, nullptr, "EnterSleep"}, + {2, nullptr, "GetLastWakeReason"}, + {3, nullptr, "Shutdown"}, {4, nullptr, "GetNotificationMessageEventHandle"}, - {5, nullptr, "Unknown3"}, - {6, nullptr, "Unknown4"}, - {7, nullptr, "Unknown5"}, + {5, nullptr, "ReceiveNotificationMessage"}, + {6, nullptr, "AnalyzeLogForLastSleepWakeSequence"}, + {7, nullptr, "ResetEventLog"}, {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"}, {9, nullptr, "ChangeHomeButtonLongPressingTime"}, - {10, nullptr, "Unknown6"}, - {11, nullptr, "Unknown7"}, + {10, nullptr, "PutErrorState"}, + {11, nullptr, "InvalidateCurrentHomeButtonPressing"}, }; // clang-format on |