summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/am/am.cpp82
-rw-r--r--src/core/hle/service/am/am.h2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp8
-rw-r--r--src/core/hle/service/am/applets/applets.h2
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp77
-rw-r--r--src/core/hle/service/am/applets/profile_select.h50
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp3
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp190
-rw-r--r--src/core/hle/service/am/applets/web_browser.h44
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp12
-rw-r--r--src/core/hle/service/fatal/fatal.cpp3
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp47
-rw-r--r--src/core/hle/service/filesystem/filesystem.h6
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp52
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
-rw-r--r--src/core/hle/service/hid/hid.cpp1064
-rw-r--r--src/core/hle/service/hid/hid.h110
-rw-r--r--src/core/hle/service/ldr/ldr.cpp36
-rw-r--r--src/core/hle/service/nfp/nfp.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp34
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h9
-rw-r--r--src/core/hle/service/pm/pm.cpp15
-rw-r--r--src/core/hle/service/pm/pm.h7
-rw-r--r--src/core/hle/service/service.cpp31
-rw-r--r--src/core/hle/service/service.h8
-rw-r--r--src/core/hle/service/sm/sm.cpp17
-rw-r--r--src/core/hle/service/time/time.cpp34
-rw-r--r--src/core/hle/service/time/time.h12
-rw-r--r--src/core/hle/service/vi/vi.cpp303
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"},