diff options
Diffstat (limited to 'src/core/hle/service')
31 files changed, 1531 insertions, 779 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 3a7b6da84..d1cbe0e44 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -8,6 +8,7 @@ #include <stack> #include "audio_core/audio_renderer.h" #include "core/core.h" +#include "core/file_sys/savedata_factory.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -19,8 +20,10 @@ #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/am/applets/profile_select.h" #include "core/hle/service/am/applets/software_keyboard.h" #include "core/hle/service/am/applets/stub_applet.h" +#include "core/hle/service/am/applets/web_browser.h" #include "core/hle/service/am/idle.h" #include "core/hle/service/am/omm.h" #include "core/hle/service/am/spsm.h" @@ -36,10 +39,13 @@ 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}; enum class AppletId : u32 { + ProfileSelect = 0x10, SoftwareKeyboard = 0x11, + LibAppletOff = 0x17, }; constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; @@ -71,10 +77,13 @@ IWindowController::IWindowController() : ServiceFramework("IWindowController") { IWindowController::~IWindowController() = default; void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + const u64 process_id = Core::System::GetInstance().Kernel().CurrentProcess()->GetProcessID(); + + LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id); + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); - rb.Push<u64>(0); + rb.Push<u64>(process_id); } void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) { @@ -454,9 +463,17 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); + const auto message = msg_queue->PopMessage(); IPC::ResponseBuilder rb{ctx, 3}; + + if (message == AppletMessageQueue::AppletMessage::NoMessage) { + LOG_ERROR(Service_AM, "Message queue is empty"); + rb.Push(ERR_NO_MESSAGES); + rb.PushEnum<AppletMessageQueue::AppletMessage>(message); + return; + } rb.Push(RESULT_SUCCESS); - rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); + rb.PushEnum<AppletMessageQueue::AppletMessage>(message); } void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { @@ -565,7 +582,6 @@ private: void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); - applet->GetBroker().SignalStateChanged(); const auto event = applet->GetBroker().GetStateChangedEvent(); IPC::ResponseBuilder rb{ctx, 2, 1}; @@ -716,10 +732,10 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - LOG_DEBUG(Service_AM, "called, offset={}", offset); - const std::vector<u8> data{ctx.ReadBuffer()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); + if (data.size() > backing.buffer.size() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", @@ -739,10 +755,10 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - LOG_DEBUG(Service_AM, "called, offset={}", offset); - const std::size_t size{ctx.GetWriteBufferSize()}; + LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); + if (size > backing.buffer.size() - offset) { LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", backing.buffer.size(), size, offset); @@ -773,8 +789,12 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default; static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { switch (id) { + case AppletId::ProfileSelect: + return std::make_shared<Applets::ProfileSelect>(); case AppletId::SoftwareKeyboard: return std::make_shared<Applets::SoftwareKeyboard>(); + case AppletId::LibAppletOff: + return std::make_shared<Applets::WebBrowser>(); default: LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", static_cast<u32>(id)); @@ -859,8 +879,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"}, {24, nullptr, "GetLaunchStorageInfoForDebug"}, - {25, nullptr, "ExtendSaveData"}, - {26, nullptr, "GetSaveDataSize"}, + {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, + {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, @@ -1037,6 +1057,48 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { rb.Push<u64>(0); } +void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw<FileSys::SaveDataType>()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw<u128>()}; + const auto new_normal_size{rp.PopRaw<u64>()}; + const auto new_journal_size{rp.PopRaw<u64>()}; + + 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); + + FileSystem::WriteSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id, + {new_normal_size, new_journal_size}); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + + // 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(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto type{rp.PopRaw<FileSys::SaveDataType>()}; + rp.Skip(1, false); + const auto user_id{rp.PopRaw<u128>()}; + + LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), + user_id[1], user_id[0]); + + const auto size = + FileSystem::ReadSaveDataSize(type, Core::CurrentProcess()->GetTitleID(), user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.Push(size.normal); + rb.Push(size.journal); +} + void InstallInterfaces(SM::ServiceManager& service_manager, std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { auto message_queue = std::make_shared<AppletMessageQueue>(); diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 34c45fadf..b6113cfdd 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -206,6 +206,8 @@ private: void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx); void NotifyRunning(Kernel::HLERequestContext& ctx); void GetPseudoDeviceId(Kernel::HLERequestContext& ctx); + void ExtendSaveData(Kernel::HLERequestContext& ctx); + void GetSaveDataSize(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 47da35537..a6064c63f 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -6,7 +6,7 @@ #include "common/assert.h" #include "core/core.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applets.h" @@ -16,11 +16,11 @@ namespace Service::AM::Applets { AppletDataBroker::AppletDataBroker() { auto& kernel = Core::System::GetInstance().Kernel(); state_changed_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent"); pop_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent"); pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair( - kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); + kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); } AppletDataBroker::~AppletDataBroker() = default; diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index b0a8913c3..37424c379 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -7,7 +7,7 @@ #include <memory> #include <queue> #include "common/swap.h" -#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/object.h" #include "core/hle/kernel/writable_event.h" union ResultCode; diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp new file mode 100644 index 000000000..14e2a1fee --- /dev/null +++ b/src/core/hle/service/am/applets/profile_select.cpp @@ -0,0 +1,77 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <cstring> + +#include "common/assert.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/frontend/applets/profile_select.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/profile_select.h" + +namespace Service::AM::Applets { + +constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; + +ProfileSelect::ProfileSelect() = default; +ProfileSelect::~ProfileSelect() = default; + +void ProfileSelect::Initialize() { + complete = false; + status = RESULT_SUCCESS; + final_data.clear(); + + Applet::Initialize(); + + const auto user_config_storage = broker.PopNormalDataToApplet(); + ASSERT(user_config_storage != nullptr); + const auto& user_config = user_config_storage->GetData(); + + ASSERT(user_config.size() >= sizeof(UserSelectionConfig)); + std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig)); +} + +bool ProfileSelect::TransactionComplete() const { + return complete; +} + +ResultCode ProfileSelect::GetStatus() const { + return status; +} + +void ProfileSelect::ExecuteInteractive() { + UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); +} + +void ProfileSelect::Execute() { + if (complete) { + broker.PushNormalDataFromApplet(IStorage{final_data}); + return; + } + + const auto& frontend{Core::System::GetInstance().GetProfileSelector()}; + + frontend.SelectProfile([this](std::optional<Account::UUID> uuid) { SelectionComplete(uuid); }); +} + +void ProfileSelect::SelectionComplete(std::optional<Account::UUID> uuid) { + UserSelectionOutput output{}; + + if (uuid.has_value() && uuid->uuid != Account::INVALID_UUID) { + output.result = 0; + output.uuid_selected = uuid->uuid; + } else { + status = ERR_USER_CANCELLED_SELECTION; + output.result = ERR_USER_CANCELLED_SELECTION.raw; + output.uuid_selected = Account::INVALID_UUID; + } + + final_data = std::vector<u8>(sizeof(UserSelectionOutput)); + std::memcpy(final_data.data(), &output, final_data.size()); + broker.PushNormalDataFromApplet(IStorage{final_data}); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h new file mode 100644 index 000000000..787485f22 --- /dev/null +++ b/src/core/hle/service/am/applets/profile_select.h @@ -0,0 +1,50 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <vector> + +#include "common/common_funcs.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +struct UserSelectionConfig { + // TODO(DarkLordZach): RE this structure + // It seems to be flags and the like that determine the UI of the applet on the switch... from + // my research this is safe to ignore for now. + INSERT_PADDING_BYTES(0xA0); +}; +static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size."); + +struct UserSelectionOutput { + u64 result; + u128 uuid_selected; +}; +static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size."); + +class ProfileSelect final : public Applet { +public: + ProfileSelect(); + ~ProfileSelect() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + void SelectionComplete(std::optional<Account::UUID> uuid); + +private: + UserSelectionConfig config; + bool complete = false; + ResultCode status = RESULT_SUCCESS; + std::vector<u8> final_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 981bdec51..f255f74b5 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -146,11 +146,10 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { if (complete) { broker.PushNormalDataFromApplet(IStorage{output_main}); + broker.SignalStateChanged(); } else { broker.PushInteractiveDataFromApplet(IStorage{output_sub}); } - - broker.SignalStateChanged(); } else { output_main[0] = 1; complete = true; diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp new file mode 100644 index 000000000..9b0aa7f5f --- /dev/null +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -0,0 +1,190 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <array> +#include <cstring> +#include <vector> + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_paths.h" +#include "common/file_util.h" +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/mode.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/vfs_types.h" +#include "core/frontend/applets/web_browser.h" +#include "core/hle/kernel/process.h" +#include "core/hle/service/am/applets/web_browser.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/loader/loader.h" + +namespace Service::AM::Applets { + +// TODO(DarkLordZach): There are other arguments in the WebBuffer structure that are currently not +// parsed, for example footer mode and left stick mode. Some of these are not particularly relevant, +// but some may be worth an implementation. +constexpr u16 WEB_ARGUMENT_URL_TYPE = 0x6; + +struct WebBufferHeader { + u16 count; + INSERT_PADDING_BYTES(6); +}; +static_assert(sizeof(WebBufferHeader) == 0x8, "WebBufferHeader has incorrect size."); + +struct WebArgumentHeader { + u16 type; + u16 size; + u32 offset; +}; +static_assert(sizeof(WebArgumentHeader) == 0x8, "WebArgumentHeader has incorrect size."); + +struct WebArgumentResult { + u32 result_code; + std::array<char, 0x1000> last_url; + u64 last_url_size; +}; +static_assert(sizeof(WebArgumentResult) == 0x1010, "WebArgumentResult has incorrect size."); + +static std::vector<u8> GetArgumentDataForTagType(const std::vector<u8>& data, u16 type) { + WebBufferHeader header; + ASSERT(sizeof(WebBufferHeader) <= data.size()); + std::memcpy(&header, data.data(), sizeof(WebBufferHeader)); + + u64 offset = sizeof(WebBufferHeader); + for (u16 i = 0; i < header.count; ++i) { + WebArgumentHeader arg; + ASSERT(offset + sizeof(WebArgumentHeader) <= data.size()); + std::memcpy(&arg, data.data() + offset, sizeof(WebArgumentHeader)); + offset += sizeof(WebArgumentHeader); + + if (arg.type == type) { + std::vector<u8> out(arg.size); + offset += arg.offset; + ASSERT(offset + arg.size <= data.size()); + std::memcpy(out.data(), data.data() + offset, out.size()); + return out; + } + + offset += arg.offset + arg.size; + } + + return {}; +} + +static FileSys::VirtualFile GetManualRomFS() { + auto& loader{Core::System::GetInstance().GetAppLoader()}; + + FileSys::VirtualFile out; + if (loader.ReadManualRomFS(out) == Loader::ResultStatus::Success) + return out; + + const auto& installed{FileSystem::GetUnionContents()}; + const auto res = installed.GetEntry(Core::System::GetInstance().CurrentProcess()->GetTitleID(), + FileSys::ContentRecordType::Manual); + + if (res != nullptr) + return res->GetRomFS(); + return nullptr; +} + +WebBrowser::WebBrowser() = default; + +WebBrowser::~WebBrowser() = default; + +void WebBrowser::Initialize() { + Applet::Initialize(); + + complete = false; + temporary_dir.clear(); + filename.clear(); + status = RESULT_SUCCESS; + + const auto web_arg_storage = broker.PopNormalDataToApplet(); + ASSERT(web_arg_storage != nullptr); + const auto& web_arg = web_arg_storage->GetData(); + + const auto url_data = GetArgumentDataForTagType(web_arg, WEB_ARGUMENT_URL_TYPE); + filename = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast<const char*>(url_data.data()), url_data.size()); + + temporary_dir = FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + + "web_applet_manual", + FileUtil::DirectorySeparator::PlatformDefault); + FileUtil::DeleteDirRecursively(temporary_dir); + + manual_romfs = GetManualRomFS(); + if (manual_romfs == nullptr) { + status = ResultCode(-1); + LOG_ERROR(Service_AM, "Failed to find manual for current process!"); + } + + filename = + FileUtil::SanitizePath(temporary_dir + DIR_SEP + "html-document" + DIR_SEP + filename, + FileUtil::DirectorySeparator::PlatformDefault); +} + +bool WebBrowser::TransactionComplete() const { + return complete; +} + +ResultCode WebBrowser::GetStatus() const { + return status; +} + +void WebBrowser::ExecuteInteractive() { + UNIMPLEMENTED_MSG("Unexpected interactive data recieved!"); +} + +void WebBrowser::Execute() { + if (complete) + return; + + if (status != RESULT_SUCCESS) { + complete = true; + return; + } + + auto& frontend{Core::System::GetInstance().GetWebBrowser()}; + + frontend.OpenPage(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); +} + +void WebBrowser::UnpackRomFS() { + if (unpacked) + return; + + ASSERT(manual_romfs != nullptr); + const auto dir = + FileSys::ExtractRomFS(manual_romfs, FileSys::RomFSExtractionType::SingleDiscard); + const auto& vfs{Core::System::GetInstance().GetFilesystem()}; + const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite); + FileSys::VfsRawCopyD(dir, temp_dir); + + unpacked = true; +} + +void WebBrowser::Finalize() { + complete = true; + + WebArgumentResult out{}; + out.result_code = 0; + out.last_url_size = 0; + + std::vector<u8> data(sizeof(WebArgumentResult)); + std::memcpy(data.data(), &out, sizeof(WebArgumentResult)); + + broker.PushNormalDataFromApplet(IStorage{data}); + broker.SignalStateChanged(); + + FileUtil::DeleteDirRecursively(temporary_dir); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h new file mode 100644 index 000000000..b9e228fac --- /dev/null +++ b/src/core/hle/service/am/applets/web_browser.h @@ -0,0 +1,44 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/vfs_types.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applets.h" + +namespace Service::AM::Applets { + +class WebBrowser final : public Applet { +public: + WebBrowser(); + ~WebBrowser() override; + + void Initialize() override; + + bool TransactionComplete() const override; + ResultCode GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + + // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary + // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in + // size. Attempting to access files at filename before invocation is likely to not work. + void UnpackRomFS(); + + // Callback to be fired when the frontend is finished browsing. This will delete the temporary + // manual RomFS extracted files, so ensure this is only called at actual finalization. + void Finalize(); + +private: + bool complete = false; + bool unpacked = false; + ResultCode status = RESULT_SUCCESS; + + FileSys::VirtualFile manual_romfs; + std::string temporary_dir; + std::string filename; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 0417fdb92..b506bc3dd 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -20,6 +20,7 @@ #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#include "core/settings.h" namespace Service::AOC { @@ -76,6 +77,13 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); + + const auto& disabled = Settings::values.disabled_addons[current]; + if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) { + rb.Push<u32>(0); + return; + } + rb.Push<u32>(static_cast<u32>( std::count_if(add_on_content.begin(), add_on_content.end(), [current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); }))); @@ -96,6 +104,10 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { out.push_back(static_cast<u32>(add_on_content[i] & 0x7FF)); } + const auto& disabled = Settings::values.disabled_addons[current]; + if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) + out = {}; + if (out.size() < offset) { IPC::ResponseBuilder rb{ctx, 2}; // TODO(DarkLordZach): Find the correct error code. diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 2f15ac2a6..770590d0b 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -111,7 +111,8 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { } static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) { - LOG_ERROR(Service_Fatal, "Threw fatal error type {}", static_cast<u32>(fatal_type)); + LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", + static_cast<u32>(fatal_type), error_code.raw); switch (fatal_type) { case FatalType::ErrorReportAndScreen: GenerateErrorReport(error_code, info); diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index b1490e6fa..c6da2df43 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -8,18 +8,23 @@ #include "common/file_util.h" #include "core/core.h" #include "core/file_sys/bis_factory.h" +#include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" #include "core/file_sys/mode.h" +#include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_offset.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/filesystem/fsp_ldr.h" #include "core/hle/service/filesystem/fsp_pr.h" #include "core/hle/service/filesystem/fsp_srv.h" +#include "core/loader/loader.h" namespace Service::FileSystem { @@ -28,6 +33,10 @@ namespace Service::FileSystem { // TODO(DarkLordZach): Eventually make this configurable in settings. constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000; +// A default size for normal/journal save data size if application control metadata cannot be found. +// This should be large enough to satisfy even the most extreme requirements (~4.2GB) +constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; + static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, std::string_view dir_name_) { std::string dir_name(FileUtil::SanitizePath(dir_name_)); @@ -341,6 +350,44 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() { return sdmc_factory->Open(); } +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) { + if (save_data_factory == nullptr) { + return {0, 0}; + } + + const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); + + if (value.normal == 0 && value.journal == 0) { + FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; + + FileSys::NACP nacp; + const auto res = Core::System::GetInstance().GetAppLoader().ReadControlData(nacp); + + if (res != Loader::ResultStatus::Success) { + FileSys::PatchManager pm{Core::CurrentProcess()->GetTitleID()}; + auto [nacp_unique, discard] = pm.GetControlMetadata(); + + if (nacp_unique != nullptr) { + new_size = {nacp_unique->GetDefaultNormalSaveSize(), + nacp_unique->GetDefaultJournalSaveSize()}; + } + } else { + new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; + } + + WriteSaveDataSize(type, title_id, user_id, new_size); + return new_size; + } + + return value; +} + +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value) { + if (save_data_factory != nullptr) + save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); +} + FileSys::RegisteredCacheUnion GetUnionContents() { return FileSys::RegisteredCacheUnion{ {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}}; diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 965414be0..6fd5e7b23 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -21,9 +21,11 @@ class SDMCFactory; enum class ContentRecordType : u8; enum class Mode : u32; enum class SaveDataSpaceId : u8; +enum class SaveDataType : u8; enum class StorageId : u8; struct SaveDataDescriptor; +struct SaveDataSize; } // namespace FileSys namespace Service { @@ -48,6 +50,10 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); ResultVal<FileSys::VirtualDir> OpenSDMC(); +FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); +void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value); + FileSys::RegisteredCacheUnion GetUnionContents(); FileSys::RegisteredCache* GetSystemNANDContents(); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index d2ffd5776..74c4e583b 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -45,8 +45,12 @@ public: explicit IStorage(FileSys::VirtualFile backend_) : ServiceFramework("IStorage"), backend(std::move(backend_)) { static const FunctionInfo functions[] = { - {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, - {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, {5, nullptr, "OperateRange"}, + {0, &IStorage::Read, "Read"}, + {1, nullptr, "Write"}, + {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, + {4, &IStorage::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, }; RegisterHandlers(functions); } @@ -83,6 +87,15 @@ private: IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + + void GetSize(Kernel::HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(size); + } }; class IFile final : public ServiceFramework<IFile> { @@ -796,9 +809,18 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); + enum class LogMode : u32 { + Off, + Log, + RedirectToSdCard, + LogToSdCard = Log | RedirectToSdCard, + }; + + // Given we always want to receive logging information, + // we always specify logging as enabled. IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(5); + rb.PushEnum(LogMode::Log); } void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index d6829d0b8..04c8c35a8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -339,52 +339,6 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index]; auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; - if (hold_type == NpadHoldType::Horizontal) { - ControllerPadState state{}; - AnalogPosition temp_lstick_entry{}; - AnalogPosition temp_rstick_entry{}; - if (controller_type == NPadControllerType::JoyLeft) { - state.d_down.Assign(pad_state.pad_states.d_left.Value()); - state.d_left.Assign(pad_state.pad_states.d_up.Value()); - state.d_right.Assign(pad_state.pad_states.d_down.Value()); - state.d_up.Assign(pad_state.pad_states.d_right.Value()); - state.l.Assign(pad_state.pad_states.l.Value() | - pad_state.pad_states.left_sl.Value()); - state.r.Assign(pad_state.pad_states.r.Value() | - pad_state.pad_states.left_sr.Value()); - - state.zl.Assign(pad_state.pad_states.zl.Value()); - state.plus.Assign(pad_state.pad_states.minus.Value()); - - temp_lstick_entry = pad_state.l_stick; - temp_rstick_entry = pad_state.r_stick; - std::swap(temp_lstick_entry.x, temp_lstick_entry.y); - std::swap(temp_rstick_entry.x, temp_rstick_entry.y); - temp_lstick_entry.y *= -1; - } else if (controller_type == NPadControllerType::JoyRight) { - state.x.Assign(pad_state.pad_states.a.Value()); - state.a.Assign(pad_state.pad_states.b.Value()); - state.b.Assign(pad_state.pad_states.y.Value()); - state.y.Assign(pad_state.pad_states.b.Value()); - - state.l.Assign(pad_state.pad_states.l.Value() | - pad_state.pad_states.right_sl.Value()); - state.r.Assign(pad_state.pad_states.r.Value() | - pad_state.pad_states.right_sr.Value()); - state.zr.Assign(pad_state.pad_states.zr.Value()); - state.plus.Assign(pad_state.pad_states.plus.Value()); - - temp_lstick_entry = pad_state.l_stick; - temp_rstick_entry = pad_state.r_stick; - std::swap(temp_lstick_entry.x, temp_lstick_entry.y); - std::swap(temp_rstick_entry.x, temp_rstick_entry.y); - temp_rstick_entry.x *= -1; - } - pad_state.pad_states.raw = state.raw; - pad_state.l_stick = temp_lstick_entry; - pad_state.r_stick = temp_rstick_entry; - } - libnx_entry.connection_status.raw = 0; switch (controller_type) { @@ -456,6 +410,8 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; libnx_entry.pad.l_stick = pad_state.l_stick; libnx_entry.pad.r_stick = pad_state.r_stick; + + press_state |= static_cast<u32>(pad_state.pad_states.raw); } std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), shared_memory_entries.size() * sizeof(NPadEntry)); @@ -682,6 +638,10 @@ void Controller_NPad::ClearAllControllers() { }); } +u32 Controller_NPad::GetAndResetPressState() { + return std::exchange(press_state, 0); +} + bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 29851f16a..106cf58c8 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -124,6 +124,10 @@ public: void ConnectAllDisconnectedControllers(); void ClearAllControllers(); + // Logical OR for all buttons presses on all controllers + // Specifically for cheat engine and other features. + u32 GetAndResetPressState(); + static std::size_t NPadIdToIndex(u32 npad_id); static u32 IndexToNPad(std::size_t index); @@ -292,6 +296,8 @@ private: bool is_connected; }; + u32 press_state{}; + NPadType style{}; std::array<NPadEntry, 10> shared_memory_entries{}; std::array< diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2ec38c726..008bf3f02 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -40,119 +40,82 @@ constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66; constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; -enum class HidController : std::size_t { - DebugPad, - Touchscreen, - Mouse, - Keyboard, - XPad, - Unknown1, - Unknown2, - Unknown3, - SixAxisSensor, - NPad, - Gesture, - - MaxControllers, -}; - -class IAppletResource final : public ServiceFramework<IAppletResource> { -public: - IAppletResource() : ServiceFramework("IAppletResource") { - static const FunctionInfo functions[] = { - {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, - }; - RegisterHandlers(functions); - - auto& kernel = Core::System::GetInstance().Kernel(); - shared_mem = Kernel::SharedMemory::Create( - kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, - Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); - - MakeController<Controller_DebugPad>(HidController::DebugPad); - MakeController<Controller_Touchscreen>(HidController::Touchscreen); - MakeController<Controller_Mouse>(HidController::Mouse); - MakeController<Controller_Keyboard>(HidController::Keyboard); - MakeController<Controller_XPad>(HidController::XPad); - MakeController<Controller_Stubbed>(HidController::Unknown1); - MakeController<Controller_Stubbed>(HidController::Unknown2); - MakeController<Controller_Stubbed>(HidController::Unknown3); - MakeController<Controller_Stubbed>(HidController::SixAxisSensor); - MakeController<Controller_NPad>(HidController::NPad); - MakeController<Controller_Gesture>(HidController::Gesture); - - // Homebrew doesn't try to activate some controllers, so we activate them by default - GetController<Controller_NPad>(HidController::NPad).ActivateController(); - GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); - - GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); - GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); - GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); - - // Register update callbacks - pad_update_event = CoreTiming::RegisterEvent( - "HID::UpdatePadCallback", - [this](u64 userdata, int cycles_late) { UpdateControllers(userdata, cycles_late); }); - - // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) - - CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); - - ReloadInputDevices(); - } - - void ActivateController(HidController controller) { - controllers[static_cast<size_t>(controller)]->ActivateController(); - } - void DeactivateController(HidController controller) { - controllers[static_cast<size_t>(controller)]->DeactivateController(); - } +IAppletResource::IAppletResource() : ServiceFramework("IAppletResource") { + static const FunctionInfo functions[] = { + {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, + }; + RegisterHandlers(functions); + + auto& kernel = Core::System::GetInstance().Kernel(); + shared_mem = Kernel::SharedMemory::Create( + kernel, nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, + Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory"); + + MakeController<Controller_DebugPad>(HidController::DebugPad); + MakeController<Controller_Touchscreen>(HidController::Touchscreen); + MakeController<Controller_Mouse>(HidController::Mouse); + MakeController<Controller_Keyboard>(HidController::Keyboard); + MakeController<Controller_XPad>(HidController::XPad); + MakeController<Controller_Stubbed>(HidController::Unknown1); + MakeController<Controller_Stubbed>(HidController::Unknown2); + MakeController<Controller_Stubbed>(HidController::Unknown3); + MakeController<Controller_Stubbed>(HidController::SixAxisSensor); + MakeController<Controller_NPad>(HidController::NPad); + MakeController<Controller_Gesture>(HidController::Gesture); + + // Homebrew doesn't try to activate some controllers, so we activate them by default + GetController<Controller_NPad>(HidController::NPad).ActivateController(); + GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController(); + + GetController<Controller_Stubbed>(HidController::Unknown1).SetCommonHeaderOffset(0x4c00); + GetController<Controller_Stubbed>(HidController::Unknown2).SetCommonHeaderOffset(0x4e00); + GetController<Controller_Stubbed>(HidController::Unknown3).SetCommonHeaderOffset(0x5000); + + // Register update callbacks + pad_update_event = + CoreTiming::RegisterEvent("HID::UpdatePadCallback", [this](u64 userdata, int cycles_late) { + UpdateControllers(userdata, cycles_late); + }); + + // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) + + CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); + + ReloadInputDevices(); +} - template <typename T> - void MakeController(HidController controller) { - controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); - } +void IAppletResource::ActivateController(HidController controller) { + controllers[static_cast<size_t>(controller)]->ActivateController(); +} - template <typename T> - T& GetController(HidController controller) { - return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); - } +void IAppletResource::DeactivateController(HidController controller) { + controllers[static_cast<size_t>(controller)]->DeactivateController(); +} - ~IAppletResource() { - CoreTiming::UnscheduleEvent(pad_update_event, 0); - } +IAppletResource ::~IAppletResource() { + CoreTiming::UnscheduleEvent(pad_update_event, 0); +} -private: - void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(shared_mem); - } + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(shared_mem); +} - void UpdateControllers(u64 userdata, int cycles_late) { - const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); - for (const auto& controller : controllers) { - if (should_reload) { - controller->OnLoadInputDevices(); - } - controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); +void IAppletResource::UpdateControllers(u64 userdata, int cycles_late) { + const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); + for (const auto& controller : controllers) { + if (should_reload) { + controller->OnLoadInputDevices(); } - - CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); + controller->OnUpdate(shared_mem->GetPointer(), SHARED_MEMORY_SIZE); } - // Handle to shared memory region designated to HID service - Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; - - // CoreTiming update events - CoreTiming::EventType* pad_update_event; - - std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> - controllers{}; -}; + CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); +} class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { public: @@ -172,480 +135,597 @@ private: } }; -class Hid final : public ServiceFramework<Hid> { -public: - Hid() : ServiceFramework("hid") { - // clang-format off - static const FunctionInfo functions[] = { - {0, &Hid::CreateAppletResource, "CreateAppletResource"}, - {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, - {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, - {21, &Hid::ActivateMouse, "ActivateMouse"}, - {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, - {32, nullptr, "SendKeyboardLockKeyEvent"}, - {40, nullptr, "AcquireXpadIdEventHandle"}, - {41, nullptr, "ReleaseXpadIdEventHandle"}, - {51, &Hid::ActivateXpad, "ActivateXpad"}, - {55, nullptr, "GetXpadIds"}, - {56, nullptr, "ActivateJoyXpad"}, - {58, nullptr, "GetJoyXpadLifoHandle"}, - {59, nullptr, "GetJoyXpadIds"}, - {60, nullptr, "ActivateSixAxisSensor"}, - {61, nullptr, "DeactivateSixAxisSensor"}, - {62, nullptr, "GetSixAxisSensorLifoHandle"}, - {63, nullptr, "ActivateJoySixAxisSensor"}, - {64, nullptr, "DeactivateJoySixAxisSensor"}, - {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, - {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, - {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, - {68, nullptr, "IsSixAxisSensorFusionEnabled"}, - {69, nullptr, "EnableSixAxisSensorFusion"}, - {70, nullptr, "SetSixAxisSensorFusionParameters"}, - {71, nullptr, "GetSixAxisSensorFusionParameters"}, - {72, nullptr, "ResetSixAxisSensorFusionParameters"}, - {73, nullptr, "SetAccelerometerParameters"}, - {74, nullptr, "GetAccelerometerParameters"}, - {75, nullptr, "ResetAccelerometerParameters"}, - {76, nullptr, "SetAccelerometerPlayMode"}, - {77, nullptr, "GetAccelerometerPlayMode"}, - {78, nullptr, "ResetAccelerometerPlayMode"}, - {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, - {80, nullptr, "GetGyroscopeZeroDriftMode"}, - {81, nullptr, "ResetGyroscopeZeroDriftMode"}, - {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, - {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"}, - {91, &Hid::ActivateGesture, "ActivateGesture"}, - {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, - {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, - {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, - {103, &Hid::ActivateNpad, "ActivateNpad"}, - {104, nullptr, "DeactivateNpad"}, - {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, - {107, &Hid::DisconnectNpad, "DisconnectNpad"}, - {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, - {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, - {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, - {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, - {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, - {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, - {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, - {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, - {126, nullptr, "StartLrAssignmentMode"}, - {127, nullptr, "StopLrAssignmentMode"}, - {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, - {129, nullptr, "GetNpadHandheldActivationMode"}, - {130, nullptr, "SwapNpadAssignment"}, - {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, - {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, - {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, - {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, - {201, &Hid::SendVibrationValue, "SendVibrationValue"}, - {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, - {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, - {204, nullptr, "PermitVibration"}, - {205, nullptr, "IsVibrationPermitted"}, - {206, &Hid::SendVibrationValues, "SendVibrationValues"}, - {207, nullptr, "SendVibrationGcErmCommand"}, - {208, nullptr, "GetActualVibrationGcErmCommand"}, - {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, - {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, - {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, - {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, - {302, nullptr, "StopConsoleSixAxisSensor"}, - {303, nullptr, "ActivateSevenSixAxisSensor"}, - {304, nullptr, "StartSevenSixAxisSensor"}, - {305, nullptr, "StopSevenSixAxisSensor"}, - {306, nullptr, "InitializeSevenSixAxisSensor"}, - {307, nullptr, "FinalizeSevenSixAxisSensor"}, - {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, - {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, - {310, nullptr, "ResetSevenSixAxisSensorTimestamp"}, - {400, nullptr, "IsUsbFullKeyControllerEnabled"}, - {401, nullptr, "EnableUsbFullKeyController"}, - {402, nullptr, "IsUsbFullKeyControllerConnected"}, - {403, nullptr, "HasBattery"}, - {404, nullptr, "HasLeftRightBattery"}, - {405, nullptr, "GetNpadInterfaceType"}, - {406, nullptr, "GetNpadLeftRightInterfaceType"}, - {500, nullptr, "GetPalmaConnectionHandle"}, - {501, nullptr, "InitializePalma"}, - {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, - {503, nullptr, "GetPalmaOperationInfo"}, - {504, nullptr, "PlayPalmaActivity"}, - {505, nullptr, "SetPalmaFrModeType"}, - {506, nullptr, "ReadPalmaStep"}, - {507, nullptr, "EnablePalmaStep"}, - {508, nullptr, "ResetPalmaStep"}, - {509, nullptr, "ReadPalmaApplicationSection"}, - {510, nullptr, "WritePalmaApplicationSection"}, - {511, nullptr, "ReadPalmaUniqueCode"}, - {512, nullptr, "SetPalmaUniqueCodeInvalid"}, - {513, nullptr, "WritePalmaActivityEntry"}, - {514, nullptr, "WritePalmaRgbLedPatternEntry"}, - {515, nullptr, "WritePalmaWaveEntry"}, - {516, nullptr, "SetPalmaDataBaseIdentificationVersion"}, - {517, nullptr, "GetPalmaDataBaseIdentificationVersion"}, - {518, nullptr, "SuspendPalmaFeature"}, - {519, nullptr, "GetPalmaOperationResult"}, - {520, nullptr, "ReadPalmaPlayLog"}, - {521, nullptr, "ResetPalmaPlayLog"}, - {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"}, - {523, nullptr, "SetIsPalmaPairedConnectable"}, - {524, nullptr, "PairPalma"}, - {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, - {1000, nullptr, "SetNpadCommunicationMode"}, - {1001, nullptr, "GetNpadCommunicationMode"}, - }; - // clang-format on - - RegisterHandlers(functions); +std::shared_ptr<IAppletResource> Hid::GetAppletResource() { + if (applet_resource == nullptr) { + applet_resource = std::make_shared<IAppletResource>(); } - ~Hid() = default; -private: - std::shared_ptr<IAppletResource> applet_resource; + return applet_resource; +} - void CreateAppletResource(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +Hid::Hid() : ServiceFramework("hid") { + // clang-format off + static const FunctionInfo functions[] = { + {0, &Hid::CreateAppletResource, "CreateAppletResource"}, + {1, &Hid::ActivateDebugPad, "ActivateDebugPad"}, + {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, + {21, &Hid::ActivateMouse, "ActivateMouse"}, + {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, + {32, nullptr, "SendKeyboardLockKeyEvent"}, + {40, nullptr, "AcquireXpadIdEventHandle"}, + {41, nullptr, "ReleaseXpadIdEventHandle"}, + {51, &Hid::ActivateXpad, "ActivateXpad"}, + {55, nullptr, "GetXpadIds"}, + {56, nullptr, "ActivateJoyXpad"}, + {58, nullptr, "GetJoyXpadLifoHandle"}, + {59, nullptr, "GetJoyXpadIds"}, + {60, nullptr, "ActivateSixAxisSensor"}, + {61, nullptr, "DeactivateSixAxisSensor"}, + {62, nullptr, "GetSixAxisSensorLifoHandle"}, + {63, nullptr, "ActivateJoySixAxisSensor"}, + {64, nullptr, "DeactivateJoySixAxisSensor"}, + {65, nullptr, "GetJoySixAxisSensorLifoHandle"}, + {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, + {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, + {68, nullptr, "IsSixAxisSensorFusionEnabled"}, + {69, nullptr, "EnableSixAxisSensorFusion"}, + {70, nullptr, "SetSixAxisSensorFusionParameters"}, + {71, nullptr, "GetSixAxisSensorFusionParameters"}, + {72, nullptr, "ResetSixAxisSensorFusionParameters"}, + {73, nullptr, "SetAccelerometerParameters"}, + {74, nullptr, "GetAccelerometerParameters"}, + {75, nullptr, "ResetAccelerometerParameters"}, + {76, nullptr, "SetAccelerometerPlayMode"}, + {77, nullptr, "GetAccelerometerPlayMode"}, + {78, nullptr, "ResetAccelerometerPlayMode"}, + {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, + {80, nullptr, "GetGyroscopeZeroDriftMode"}, + {81, nullptr, "ResetGyroscopeZeroDriftMode"}, + {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, + {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"}, + {91, &Hid::ActivateGesture, "ActivateGesture"}, + {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"}, + {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"}, + {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"}, + {103, &Hid::ActivateNpad, "ActivateNpad"}, + {104, nullptr, "DeactivateNpad"}, + {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, + {107, &Hid::DisconnectNpad, "DisconnectNpad"}, + {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"}, + {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, + {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, + {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, + {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"}, + {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"}, + {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"}, + {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, + {126, nullptr, "StartLrAssignmentMode"}, + {127, nullptr, "StopLrAssignmentMode"}, + {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, + {129, nullptr, "GetNpadHandheldActivationMode"}, + {130, nullptr, "SwapNpadAssignment"}, + {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, + {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, + {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, + {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, + {201, &Hid::SendVibrationValue, "SendVibrationValue"}, + {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, + {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"}, + {204, nullptr, "PermitVibration"}, + {205, nullptr, "IsVibrationPermitted"}, + {206, &Hid::SendVibrationValues, "SendVibrationValues"}, + {207, nullptr, "SendVibrationGcErmCommand"}, + {208, nullptr, "GetActualVibrationGcErmCommand"}, + {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, + {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, + {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, + {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, + {302, nullptr, "StopConsoleSixAxisSensor"}, + {303, nullptr, "ActivateSevenSixAxisSensor"}, + {304, nullptr, "StartSevenSixAxisSensor"}, + {305, nullptr, "StopSevenSixAxisSensor"}, + {306, nullptr, "InitializeSevenSixAxisSensor"}, + {307, nullptr, "FinalizeSevenSixAxisSensor"}, + {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, + {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, + {310, nullptr, "ResetSevenSixAxisSensorTimestamp"}, + {400, nullptr, "IsUsbFullKeyControllerEnabled"}, + {401, nullptr, "EnableUsbFullKeyController"}, + {402, nullptr, "IsUsbFullKeyControllerConnected"}, + {403, nullptr, "HasBattery"}, + {404, nullptr, "HasLeftRightBattery"}, + {405, nullptr, "GetNpadInterfaceType"}, + {406, nullptr, "GetNpadLeftRightInterfaceType"}, + {500, nullptr, "GetPalmaConnectionHandle"}, + {501, nullptr, "InitializePalma"}, + {502, nullptr, "AcquirePalmaOperationCompleteEvent"}, + {503, nullptr, "GetPalmaOperationInfo"}, + {504, nullptr, "PlayPalmaActivity"}, + {505, nullptr, "SetPalmaFrModeType"}, + {506, nullptr, "ReadPalmaStep"}, + {507, nullptr, "EnablePalmaStep"}, + {508, nullptr, "ResetPalmaStep"}, + {509, nullptr, "ReadPalmaApplicationSection"}, + {510, nullptr, "WritePalmaApplicationSection"}, + {511, nullptr, "ReadPalmaUniqueCode"}, + {512, nullptr, "SetPalmaUniqueCodeInvalid"}, + {513, nullptr, "WritePalmaActivityEntry"}, + {514, nullptr, "WritePalmaRgbLedPatternEntry"}, + {515, nullptr, "WritePalmaWaveEntry"}, + {516, nullptr, "SetPalmaDataBaseIdentificationVersion"}, + {517, nullptr, "GetPalmaDataBaseIdentificationVersion"}, + {518, nullptr, "SuspendPalmaFeature"}, + {519, nullptr, "GetPalmaOperationResult"}, + {520, nullptr, "ReadPalmaPlayLog"}, + {521, nullptr, "ResetPalmaPlayLog"}, + {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"}, + {523, nullptr, "SetIsPalmaPairedConnectable"}, + {524, nullptr, "PairPalma"}, + {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"}, + {1000, nullptr, "SetNpadCommunicationMode"}, + {1001, nullptr, "GetNpadCommunicationMode"}, + }; + // clang-format on + + RegisterHandlers(functions); +} - if (applet_resource == nullptr) { - applet_resource = std::make_shared<IAppletResource>(); - } +Hid::~Hid() = default; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IAppletResource>(applet_resource); - } +void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void ActivateXpad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - applet_resource->ActivateController(HidController::XPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + if (applet_resource == nullptr) { + applet_resource = std::make_shared<IAppletResource>(); } - void ActivateDebugPad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IAppletResource>(applet_resource); +} - applet_resource->ActivateController(HidController::DebugPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto basic_xpad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, + applet_resource_user_id); - applet_resource->ActivateController(HidController::Touchscreen); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->ActivateController(HidController::XPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void ActivateMouse(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::Mouse); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void ActivateKeyboard(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + applet_resource->ActivateController(HidController::DebugPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - applet_resource->ActivateController(HidController::Keyboard); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void ActivateGesture(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - applet_resource->ActivateController(HidController::Gesture); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->ActivateController(HidController::Touchscreen); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { - // Should have no effect with how our npad sets up the data - LOG_DEBUG(Service_HID, "called"); +void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - applet_resource->ActivateController(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto handle = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle); + applet_resource->ActivateController(HidController::Mouse); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->ActivateController(HidController::Keyboard); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); +void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. - rb.Push(true); - } + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); - void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto supported_styleset = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset); + applet_resource->ActivateController(HidController::Gesture); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedStyleSet({supported_styleset}); +void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { + // Should have no effect with how our npad sets up the data + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, + applet_resource_user_id); - void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + applet_resource->ActivateController(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(controller.GetSupportedStyleSet().raw); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); - void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto drift_mode{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void ActivateNpad(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_WARNING(Service_HID, + "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, + drift_mode, applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - applet_resource->ActivateController(HidController::NPad); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); +void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetStyleSetChangedEvent()); - } + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); - void DisconnectNpad(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. + rb.Push(true); +} - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .DisconnectNPad(npad_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto supported_styleset{rp.Pop<u32>()}; - void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetLedPattern(npad_id) - .raw); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSupportedStyleSet({supported_styleset}); - void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto hold_type = rp.PopRaw<u64>(); - LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); +void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - const auto& controller = - applet_resource->GetController<Controller_NPad>(HidController::NPad); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); - } + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(controller.GetSupportedStyleSet().raw); +} - void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto npad_id = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id); +void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetVibrationEnabled(true); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .SetVibrationEnabled(false); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + applet_resource->ActivateController(HidController::NPad); +} - void SendVibrationValue(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto controller_id = rp.PopRaw<u32>(); - const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); - LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id); +void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, + applet_resource_user_id, unknown); - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .VibrateController({controller_id}, {vibration_values}); - } + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .GetStyleSetChangedEvent()); +} - void SendVibrationValues(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto controllers = ctx.ReadBuffer(0); - const auto vibrations = ctx.ReadBuffer(1); + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); - std::vector<u32> controller_list(controllers.size() / sizeof(u32)); - std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / - sizeof(Controller_NPad::Vibration)); + applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - std::memcpy(controller_list.data(), controllers.data(), controllers.size()); - std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); - std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), - [](u32 controller_id) { return controller_id - 3; }); +void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .VibrateController(controller_list, vibration_list); + LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) + .GetLedPattern(npad_id) + .raw); +} - void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); +void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto hold_type{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(RESULT_SUCCESS); - rb.PushRaw<Controller_NPad::Vibration>( - applet_resource->GetController<Controller_NPad>(HidController::NPad) - .GetLastVibration()); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", + applet_resource_user_id, hold_type); - void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto npad_id = rp.PopRaw<u32>(); - LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); - auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } +void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); +} - void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto mode = rp.PopRaw<u32>(); - LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode); +void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); - void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(1); - rb.Push<u32>(0); - } +void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(RESULT_SUCCESS); - rb.PushIpcInterface<IActiveVibrationDeviceList>(); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); +void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} - void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); +void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto controller_id{rp.Pop<u32>()}; + const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, + applet_resource_user_id); - void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .VibrateController({controller_id}, {vibration_values}); +} - void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); +void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + const auto controllers = ctx.ReadBuffer(0); + const auto vibrations = ctx.ReadBuffer(1); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } -}; + std::vector<u32> controller_list(controllers.size() / sizeof(u32)); + std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / + sizeof(Controller_NPad::Vibration)); + + std::memcpy(controller_list.data(), controllers.data(), controllers.size()); + std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); + std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(), + [](u32 controller_id) { return controller_id - 3; }); + + applet_resource->GetController<Controller_NPad>(HidController::NPad) + .VibrateController(controller_list, vibration_list); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto controller_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(RESULT_SUCCESS); + rb.PushRaw<Controller_NPad::Vibration>( + applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration()); +} + +void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto npad_id{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, + applet_resource_user_id); + + auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); + controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown_1{rp.Pop<u32>()}; + const auto unknown_2{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", + unknown_1, unknown_2, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto mode{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, mode={}", + applet_resource_user_id, mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(1); + rb.Push<u32>(0); +} + +void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_HID, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<IActiveVibrationDeviceList>(); +} + +void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto unknown{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", + applet_resource_user_id, unknown); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto unknown{rp.Pop<u32>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} class HidDbg final : public ServiceFramework<HidDbg> { public: diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 773035460..eca27c056 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -4,12 +4,122 @@ #pragma once +#include "controllers/controller_base.h" +#include "core/hle/service/service.h" + +namespace CoreTiming { +struct EventType; +} + +namespace Kernel { +class SharedMemory; +} + namespace SM { class ServiceManager; } namespace Service::HID { +enum class HidController : std::size_t { + DebugPad, + Touchscreen, + Mouse, + Keyboard, + XPad, + Unknown1, + Unknown2, + Unknown3, + SixAxisSensor, + NPad, + Gesture, + + MaxControllers, +}; + +class IAppletResource final : public ServiceFramework<IAppletResource> { +public: + IAppletResource(); + ~IAppletResource() override; + + void ActivateController(HidController controller); + void DeactivateController(HidController controller); + + template <typename T> + T& GetController(HidController controller) { + return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); + } + + template <typename T> + const T& GetController(HidController controller) const { + return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); + } + +private: + template <typename T> + void MakeController(HidController controller) { + controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(); + } + + void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); + void UpdateControllers(u64 userdata, int cycles_late); + + Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; + + CoreTiming::EventType* pad_update_event; + + std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> + controllers{}; +}; + +class Hid final : public ServiceFramework<Hid> { +public: + Hid(); + ~Hid() override; + + std::shared_ptr<IAppletResource> GetAppletResource(); + +private: + void CreateAppletResource(Kernel::HLERequestContext& ctx); + void ActivateXpad(Kernel::HLERequestContext& ctx); + void ActivateDebugPad(Kernel::HLERequestContext& ctx); + void ActivateTouchScreen(Kernel::HLERequestContext& ctx); + void ActivateMouse(Kernel::HLERequestContext& ctx); + void ActivateKeyboard(Kernel::HLERequestContext& ctx); + void ActivateGesture(Kernel::HLERequestContext& ctx); + void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); + void StartSixAxisSensor(Kernel::HLERequestContext& ctx); + void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); + void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); + void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); + void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); + void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); + void ActivateNpad(Kernel::HLERequestContext& ctx); + void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); + void DisconnectNpad(Kernel::HLERequestContext& ctx); + void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); + void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); + void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); + void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); + void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); + void SendVibrationValue(Kernel::HLERequestContext& ctx); + void SendVibrationValues(Kernel::HLERequestContext& ctx); + void GetActualVibrationValue(Kernel::HLERequestContext& ctx); + void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx); + void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx); + void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); + void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); + void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); + void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); + void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); + void StopSixAxisSensor(Kernel::HLERequestContext& ctx); + void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); + void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); + + std::shared_ptr<IAppletResource> applet_resource; +}; + /// Reload input devices. Used when input configuration changed void ReloadInputDevices(); diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 453d90a22..9df7ac50f 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -318,14 +318,18 @@ public: return; } - ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(*map_address, nro_addr, nro_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess()); if (bss_size > 0) { - ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(*map_address + nro_size, bss_addr, bss_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess()); } vm_manager.ReprotectRange(*map_address, header.text_size, @@ -380,13 +384,14 @@ public: return; } - auto* process = Core::CurrentProcess(); - auto& vm_manager = process->VMManager(); + auto& vm_manager = Core::CurrentProcess()->VMManager(); const auto& nro_size = iter->second.size; - ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size, - Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); - ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); + ASSERT(vm_manager + .MirrorMemory(heap_addr, mapped_addr, nro_size, + Kernel::MemoryState::ModuleCodeStatic) + .IsSuccess()); + ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess()); Core::System::GetInstance().InvalidateCpuInstructionCaches(); @@ -408,13 +413,13 @@ private: using SHA256Hash = std::array<u8, 0x20>; struct NROHeader { - u32_le entrypoint_insn; + INSERT_PADDING_WORDS(1); u32_le mod_offset; INSERT_PADDING_WORDS(2); u32_le magic; - INSERT_PADDING_WORDS(1); + u32_le version; u32_le nro_size; - INSERT_PADDING_WORDS(1); + u32_le flags; u32_le text_offset; u32_le text_size; u32_le ro_offset; @@ -430,9 +435,10 @@ private: struct NRRHeader { u32_le magic; - INSERT_PADDING_BYTES(0x1C); + INSERT_PADDING_BYTES(12); u64_le title_id_mask; u64_le title_id_pattern; + INSERT_PADDING_BYTES(16); std::array<u8, 0x100> modulus; std::array<u8, 0x100> signature_1; std::array<u8, 0x100> signature_2; diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index d5df112a0..1c4482e47 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -9,9 +9,9 @@ #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" -#include "core/hle/service/hid/hid.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_user.h" @@ -20,7 +20,8 @@ namespace Service::NFP { namespace ErrCodes { constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP, -1); // TODO(ogniK): Find the actual error code -} +constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); +} // namespace ErrCodes Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) : ServiceFramework(name), module(std::move(module)) { @@ -292,10 +293,9 @@ private: } void OpenApplicationArea(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); - // We don't need to worry about this since we can just open the file + LOG_WARNING(Service_NFP, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); + rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA); } void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { @@ -317,8 +317,8 @@ private: } bool has_attached_handle{}; - const u64 device_handle{Common::MakeMagic('Y', 'U', 'Z', 'U')}; - const u32 npad_id{0}; // Player 1 controller + const u64 device_handle{0}; // Npad device 1 + const u32 npad_id{0}; // Player 1 controller State state{State::NonInitialized}; DeviceState device_state{DeviceState::Initialized}; Kernel::EventPair deactivate_event; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 3bfce0110..0a650f36c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -137,6 +137,10 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< } static void PushGPUEntries(Tegra::CommandList&& entries) { + if (entries.empty()) { + return; + } + auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()}; dma_pusher.Push(std::move(entries)); dma_pusher.DispatchCalls(); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 05af2d593..6db2cce41 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -5,7 +5,6 @@ #include <algorithm> #include <optional> -#include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -22,7 +21,6 @@ #include "core/hle/service/nvflinger/nvflinger.h" #include "core/perf_stats.h" #include "video_core/renderer_base.h" -#include "video_core/video_core.h" namespace Service::NVFlinger { @@ -30,12 +28,6 @@ constexpr std::size_t SCREEN_REFRESH_RATE = 60; constexpr u64 frame_ticks = static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / SCREEN_REFRESH_RATE); NVFlinger::NVFlinger() { - // Add the different displays to the list of displays. - displays.emplace_back(0, "Default"); - displays.emplace_back(1, "External"); - displays.emplace_back(2, "Edid"); - displays.emplace_back(3, "Internal"); - // Schedule the screen composition events composition_event = CoreTiming::RegisterEvent("ScreenComposition", [this](u64 userdata, int cycles_late) { @@ -55,13 +47,13 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { } u64 NVFlinger::OpenDisplay(std::string_view name) { - LOG_WARNING(Service, "Opening display {}", name); + LOG_DEBUG(Service, "Opening \"{}\" display", name); // TODO(Subv): Currently we only support the Default display. ASSERT(name == "Default"); - auto itr = std::find_if(displays.begin(), displays.end(), - [&](const Display& display) { return display.name == name; }); + const auto itr = std::find_if(displays.begin(), displays.end(), + [&](const Display& display) { return display.name == name; }); ASSERT(itr != displays.end()); @@ -73,8 +65,8 @@ u64 NVFlinger::CreateLayer(u64 display_id) { ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment"); - u64 layer_id = next_layer_id++; - u32 buffer_queue_id = next_buffer_queue_id++; + const u64 layer_id = next_layer_id++; + const u32 buffer_queue_id = next_buffer_queue_id++; auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id); display.layers.emplace_back(layer_id, buffer_queue); buffer_queues.emplace_back(std::move(buffer_queue)); @@ -91,16 +83,16 @@ Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id } std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { - auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), - [&](const auto& queue) { return queue->GetId() == id; }); + const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), + [&](const auto& queue) { return queue->GetId() == id; }); ASSERT(itr != buffer_queues.end()); return *itr; } Display& NVFlinger::GetDisplay(u64 display_id) { - auto itr = std::find_if(displays.begin(), displays.end(), - [&](const Display& display) { return display.id == display_id; }); + const auto itr = std::find_if(displays.begin(), displays.end(), + [&](const Display& display) { return display.id == display_id; }); ASSERT(itr != displays.end()); return *itr; @@ -109,8 +101,8 @@ Display& NVFlinger::GetDisplay(u64 display_id) { Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) { auto& display = GetDisplay(display_id); - auto itr = std::find_if(display.layers.begin(), display.layers.end(), - [&](const Layer& layer) { return layer.id == layer_id; }); + const auto itr = std::find_if(display.layers.begin(), display.layers.end(), + [&](const Layer& layer) { return layer.id == layer_id; }); ASSERT(itr != display.layers.end()); return *itr; @@ -145,7 +137,7 @@ void NVFlinger::Compose() { continue; } - auto& igbp_buffer = buffer->get().igbp_buffer; + const auto& igbp_buffer = buffer->get().igbp_buffer; // Now send the buffer to the GPU for drawing. // TODO(Subv): Support more than just disp0. The display device selection is probably based @@ -166,7 +158,7 @@ Layer::~Layer() = default; Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { auto& kernel = Core::System::GetInstance().Kernel(); - vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse, + vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky, fmt::format("Display VSync Event {}", id)); } diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 9abba555b..8f9a0a7f8 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -4,6 +4,7 @@ #pragma once +#include <array> #include <memory> #include <string> #include <string_view> @@ -84,7 +85,13 @@ private: std::shared_ptr<Nvidia::Module> nvdrv; - std::vector<Display> displays; + std::array<Display, 5> displays{{ + {0, "Default"}, + {1, "External"}, + {2, "Edid"}, + {3, "Internal"}, + {4, "Null"}, + }}; std::vector<std::shared_ptr<BufferQueue>> buffer_queues; /// Id to use for the next layer that is created, this counter is shared among all displays. diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 53e7da9c3..6b27dc4a3 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -13,7 +13,7 @@ public: explicit BootMode() : ServiceFramework{"pm:bm"} { static const FunctionInfo functions[] = { {0, &BootMode::GetBootMode, "GetBootMode"}, - {1, nullptr, "SetMaintenanceBoot"}, + {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"}, }; RegisterHandlers(functions); } @@ -24,8 +24,19 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode + rb.PushEnum(boot_mode); } + + void SetMaintenanceBoot(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PM, "called"); + + boot_mode = SystemBootMode::Maintenance; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + SystemBootMode boot_mode = SystemBootMode::Normal; }; class DebugMonitor final : public ServiceFramework<DebugMonitor> { diff --git a/src/core/hle/service/pm/pm.h b/src/core/hle/service/pm/pm.h index 370f2ed72..cc8d3f215 100644 --- a/src/core/hle/service/pm/pm.h +++ b/src/core/hle/service/pm/pm.h @@ -9,7 +9,12 @@ class ServiceManager; } namespace Service::PM { -enum class SystemBootMode : u32 { Normal = 0, Maintenance = 1 }; + +enum class SystemBootMode { + Normal, + Maintenance, +}; + /// Registers all PM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 1ec340466..d25b80ab0 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -70,10 +70,6 @@ #include "core/hle/service/vi/vi.h" #include "core/hle/service/wlan/wlan.h" -using Kernel::ClientPort; -using Kernel::ServerPort; -using Kernel::SharedPtr; - namespace Service { /** @@ -101,33 +97,33 @@ ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_ses ServiceFrameworkBase::~ServiceFrameworkBase() = default; void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { - ASSERT(port == nullptr); - port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); + ASSERT(!port_installed); + + auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); port->SetHleHandler(shared_from_this()); + port_installed = true; } void ServiceFrameworkBase::InstallAsNamedPort() { - ASSERT(port == nullptr); + ASSERT(!port_installed); auto& kernel = Core::System::GetInstance().Kernel(); - SharedPtr<ServerPort> server_port; - SharedPtr<ClientPort> client_port; - std::tie(server_port, client_port) = - ServerPort::CreatePortPair(kernel, max_sessions, service_name); + auto [server_port, client_port] = + Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); server_port->SetHleHandler(shared_from_this()); kernel.AddNamedPort(service_name, std::move(client_port)); + port_installed = true; } Kernel::SharedPtr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort() { - ASSERT(port == nullptr); + ASSERT(!port_installed); auto& kernel = Core::System::GetInstance().Kernel(); - Kernel::SharedPtr<Kernel::ServerPort> server_port; - Kernel::SharedPtr<Kernel::ClientPort> client_port; - std::tie(server_port, client_port) = + auto [server_port, client_port] = Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name); - port = MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)).Unwrap(); + auto port = MakeResult(std::move(server_port)).Unwrap(); port->SetHleHandler(shared_from_this()); + port_installed = true; return client_port; } @@ -152,8 +148,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext } buf.push_back('}'); - LOG_ERROR(Service, "unknown / unimplemented {}", fmt::to_string(buf)); - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); } void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 98483ecf1..029533628 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -96,11 +96,9 @@ private: /// Maximum number of concurrent sessions that this service can handle. u32 max_sessions; - /** - * Port where incoming connections will be received. Only created when InstallAsService() or - * InstallAsNamedPort() are called. - */ - Kernel::SharedPtr<Kernel::ServerPort> port; + /// Flag to store if a port was already create/installed to detect multiple install attempts, + /// which is not supported. + bool port_installed = false; /// Function used to safely up-cast pointers to the derived class before invoking a handler. InvokerFn* handler_invoker; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 0d0f63a78..142929124 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -54,13 +54,11 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService return ERR_ALREADY_REGISTERED; auto& kernel = Core::System::GetInstance().Kernel(); - Kernel::SharedPtr<Kernel::ServerPort> server_port; - Kernel::SharedPtr<Kernel::ClientPort> client_port; - std::tie(server_port, client_port) = + auto [server_port, client_port] = Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name); registered_services.emplace(std::move(name), std::move(client_port)); - return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); + return MakeResult(std::move(server_port)); } ResultCode ServiceManager::UnregisterService(const std::string& name) { @@ -83,7 +81,7 @@ ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( return ERR_SERVICE_NOT_REGISTERED; } - return MakeResult<Kernel::SharedPtr<Kernel::ClientPort>>(it->second); + return MakeResult(it->second); } ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ServiceManager::ConnectToService( @@ -147,12 +145,13 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) { const std::string name(name_buf.begin(), end); - const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>()); - const auto session_count = rp.PopRaw<u32>(); + const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); + const auto max_session_count = rp.PopRaw<u32>(); - LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool); + LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, + max_session_count, is_light); - auto handle = service_manager->RegisterService(name, session_count); + auto handle = service_manager->RegisterService(name, max_session_count); if (handle.Failed()) { LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", handle.Code().raw); diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 60b201d06..c13640ad8 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -12,9 +12,16 @@ #include "core/hle/kernel/client_session.h" #include "core/hle/service/time/interface.h" #include "core/hle/service/time/time.h" +#include "core/settings.h" namespace Service::Time { +static std::chrono::seconds GetSecondsSinceEpoch() { + return std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + + Settings::values.custom_rtc_differential; +} + static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, CalendarAdditionalInfo& additional_info, [[maybe_unused]] const TimeZoneRule& /*rule*/) { @@ -68,9 +75,7 @@ public: private: void GetCurrentTime(Kernel::HLERequestContext& ctx) { - const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()) - .count()}; + const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; LOG_DEBUG(Service_Time, "called"); IPC::ResponseBuilder rb{ctx, 4}; @@ -264,14 +269,9 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Time, "called"); IPC::RequestParser rp{ctx}; - auto unknown_u8 = rp.PopRaw<u8>(); - - ClockSnapshot clock_snapshot{}; + const auto initial_type = rp.PopRaw<u8>(); - const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()) - .count()}; - CalendarTime calendar_time{}; + const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; const std::time_t time(time_since_epoch); const std::tm* tm = std::localtime(&time); if (tm == nullptr) { @@ -280,16 +280,19 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code return; } - SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / - 1000}; - LocationName location_name{"UTC"}; + const SteadyClockTimePoint steady_clock_time_point{ + CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000, {}}; + + CalendarTime calendar_time{}; calendar_time.year = tm->tm_year + 1900; calendar_time.month = tm->tm_mon + 1; calendar_time.day = tm->tm_mday; calendar_time.hour = tm->tm_hour; calendar_time.minute = tm->tm_min; calendar_time.second = tm->tm_sec; + + ClockSnapshot clock_snapshot{}; clock_snapshot.system_posix_time = time_since_epoch; clock_snapshot.network_posix_time = time_since_epoch; clock_snapshot.system_calendar_time = calendar_time; @@ -302,9 +305,10 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { clock_snapshot.network_calendar_info = additional_info; clock_snapshot.steady_clock_timepoint = steady_clock_time_point; - clock_snapshot.location_name = location_name; + clock_snapshot.location_name = LocationName{"UTC"}; clock_snapshot.clock_auto_adjustment_enabled = 1; - clock_snapshot.ipc_u8 = unknown_u8; + clock_snapshot.type = initial_type; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index ea43fbea7..f11affe95 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -22,7 +22,6 @@ struct CalendarTime { u8 hour; u8 minute; u8 second; - INSERT_PADDING_BYTES(1); }; static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size"); @@ -30,7 +29,7 @@ struct CalendarAdditionalInfo { u32_le day_of_week; u32_le day_of_year; std::array<u8, 8> name; - INSERT_PADDING_BYTES(1); + u8 is_dst; s32_le utc_offset; }; static_assert(sizeof(CalendarAdditionalInfo) == 0x18, @@ -42,8 +41,10 @@ struct TimeZoneRule { }; struct SteadyClockTimePoint { + using SourceID = std::array<u8, 16>; + u64_le value; - INSERT_PADDING_WORDS(4); + SourceID source_id; }; static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); @@ -66,8 +67,9 @@ struct ClockSnapshot { SteadyClockTimePoint steady_clock_timepoint; LocationName location_name; u8 clock_auto_adjustment_enabled; - u8 ipc_u8; - INSERT_PADDING_BYTES(2); + u8 type; + u8 version; + INSERT_PADDING_BYTES(1); }; static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size"); diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 311b0c765..0f2c25182 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -19,6 +19,7 @@ #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/thread.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvflinger/buffer_queue.h" @@ -31,12 +32,26 @@ namespace Service::VI { +constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1}; +constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6}; + struct DisplayInfo { + /// The name of this particular display. char display_name[0x40]{"Default"}; - u64 unknown_1{1}; - u64 unknown_2{1}; - u64 width{1280}; - u64 height{720}; + + /// Whether or not the display has a limited number of layers. + u8 has_limited_layers{1}; + INSERT_PADDING_BYTES(7){}; + + /// Indicates the total amount of layers supported by the display. + /// @note This is only valid if has_limited_layers is set. + u64 max_layers{1}; + + /// Maximum width in pixels. + u64 width{1920}; + + /// Maximum height in pixels. + u64 height{1080}; }; static_assert(sizeof(DisplayInfo) == 0x60, "DisplayInfo has wrong size"); @@ -502,10 +517,12 @@ private: void TransactParcel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); - u32 flags = rp.Pop<u32>(); - LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); + const u32 id = rp.Pop<u32>(); + const auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); + const u32 flags = rp.Pop<u32>(); + + LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, + static_cast<u32>(transaction), flags); auto buffer_queue = nv_flinger->GetBufferQueue(id); @@ -593,9 +610,10 @@ private: void AdjustRefcount(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - s32 addval = rp.PopRaw<s32>(); - u32 type = rp.Pop<u32>(); + const u32 id = rp.Pop<u32>(); + const s32 addval = rp.PopRaw<s32>(); + const u32 type = rp.Pop<u32>(); + LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, type); @@ -605,11 +623,12 @@ private: void GetNativeHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u32 id = rp.Pop<u32>(); - u32 unknown = rp.Pop<u32>(); + const u32 id = rp.Pop<u32>(); + const u32 unknown = rp.Pop<u32>(); + LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); - auto buffer_queue = nv_flinger->GetBufferQueue(id); + const auto buffer_queue = nv_flinger->GetBufferQueue(id); // TODO(Subv): Find out what this actually is. IPC::ResponseBuilder rb{ctx, 2, 1}; @@ -674,22 +693,25 @@ public: private: void SetLayerZ(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - u64 z_value = rp.Pop<u64>(); + const u64 layer_id = rp.Pop<u64>(); + const u64 z_value = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}, z_value=0x{:016X}", layer_id, + z_value); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } + // This function currently does nothing but return a success error code in + // the vi library itself, so do the same thing, but log out the passed in values. void SetLayerVisibility(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - bool visibility = rp.Pop<bool>(); - LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, - visibility); + const u64 layer_id = rp.Pop<u64>(); + const bool visibility = rp.Pop<bool>(); + + LOG_DEBUG(Service_VI, "called, layer_id=0x{:08X}, visibility={}", layer_id, visibility); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -796,25 +818,27 @@ public: private: void CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display = rp.Pop<u64>(); + const u64 display = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display=0x{:016X}", display); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void CreateManagedLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 unknown = rp.Pop<u32>(); + const u32 unknown = rp.Pop<u32>(); rp.Skip(1, false); - u64 display = rp.Pop<u64>(); - u64 aruid = rp.Pop<u64>(); + const u64 display = rp.Pop<u64>(); + const u64 aruid = rp.Pop<u64>(); - u64 layer_id = nv_flinger->CreateLayer(display); + LOG_WARNING(Service_VI, + "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", + unknown, display, aruid); + + const u64 layer_id = nv_flinger->CreateLayer(display); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); @@ -822,11 +846,12 @@ private: } void AddToLayerStack(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 stack = rp.Pop<u32>(); - u64 layer_id = rp.Pop<u64>(); + const u32 stack = rp.Pop<u32>(); + const u64 layer_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. stack=0x{:08X}, layer_id=0x{:016X}", stack, + layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -834,8 +859,9 @@ private: void SetLayerVisibility(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); - bool visibility = rp.Pop<bool>(); + const u64 layer_id = rp.Pop<u64>(); + const bool visibility = rp.Pop<bool>(); + LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, visibility); @@ -852,6 +878,22 @@ public: ~IApplicationDisplayService() = default; private: + enum class ConvertedScaleMode : u64 { + Freeze = 0, + ScaleToWindow = 1, + ScaleAndCrop = 2, + None = 3, + PreserveAspectRatio = 4, + }; + + enum class NintendoScaleMode : u32 { + None = 0, + Freeze = 1, + ScaleToWindow = 2, + ScaleAndCrop = 3, + PreserveAspectRatio = 4, + }; + void GetRelayService(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_VI, "(STUBBED) called"); @@ -888,10 +930,23 @@ private: LOG_WARNING(Service_VI, "(STUBBED) called"); IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + const auto name_buf = rp.PopRaw<std::array<char, 0x40>>(); + + OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()}); + } + + void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called"); - std::string name(name_buf.begin(), end); + OpenDisplayImpl(ctx, "Default"); + } + + void OpenDisplayImpl(Kernel::HLERequestContext& ctx, std::string_view name) { + const auto trim_pos = name.find('\0'); + + if (trim_pos != std::string_view::npos) { + name.remove_suffix(name.size() - trim_pos); + } ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); @@ -901,45 +956,65 @@ private: } void CloseDisplay(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - void GetDisplayResolution(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); + // This literally does nothing internally in the actual service itself, + // and just returns a successful result code regardless of the input. + void SetDisplayEnabled(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_VI, "called."); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void GetDisplayResolution(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_DEBUG(Service_VI, "called. display_id=0x{:016X}", display_id); IPC::ResponseBuilder rb{ctx, 6}; rb.Push(RESULT_SUCCESS); - if (Settings::values.use_docked_mode) { - rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) * - static_cast<u32>(Settings::values.resolution_factor)); - rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) * - static_cast<u32>(Settings::values.resolution_factor)); - } else { - rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) * - static_cast<u32>(Settings::values.resolution_factor)); - rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) * - static_cast<u32>(Settings::values.resolution_factor)); - } + // This only returns the fixed values of 1280x720 and makes no distinguishing + // between docked and undocked dimensions. We take the liberty of applying + // the resolution scaling factor here. + rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) * + static_cast<u32>(Settings::values.resolution_factor)); + rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) * + static_cast<u32>(Settings::values.resolution_factor)); } void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u32 scaling_mode = rp.Pop<u32>(); - u64 unknown = rp.Pop<u64>(); + const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); + const u64 unknown = rp.Pop<u64>(); + + LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", + static_cast<u32>(scaling_mode), unknown); IPC::ResponseBuilder rb{ctx, 2}; + + if (scaling_mode > NintendoScaleMode::PreserveAspectRatio) { + LOG_ERROR(Service_VI, "Invalid scaling mode provided."); + rb.Push(ERR_OPERATION_FAILED); + return; + } + + if (scaling_mode != NintendoScaleMode::ScaleToWindow && + scaling_mode != NintendoScaleMode::PreserveAspectRatio) { + LOG_ERROR(Service_VI, "Unsupported scaling mode supplied."); + rb.Push(ERR_UNSUPPORTED); + return; + } + rb.Push(RESULT_SUCCESS); } @@ -957,19 +1032,19 @@ private: } void OpenLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); - IPC::RequestParser rp{ctx}; - auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); + const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); + + const std::string display_name(name_buf.begin(), end); - std::string display_name(name_buf.begin(), end); + const u64 layer_id = rp.Pop<u64>(); + const u64 aruid = rp.Pop<u64>(); - u64 layer_id = rp.Pop<u64>(); - u64 aruid = rp.Pop<u64>(); + LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); - u64 display_id = nv_flinger->OpenDisplay(display_name); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + const u64 display_id = nv_flinger->OpenDisplay(display_name); + const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; IPC::ResponseBuilder rb{ctx, 4}; @@ -978,17 +1053,17 @@ private: } void CreateStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_VI, "called"); - IPC::RequestParser rp{ctx}; - u32 flags = rp.Pop<u32>(); + const u32 flags = rp.Pop<u32>(); rp.Pop<u32>(); // padding - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_DEBUG(Service_VI, "called. flags=0x{:08X}, display_id=0x{:016X}", flags, display_id); // TODO(Subv): What's the difference between a Stray and a Managed layer? - u64 layer_id = nv_flinger->CreateLayer(display_id); - u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); + const u64 layer_id = nv_flinger->CreateLayer(display_id); + const u32 buffer_queue_id = nv_flinger->GetBufferQueueId(display_id, layer_id); NativeWindow native_window{buffer_queue_id}; IPC::ResponseBuilder rb{ctx, 6}; @@ -998,73 +1073,59 @@ private: } void DestroyStrayLayer(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 layer_id = rp.Pop<u64>(); + const u64 layer_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_VI, "(STUBBED) called"); - IPC::RequestParser rp{ctx}; - u64 display_id = rp.Pop<u64>(); + const u64 display_id = rp.Pop<u64>(); + + LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); - auto vsync_event = nv_flinger->GetVsyncEvent(display_id); + const auto vsync_event = nv_flinger->GetVsyncEvent(display_id); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(vsync_event); } - enum class ConvertedScaleMode : u64 { - None = 0, // VI seems to name this as "Unknown" but lots of games pass it, assume it's no - // scaling/default - Freeze = 1, - ScaleToWindow = 2, - Crop = 3, - NoCrop = 4, - }; - - // This struct is different, currently it's 1:1 but this might change in the future. - enum class NintendoScaleMode : u32 { - None = 0, - Freeze = 1, - ScaleToWindow = 2, - Crop = 3, - NoCrop = 4, - }; - void ConvertScalingMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto mode = rp.PopEnum<NintendoScaleMode>(); + const auto mode = rp.PopEnum<NintendoScaleMode>(); LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode)); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); + const auto converted_mode = ConvertScalingModeImpl(mode); + + if (converted_mode.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.PushEnum(*converted_mode); + } else { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(converted_mode.Code()); + } + } + + static ResultVal<ConvertedScaleMode> ConvertScalingModeImpl(NintendoScaleMode mode) { switch (mode) { case NintendoScaleMode::None: - rb.PushEnum(ConvertedScaleMode::None); - break; + return MakeResult(ConvertedScaleMode::None); case NintendoScaleMode::Freeze: - rb.PushEnum(ConvertedScaleMode::Freeze); - break; + return MakeResult(ConvertedScaleMode::Freeze); case NintendoScaleMode::ScaleToWindow: - rb.PushEnum(ConvertedScaleMode::ScaleToWindow); - break; - case NintendoScaleMode::Crop: - rb.PushEnum(ConvertedScaleMode::Crop); - break; - case NintendoScaleMode::NoCrop: - rb.PushEnum(ConvertedScaleMode::NoCrop); - break; + return MakeResult(ConvertedScaleMode::ScaleToWindow); + case NintendoScaleMode::ScaleAndCrop: + return MakeResult(ConvertedScaleMode::ScaleAndCrop); + case NintendoScaleMode::PreserveAspectRatio: + return MakeResult(ConvertedScaleMode::PreserveAspectRatio); default: - UNIMPLEMENTED_MSG("Unknown scaling mode {}", static_cast<u32>(mode)); - rb.PushEnum(ConvertedScaleMode::None); - break; + return ERR_OPERATION_FAILED; } } @@ -1082,9 +1143,9 @@ IApplicationDisplayService::IApplicationDisplayService( "GetIndirectDisplayTransactionService"}, {1000, &IApplicationDisplayService::ListDisplays, "ListDisplays"}, {1010, &IApplicationDisplayService::OpenDisplay, "OpenDisplay"}, - {1011, nullptr, "OpenDefaultDisplay"}, + {1011, &IApplicationDisplayService::OpenDefaultDisplay, "OpenDefaultDisplay"}, {1020, &IApplicationDisplayService::CloseDisplay, "CloseDisplay"}, - {1101, nullptr, "SetDisplayEnabled"}, + {1101, &IApplicationDisplayService::SetDisplayEnabled, "SetDisplayEnabled"}, {1102, &IApplicationDisplayService::GetDisplayResolution, "GetDisplayResolution"}, {2020, &IApplicationDisplayService::OpenLayer, "OpenLayer"}, {2021, nullptr, "CloseLayer"}, |