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/acc/acc.cpp44
-rw-r--r--src/core/hle/service/acc/acc.h1
-rw-r--r--src/core/hle/service/acc/acc_su.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp2
-rw-r--r--src/core/hle/service/acc/acc_u1.cpp2
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp30
-rw-r--r--src/core/hle/service/acc/profile_manager.h30
-rw-r--r--src/core/hle/service/am/am.cpp657
-rw-r--r--src/core/hle/service/am/am.h69
-rw-r--r--src/core/hle/service/am/applet_ae.cpp100
-rw-r--r--src/core/hle/service/am/applet_ae.h6
-rw-r--r--src/core/hle/service/am/applet_oe.cpp48
-rw-r--r--src/core/hle/service/am/applet_oe.h6
-rw-r--r--src/core/hle/service/am/applets/applets.cpp114
-rw-r--r--src/core/hle/service/am/applets/applets.h109
-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.cpp160
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h74
-rw-r--r--src/core/hle/service/am/applets/stub_applet.cpp70
-rw-r--r--src/core/hle/service/am/applets/stub_applet.h24
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp32
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/apm/interface.cpp16
-rw-r--r--src/core/hle/service/arp/arp.cpp4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp48
-rw-r--r--src/core/hle/service/audio/audout_u.h3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp102
-rw-r--r--src/core/hle/service/audio/hwopus.cpp50
-rw-r--r--src/core/hle/service/bcat/module.cpp3
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp43
-rw-r--r--src/core/hle/service/btm/btm.cpp121
-rw-r--r--src/core/hle/service/erpt/erpt.cpp12
-rw-r--r--src/core/hle/service/fatal/fatal.cpp3
-rw-r--r--src/core/hle/service/fgm/fgm.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp104
-rw-r--r--src/core/hle/service/filesystem/filesystem.h22
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp234
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h41
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h7
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h9
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp488
-rw-r--r--src/core/hle/service/hid/controllers/npad.h56
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h12
-rw-r--r--src/core/hle/service/hid/hid.cpp278
-rw-r--r--src/core/hle/service/hid/irs.cpp54
-rw-r--r--src/core/hle/service/lbl/lbl.cpp12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp12
-rw-r--r--src/core/hle/service/ldr/ldr.cpp392
-rw-r--r--src/core/hle/service/lm/lm.cpp17
-rw-r--r--src/core/hle/service/mm/mm_u.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc.cpp24
-rw-r--r--src/core/hle/service/nfp/nfp.cpp58
-rw-r--r--src/core/hle/service/nfp/nfp.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp43
-rw-r--r--src/core/hle/service/nim/nim.cpp43
-rw-r--r--src/core/hle/service/ns/ns.cpp72
-rw-r--r--src/core/hle/service/ns/pl_u.cpp18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp29
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp16
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp33
-rw-r--r--src/core/hle/service/nvdrv/interface.h9
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp32
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h22
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp25
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/pctl/module.cpp8
-rw-r--r--src/core/hle/service/pm/pm.cpp4
-rw-r--r--src/core/hle/service/psc/psc.cpp4
-rw-r--r--src/core/hle/service/service.cpp35
-rw-r--r--src/core/hle/service/service.h8
-rw-r--r--src/core/hle/service/set/set.cpp52
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/set/set_sys.cpp8
-rw-r--r--src/core/hle/service/sm/controller.cpp11
-rw-r--r--src/core/hle/service/sm/sm.cpp67
-rw-r--r--src/core/hle/service/sm/sm.h3
-rw-r--r--src/core/hle/service/spl/module.cpp13
-rw-r--r--src/core/hle/service/spl/module.h4
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/interface.cpp5
-rw-r--r--src/core/hle/service/time/time.cpp172
-rw-r--r--src/core/hle/service/time/time.h28
-rw-r--r--src/core/hle/service/usb/usb.cpp12
-rw-r--r--src/core/hle/service/vi/vi.cpp256
96 files changed, 4103 insertions, 1039 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index c6437a671..1f8ed265e 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -21,17 +21,6 @@
namespace Service::Account {
-// TODO: RE this structure
-struct UserData {
- INSERT_PADDING_WORDS(1);
- u32 icon_id;
- u8 bg_color_id;
- INSERT_PADDING_BYTES(0x7);
- INSERT_PADDING_BYTES(0x10);
- INSERT_PADDING_BYTES(0x60);
-};
-static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
-
// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
// used as a backup should the one on disk not exist
constexpr u32 backup_jpeg_size = 107;
@@ -72,9 +61,11 @@ private:
void Get(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
ProfileBase profile_base{};
- std::array<u8, MAX_DATA> data{};
+ ProfileData data{};
if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
- ctx.WriteBuffer(data);
+ std::array<u8, sizeof(ProfileData)> raw_data;
+ std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
+ ctx.WriteBuffer(raw_data);
IPC::ResponseBuilder rb{ctx, 16};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(profile_base);
@@ -216,10 +207,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
UUID user_id = rp.PopRaw<UUID>();
+ LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProfile>(user_id, *profile_manager);
- LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
}
void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
@@ -236,10 +228,34 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
}
void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IManagerForApplication>();
+}
+
+void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
+ // A u8 is passed into this function which we can safely ignore. It's to determine if we have
+ // access to use the network or not by the looks of it
+ IPC::ResponseBuilder rb{ctx, 6};
+ if (profile_manager->GetUserCount() != 1) {
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u128>(INVALID_UUID);
+ return;
+ }
+
+ const auto user_list = profile_manager->GetAllUsers();
+ if (std::all_of(user_list.begin(), user_list.end(),
+ [](const auto& user) { return user.uuid == INVALID_UUID; })) {
+ rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
+ rb.PushRaw<u128>(INVALID_UUID);
+ return;
+ }
+
+ // Select the first user we have
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
}
Module::Interface::Interface(std::shared_ptr<Module> module,
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index c7ed74351..89b2104fa 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -27,6 +27,7 @@ public:
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
+ void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index ad455c3a7..5e2030355 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -17,7 +17,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_SU::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 72d4adf35..a4d705b45 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -17,7 +17,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_U0::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index d480f08e5..8fffc93b5 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -17,7 +17,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
{5, &ACC_U1::GetProfile, "GetProfile"},
{6, nullptr, "GetProfileDigest"},
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
- {51, nullptr, "TrySelectUserWithoutInteraction"},
+ {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
{60, nullptr, "ListOpenContextStoredUsers"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 3cac1b4ff..1316d0b07 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -2,8 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <random>
+#include <fmt/format.h>
+
#include "common/file_util.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/settings.h"
@@ -15,7 +18,7 @@ struct UserRaw {
UUID uuid2;
u64 timestamp;
ProfileUsername username;
- INSERT_PADDING_BYTES(0x80);
+ ProfileData extra_data;
};
static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
@@ -39,6 +42,19 @@ UUID UUID::Generate() {
return UUID{distribution(gen), distribution(gen)};
}
+std::string UUID::Format() const {
+ return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
+}
+
+std::string UUID::FormatSwitch() const {
+ std::array<u8, 16> s{};
+ std::memcpy(s.data(), uuid.data(), sizeof(u128));
+ return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
+ ":02x}{:02x}{:02x}{:02x}{:02x}",
+ s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
+ s[12], s[13], s[14], s[15]);
+}
+
ProfileManager::ProfileManager() {
ParseUserSaveFile();
@@ -195,7 +211,7 @@ std::size_t ProfileManager::GetOpenUserCount() const {
/// Checks if a user id exists in our profile manager
bool ProfileManager::UserExists(UUID uuid) const {
- return GetUserIndex(uuid) != std::nullopt;
+ return GetUserIndex(uuid).has_value();
}
bool ProfileManager::UserExistsIndex(std::size_t index) const {
@@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() {
return;
}
- for (std::size_t i = 0; i < MAX_USERS; ++i) {
- const auto& user = data.users[i];
+ for (const auto& user : data.users) {
+ if (user.uuid == UUID(INVALID_UUID)) {
+ continue;
+ }
- if (user.uuid != UUID(INVALID_UUID))
- AddUser({user.uuid, user.username, user.timestamp, {}, false});
+ AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false});
}
std::stable_partition(profiles.begin(), profiles.end(),
@@ -344,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() {
raw.users[i].uuid2 = profiles[i].user_uuid;
raw.users[i].uuid = profiles[i].user_uuid;
raw.users[i].timestamp = profiles[i].creation_time;
+ raw.users[i].extra_data = profiles[i].data;
}
const auto raw_path =
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 1cd2e51b2..c4ce2e0b3 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -13,7 +13,6 @@
namespace Service::Account {
constexpr std::size_t MAX_USERS = 8;
-constexpr std::size_t MAX_DATA = 128;
constexpr u128 INVALID_UUID{{0, 0}};
struct UUID {
@@ -42,25 +41,28 @@ struct UUID {
void Invalidate() {
uuid = INVALID_UUID;
}
- std::string Format() const {
- return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
- }
- std::string FormatSwitch() const {
- std::array<u8, 16> s{};
- std::memcpy(s.data(), uuid.data(), sizeof(u128));
- return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
- ":02x}{:02x}{:02x}{:02x}{:02x}",
- s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
- s[12], s[13], s[14], s[15]);
- }
+ std::string Format() const;
+ std::string FormatSwitch() const;
};
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
-using ProfileUsername = std::array<u8, 0x20>;
-using ProfileData = std::array<u8, MAX_DATA>;
+constexpr std::size_t profile_username_size = 32;
+using ProfileUsername = std::array<u8, profile_username_size>;
using UserIDArray = std::array<UUID, MAX_USERS>;
+/// Contains extra data related to a user.
+/// TODO: RE this structure
+struct ProfileData {
+ INSERT_PADDING_WORDS(1);
+ u32 icon_id;
+ u8 bg_color_id;
+ INSERT_PADDING_BYTES(0x7);
+ INSERT_PADDING_BYTES(0x10);
+ INSERT_PADDING_BYTES(0x60);
+};
+static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size");
+
/// This holds general information about a users profile. This is where we store all the information
/// based on a specific user
struct ProfileInfo {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 59aafd616..d13ce4dca 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -6,14 +6,23 @@
#include <cinttypes>
#include <cstring>
#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/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
#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/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
@@ -28,6 +37,14 @@
namespace Service::AM {
+constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
+constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
+
+enum class AppletId : u32 {
+ ProfileSelect = 0x10,
+ SoftwareKeyboard = 0x11,
+};
+
constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
struct LaunchParameters {
@@ -57,10 +74,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) {
@@ -196,15 +216,16 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- launchable_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
+ launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "ISelfController:LaunchableEvent");
}
ISelfController::~ISelfController() = default;
void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
- // Takes 3 input u8s with each field located immediately after the previous u8, these are
- // bool flags. No output.
+ // Takes 3 input u8s with each field located immediately after the previous
+ // u8, these are bool flags. No output.
+ LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
@@ -217,128 +238,172 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
+ LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
}
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
+ LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
}
void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
- // Takes 3 input u8s with each field located immediately after the previous u8, these are
- // bool flags. No output.
+ // Takes 3 input u8s with each field located immediately after the previous
+ // u8, these are bool flags. No output.
IPC::RequestParser rp{ctx};
bool enabled = rp.Pop<bool>();
+ LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
}
void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
- launchable_event->Signal();
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ launchable_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(launchable_event);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ rb.PushCopyObjects(launchable_event.readable);
}
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
- // TODO(Subv): Find out how AM determines the display to use, for now just create the layer
- // in the Default display.
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+ // TODO(Subv): Find out how AM determines the display to use, for now just
+ // create the layer in the Default display.
u64 display_id = nvflinger->OpenDisplay("Default");
u64 layer_id = nvflinger->CreateLayer(display_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(layer_id);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
idle_time_detection_extension = rp.Pop<u32>();
+ LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
+ idle_time_detection_extension);
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(idle_time_detection_extension);
+}
- LOG_WARNING(Service_AM, "(STUBBED) called");
+AppletMessageQueue::AppletMessageQueue() {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "AMMessageQueue:OnMessageRecieved");
+ on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
+}
+
+AppletMessageQueue::~AppletMessageQueue() = default;
+
+const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
+ const {
+ return on_new_message.readable;
+}
+
+const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
+ const {
+ return on_operation_mode_changed.readable;
+}
+
+void AppletMessageQueue::PushMessage(AppletMessage msg) {
+ messages.push(msg);
+ on_new_message.writable->Signal();
+}
+
+AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
+ if (messages.empty()) {
+ on_new_message.writable->Clear();
+ return AppletMessage::NoMessage;
+ }
+ auto msg = messages.front();
+ messages.pop();
+ if (messages.empty()) {
+ on_new_message.writable->Clear();
+ }
+ return msg;
}
-ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
+std::size_t AppletMessageQueue::GetMessageCount() const {
+ return messages.size();
+}
+
+void AppletMessageQueue::OperationModeChanged() {
+ PushMessage(AppletMessage::OperationModeChanged);
+ PushMessage(AppletMessage::PerformanceModeChanged);
+ on_operation_mode_changed.writable->Signal();
+}
+
+ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -371,101 +436,131 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
// clang-format on
RegisterHandlers(functions);
-
- auto& kernel = Core::System::GetInstance().Kernel();
- event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
}
ICommonStateGetter::~ICommonStateGetter() = default;
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
-
- LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
- event->Signal();
+ LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
}
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(15);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
}
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(FocusState::InFocus));
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
- event->Signal();
+ LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
}
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
+ static_cast<u32>(Settings::values.resolution_factor));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
+ static_cast<u32>(Settings::values.resolution_factor));
} else {
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
+ static_cast<u32>(Settings::values.resolution_factor));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
+ static_cast<u32>(Settings::values.resolution_factor));
}
+}
- LOG_DEBUG(Service_AM, "called");
+IStorage::IStorage(std::vector<u8> buffer)
+ : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IStorage::Open, "Open"},
+ {1, nullptr, "OpenTransferStorage"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IStorage::~IStorage() = default;
+
+const std::vector<u8>& IStorage::GetData() const {
+ return buffer;
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode};
+ LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode};
+ LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
: APM::PerformanceMode::Handheld));
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
-class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
+class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
- explicit IStorageAccessor(std::vector<u8> buffer)
- : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
+ explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
+ : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &IStorageAccessor::GetSize, "GetSize"},
- {10, &IStorageAccessor::Write, "Write"},
- {11, &IStorageAccessor::Read, "Read"},
+ {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
+ {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
+ {10, &ILibraryAppletAccessor::Start, "Start"},
+ {20, nullptr, "RequestExit"},
+ {25, nullptr, "Terminate"},
+ {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
+ {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
+ {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
+ {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
+ {102, nullptr, "PushExtraStorage"},
+ {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
+ {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
+ {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
+ {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
+ {110, nullptr, "NeedsToExitProcess"},
+ {120, nullptr, "GetLibraryAppletInfo"},
+ {150, nullptr, "RequestForAppletToGetForeground"},
+ {160, nullptr, "GetIndirectLayerConsumerHandle"},
};
// clang-format on
@@ -473,158 +568,199 @@ public:
}
private:
- std::vector<u8> buffer;
+ void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- void GetSize(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 4};
+ const auto event = applet->GetBroker().GetStateChangedEvent();
+ IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(buffer.size()));
+ rb.PushCopyObjects(event);
+ }
+ void IsCompleted(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(applet->TransactionComplete());
}
- void Write(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
+ void GetResult(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(applet->GetStatus());
+ }
- const u64 offset{rp.Pop<u64>()};
- const std::vector<u8> data{ctx.ReadBuffer()};
+ void Start(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- ASSERT(offset + data.size() <= buffer.size());
+ ASSERT(applet != nullptr);
- std::memcpy(&buffer[offset], data.data(), data.size());
+ applet->Initialize();
+ applet->Execute();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_DEBUG(Service_AM, "called, offset={}", offset);
}
- void Read(Kernel::HLERequestContext& ctx) {
+ void PushInData(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::RequestParser rp{ctx};
+ applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
- const u64 offset{rp.Pop<u64>()};
- const std::size_t size{ctx.GetWriteBufferSize()};
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
- ASSERT(offset + size <= buffer.size());
+ void PopOutData(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- ctx.WriteBuffer(buffer.data() + offset, size);
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ const auto storage = applet->GetBroker().PopNormalDataToGame();
+ if (storage == nullptr) {
+ LOG_ERROR(Service_AM,
+ "storage is a nullptr. There is no data in the current normal channel");
- LOG_DEBUG(Service_AM, "called, offset={}", offset);
+ rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ return;
+ }
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorage>(std::move(*storage));
}
-};
-class IStorage final : public ServiceFramework<IStorage> {
-public:
- explicit IStorage(std::vector<u8> buffer)
- : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IStorage::Open, "Open"},
- {1, nullptr, "OpenTransferStorage"},
- };
- // clang-format on
+ void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- RegisterHandlers(functions);
+ IPC::RequestParser rp{ctx};
+ applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
+
+ ASSERT(applet->IsInitialized());
+ applet->ExecuteInteractive();
+ applet->Execute();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
}
-private:
- std::vector<u8> buffer;
+ void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- void Open(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ const auto storage = applet->GetBroker().PopInteractiveDataToGame();
+ if (storage == nullptr) {
+ LOG_ERROR(Service_AM,
+ "storage is a nullptr. There is no data in the current interactive channel");
+
+ rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ return;
+ }
+
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::IStorageAccessor>(buffer);
+ rb.PushIpcInterface<IStorage>(std::move(*storage));
+ }
+ void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
+ }
+
+ void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
}
+
+ std::shared_ptr<Applets::Applet> applet;
};
-class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
-public:
- explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") {
- // clang-format off
+void IStorage::Open(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IStorageAccessor>(*this);
+}
+
+IStorageAccessor::IStorageAccessor(IStorage& storage)
+ : ServiceFramework("IStorageAccessor"), backing(storage) {
+ // clang-format off
static const FunctionInfo functions[] = {
- {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
- {1, nullptr, "IsCompleted"},
- {10, &ILibraryAppletAccessor::Start, "Start"},
- {20, nullptr, "RequestExit"},
- {25, nullptr, "Terminate"},
- {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
- {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
- {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
- {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
- {102, nullptr, "PushExtraStorage"},
- {103, nullptr, "PushInteractiveInData"},
- {104, nullptr, "PopInteractiveOutData"},
- {105, nullptr, "GetPopOutDataEvent"},
- {106, nullptr, "GetPopInteractiveOutDataEvent"},
- {110, nullptr, "NeedsToExitProcess"},
- {120, nullptr, "GetLibraryAppletInfo"},
- {150, nullptr, "RequestForAppletToGetForeground"},
- {160, nullptr, "GetIndirectLayerConsumerHandle"},
+ {0, &IStorageAccessor::GetSize, "GetSize"},
+ {10, &IStorageAccessor::Write, "Write"},
+ {11, &IStorageAccessor::Read, "Read"},
};
- // clang-format on
+ // clang-format on
- RegisterHandlers(functions);
+ RegisterHandlers(functions);
+}
- auto& kernel = Core::System::GetInstance().Kernel();
- state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "ILibraryAppletAccessor:StateChangedEvent");
- }
+IStorageAccessor::~IStorageAccessor() = default;
-private:
- void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
- state_changed_event->Signal();
+void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(state_changed_event);
+ IPC::ResponseBuilder rb{ctx, 4};
- LOG_WARNING(Service_AM, "(STUBBED) called");
- }
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(static_cast<u64>(backing.buffer.size()));
+}
- void GetResult(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
- LOG_WARNING(Service_AM, "(STUBBED) called");
- }
+ const u64 offset{rp.Pop<u64>()};
+ LOG_DEBUG(Service_AM, "called, offset={}", offset);
- void Start(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ const std::vector<u8> data{ctx.ReadBuffer()};
+
+ if (data.size() > backing.buffer.size() - offset) {
+ LOG_ERROR(Service_AM,
+ "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
+ backing.buffer.size(), data.size(), offset);
- LOG_WARNING(Service_AM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
}
- void PushInData(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
+ std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
- LOG_DEBUG(Service_AM, "called");
- }
+void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
- void PopOutData(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top()));
+ const u64 offset{rp.Pop<u64>()};
+ LOG_DEBUG(Service_AM, "called, offset={}", offset);
- storage_stack.pop();
+ const std::size_t size{ctx.GetWriteBufferSize()};
- LOG_DEBUG(Service_AM, "called");
+ 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);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
}
- std::stack<std::shared_ptr<AM::IStorage>> storage_stack;
- Kernel::SharedPtr<Kernel::Event> state_changed_event;
-};
+ ctx.WriteBuffer(backing.buffer.data() + offset, size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
static const FunctionInfo functions[] = {
@@ -632,7 +768,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
{1, nullptr, "TerminateAllLibraryApplets"},
{2, nullptr, "AreAnyLibraryAppletsLeft"},
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
- {11, nullptr, "CreateTransferMemoryStorage"},
+ {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
{12, nullptr, "CreateHandleStorage"},
};
RegisterHandlers(functions);
@@ -640,25 +776,81 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
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>();
+ default:
+ LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
+ static_cast<u32>(id));
+ return std::make_shared<Applets::StubApplet>();
+ }
+}
+
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_id = rp.PopRaw<AppletId>();
+ const auto applet_mode = rp.PopRaw<u32>();
+
+ LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
+ static_cast<u32>(applet_id), applet_mode);
+
+ const auto applet = GetAppletFromId(applet_id);
+
+ if (applet == nullptr) {
+ LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<AM::ILibraryAppletAccessor>();
-
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet);
}
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size{rp.Pop<u64>()};
+ LOG_DEBUG(Service_AM, "called, size={}", size);
+
std::vector<u8> buffer(size);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
+}
- LOG_DEBUG(Service_AM, "called, size={}", size);
+void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ IPC::RequestParser rp{ctx};
+
+ rp.SetCurrentOffset(3);
+ const auto handle{rp.Pop<Kernel::Handle>()};
+
+ const auto shared_mem =
+ Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>(
+ handle);
+
+ if (shared_mem == nullptr) {
+ LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ const u8* mem_begin = shared_mem->GetPointer();
+ const u8* mem_end = mem_begin + shared_mem->GetSize();
+ std::vector<u8> memory{mem_begin, mem_end};
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
}
IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
@@ -674,8 +866,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"},
@@ -690,7 +882,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
{70, nullptr, "RequestToShutdown"},
{71, nullptr, "RequestToReboot"},
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
- {90, nullptr, "EnableApplicationCrashReport"},
+ {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
{100, nullptr, "InitializeApplicationCopyrightFrameBuffer"},
{101, nullptr, "SetApplicationCopyrightImage"},
{102, nullptr, "SetApplicationCopyrightVisibility"},
@@ -709,33 +901,46 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
IApplicationFunctions::~IApplicationFunctions() = default;
+void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
LaunchParameters params{};
params.magic = POP_LAUNCH_PARAMETER_MAGIC;
@@ -743,7 +948,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
Account::ProfileManager profile_manager{};
const auto uuid = profile_manager.GetUser(Settings::values.current_user);
- ASSERT(uuid != std::nullopt);
+ ASSERT(uuid);
params.current_user = uuid->uuid;
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -754,21 +959,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
std::memcpy(buffer.data(), &params, buffer.size());
rb.PushIpcInterface<AM::IStorage>(buffer);
-
- LOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 uid = rp.PopRaw<u128>(); // What does this do?
-
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
IPC::ResponseBuilder rb{ctx, 4};
@@ -778,70 +981,119 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
- // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak.
+ // For example, in some cases official apps use this with error 0x2A2 then
+ // uses svcBreak.
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
+ LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
}
void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(1);
rb.Push<u64>(0);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(
static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
- LOG_DEBUG(Service_AM, "called");
}
void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
-
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
// Returns a 128-bit UUID
rb.Push<u64>(0);
rb.Push<u64>(0);
+}
- LOG_WARNING(Service_AM, "(STUBBED) called");
+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) {
- std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
- std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
+ auto message_queue = std::make_shared<AppletMessageQueue>();
+ message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
+ // game boot
+
+ std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
+ std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
std::make_shared<IdleSys>()->InstallAsService(service_manager);
std::make_shared<OMM>()->InstallAsService(service_manager);
std::make_shared<SPSM>()->InstallAsService(service_manager);
@@ -868,9 +1120,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_AM, "(STUBBED) called");
}
IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 095f94851..b6113cfdd 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -5,12 +5,10 @@
#pragma once
#include <memory>
+#include <queue>
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
-namespace Kernel {
-class Event;
-}
-
namespace Service {
namespace NVFlinger {
class NVFlinger;
@@ -39,6 +37,31 @@ enum SystemLanguage {
TraditionalChinese = 16,
};
+class AppletMessageQueue {
+public:
+ enum class AppletMessage : u32 {
+ NoMessage = 0,
+ FocusStateChanged = 15,
+ OperationModeChanged = 30,
+ PerformanceModeChanged = 31,
+ };
+
+ AppletMessageQueue();
+ ~AppletMessageQueue();
+
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
+ void PushMessage(AppletMessage msg);
+ AppletMessage PopMessage();
+ std::size_t GetMessageCount() const;
+ void OperationModeChanged();
+
+private:
+ std::queue<AppletMessage> messages;
+ Kernel::EventPair on_new_message;
+ Kernel::EventPair on_operation_mode_changed;
+};
+
class IWindowController final : public ServiceFramework<IWindowController> {
public:
IWindowController();
@@ -96,13 +119,13 @@ private:
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
- Kernel::SharedPtr<Kernel::Event> launchable_event;
+ Kernel::EventPair launchable_event;
u32 idle_time_detection_extension = 0;
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
- ICommonStateGetter();
+ explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
~ICommonStateGetter() override;
private:
@@ -125,7 +148,35 @@ private:
void GetBootMode(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
- Kernel::SharedPtr<Kernel::Event> event;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
+};
+
+class IStorage final : public ServiceFramework<IStorage> {
+public:
+ explicit IStorage(std::vector<u8> buffer);
+ ~IStorage() override;
+
+ const std::vector<u8>& GetData() const;
+
+private:
+ void Open(Kernel::HLERequestContext& ctx);
+
+ std::vector<u8> buffer;
+
+ friend class IStorageAccessor;
+};
+
+class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
+public:
+ explicit IStorageAccessor(IStorage& backing);
+ ~IStorageAccessor() override;
+
+private:
+ void GetSize(Kernel::HLERequestContext& ctx);
+ void Write(Kernel::HLERequestContext& ctx);
+ void Read(Kernel::HLERequestContext& ctx);
+
+ IStorage& backing;
};
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
@@ -136,6 +187,7 @@ public:
private:
void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
void CreateStorage(Kernel::HLERequestContext& ctx);
+ void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -154,10 +206,13 @@ 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);
void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
+ void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
};
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 68ea778e8..41a573a91 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
- explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) {
+ explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
@@ -30,75 +32,87 @@ public:
private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IProcessWindingController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
- LOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
- explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) {
+ explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
@@ -117,100 +131,116 @@ public:
private:
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetAudioController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
- LOG_DEBUG(Service_AM, "called");
}
void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IHomeMenuFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGlobalStateController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationCreator>();
- LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISystemAppletProxy>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
}
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
}
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
}
-AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
+AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
@@ -228,4 +258,8 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
AppletAE::~AppletAE() = default;
+const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
+ return msg_queue;
+}
+
} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 1ed77baa4..902db2665 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -17,15 +17,19 @@ namespace AM {
class AppletAE final : public ServiceFramework<AppletAE> {
public:
- explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletAE() override;
+ const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
+
private:
void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 60717afd9..d3a0a1568 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -12,8 +12,10 @@ namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
- explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
+ explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -33,73 +35,85 @@ public:
private:
void GetAudioController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
- LOG_DEBUG(Service_AM, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ICommonStateGetter>();
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
- LOG_DEBUG(Service_AM, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
- LOG_DEBUG(Service_AM, "called");
}
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<IApplicationProxy>(nvflinger);
- LOG_DEBUG(Service_AM, "called");
+ rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
}
-AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
- : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) {
+AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue)
+ : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
+ msg_queue(std::move(msg_queue)) {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
@@ -108,4 +122,8 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
AppletOE::~AppletOE() = default;
+const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
+ return msg_queue;
+}
+
} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 60cfdfd9d..bbd0108ef 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -17,13 +17,17 @@ namespace AM {
class AppletOE final : public ServiceFramework<AppletOE> {
public:
- explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
+ explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
+ std::shared_ptr<AppletMessageQueue> msg_queue);
~AppletOE() override;
+ const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
+
private:
void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
+ std::shared_ptr<AppletMessageQueue> msg_queue;
};
} // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
new file mode 100644
index 000000000..a6064c63f
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -0,0 +1,114 @@
+// 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 "core/core.h"
+#include "core/hle/kernel/readable_event.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"
+
+namespace Service::AM::Applets {
+
+AppletDataBroker::AppletDataBroker() {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ state_changed_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent");
+ pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent");
+ pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
+}
+
+AppletDataBroker::~AppletDataBroker() = default;
+
+std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
+ if (out_channel.empty())
+ return nullptr;
+
+ auto out = std::move(out_channel.front());
+ out_channel.pop();
+ return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
+ if (in_channel.empty())
+ return nullptr;
+
+ auto out = std::move(in_channel.front());
+ in_channel.pop();
+ return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
+ if (out_interactive_channel.empty())
+ return nullptr;
+
+ auto out = std::move(out_interactive_channel.front());
+ out_interactive_channel.pop();
+ return out;
+}
+
+std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
+ if (in_interactive_channel.empty())
+ return nullptr;
+
+ auto out = std::move(in_interactive_channel.front());
+ in_interactive_channel.pop();
+ return out;
+}
+
+void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
+ in_channel.push(std::make_unique<IStorage>(storage));
+}
+
+void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
+ out_channel.push(std::make_unique<IStorage>(storage));
+ pop_out_data_event.writable->Signal();
+}
+
+void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
+ in_interactive_channel.push(std::make_unique<IStorage>(storage));
+}
+
+void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
+ out_interactive_channel.push(std::make_unique<IStorage>(storage));
+ pop_interactive_out_data_event.writable->Signal();
+}
+
+void AppletDataBroker::SignalStateChanged() const {
+ state_changed_event.writable->Signal();
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
+ return pop_out_data_event.readable;
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
+ return pop_interactive_out_data_event.readable;
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
+ return state_changed_event.readable;
+}
+
+Applet::Applet() = default;
+
+Applet::~Applet() = default;
+
+void Applet::Initialize() {
+ const auto common = broker.PopNormalDataToApplet();
+ ASSERT(common != nullptr);
+
+ const auto common_data = common->GetData();
+
+ ASSERT(common_data.size() >= sizeof(CommonArguments));
+ std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
+
+ initialized = true;
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
new file mode 100644
index 000000000..37424c379
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.h
@@ -0,0 +1,109 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include "common/swap.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/writable_event.h"
+
+union ResultCode;
+
+namespace Service::AM {
+
+class IStorage;
+
+namespace Applets {
+
+class AppletDataBroker final {
+public:
+ AppletDataBroker();
+ ~AppletDataBroker();
+
+ std::unique_ptr<IStorage> PopNormalDataToGame();
+ std::unique_ptr<IStorage> PopNormalDataToApplet();
+
+ std::unique_ptr<IStorage> PopInteractiveDataToGame();
+ std::unique_ptr<IStorage> PopInteractiveDataToApplet();
+
+ void PushNormalDataFromGame(IStorage storage);
+ void PushNormalDataFromApplet(IStorage storage);
+
+ void PushInteractiveDataFromGame(IStorage storage);
+ void PushInteractiveDataFromApplet(IStorage storage);
+
+ void SignalStateChanged() const;
+
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
+
+private:
+ // Queues are named from applet's perspective
+
+ // PopNormalDataToApplet and PushNormalDataFromGame
+ std::queue<std::unique_ptr<IStorage>> in_channel;
+
+ // PopNormalDataToGame and PushNormalDataFromApplet
+ std::queue<std::unique_ptr<IStorage>> out_channel;
+
+ // PopInteractiveDataToApplet and PushInteractiveDataFromGame
+ std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
+
+ // PopInteractiveDataToGame and PushInteractiveDataFromApplet
+ std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
+
+ Kernel::EventPair state_changed_event;
+
+ // Signaled on PushNormalDataFromApplet
+ Kernel::EventPair pop_out_data_event;
+
+ // Signaled on PushInteractiveDataFromApplet
+ Kernel::EventPair pop_interactive_out_data_event;
+};
+
+class Applet {
+public:
+ Applet();
+ virtual ~Applet();
+
+ virtual void Initialize();
+
+ virtual bool TransactionComplete() const = 0;
+ virtual ResultCode GetStatus() const = 0;
+ virtual void ExecuteInteractive() = 0;
+ virtual void Execute() = 0;
+
+ bool IsInitialized() const {
+ return initialized;
+ }
+
+ AppletDataBroker& GetBroker() {
+ return broker;
+ }
+
+ const AppletDataBroker& GetBroker() const {
+ return broker;
+ }
+
+protected:
+ struct CommonArguments {
+ u32_le arguments_version;
+ u32_le size;
+ u32_le library_version;
+ u32_le theme_color;
+ u8 play_startup_sound;
+ u64_le system_tick;
+ };
+ static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
+
+ CommonArguments common_args{};
+ AppletDataBroker broker;
+ bool initialized = false;
+};
+
+} // namespace Applets
+} // namespace Service::AM
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..4c7b45454
--- /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/software_keyboard.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
new file mode 100644
index 000000000..f255f74b5
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -0,0 +1,160 @@
+// 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/software_keyboard.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/software_keyboard.h"
+
+namespace Service::AM::Applets {
+
+constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
+constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
+constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
+constexpr bool INTERACTIVE_STATUS_OK = false;
+
+static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
+ KeyboardConfig config, std::u16string initial_text) {
+ Core::Frontend::SoftwareKeyboardParameters params{};
+
+ params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ config.submit_text.data(), config.submit_text.size());
+ params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
+ config.header_text.data(), config.header_text.size());
+ params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
+ config.sub_text.size());
+ params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
+ config.guide_text.size());
+ params.initial_text = initial_text;
+ params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
+ params.password = static_cast<bool>(config.is_password);
+ params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
+ params.value = static_cast<u8>(config.keyset_disable_bitmask);
+
+ return params;
+}
+
+SoftwareKeyboard::SoftwareKeyboard() = default;
+
+SoftwareKeyboard::~SoftwareKeyboard() = default;
+
+void SoftwareKeyboard::Initialize() {
+ complete = false;
+ initial_text.clear();
+ final_data.clear();
+
+ Applet::Initialize();
+
+ const auto keyboard_config_storage = broker.PopNormalDataToApplet();
+ ASSERT(keyboard_config_storage != nullptr);
+ const auto& keyboard_config = keyboard_config_storage->GetData();
+
+ ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
+ std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
+
+ const auto work_buffer_storage = broker.PopNormalDataToApplet();
+ ASSERT(work_buffer_storage != nullptr);
+ const auto& work_buffer = work_buffer_storage->GetData();
+
+ if (config.initial_string_size == 0)
+ return;
+
+ std::vector<char16_t> string(config.initial_string_size);
+ std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset,
+ string.size() * 2);
+ initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
+}
+
+bool SoftwareKeyboard::TransactionComplete() const {
+ return complete;
+}
+
+ResultCode SoftwareKeyboard::GetStatus() const {
+ return RESULT_SUCCESS;
+}
+
+void SoftwareKeyboard::ExecuteInteractive() {
+ if (complete)
+ return;
+
+ const auto storage = broker.PopInteractiveDataToApplet();
+ ASSERT(storage != nullptr);
+ const auto data = storage->GetData();
+ const auto status = static_cast<bool>(data[0]);
+
+ if (status == INTERACTIVE_STATUS_OK) {
+ complete = true;
+ } else {
+ const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
+
+ std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
+ std::memcpy(string.data(), data.data() + 4, string.size() * 2);
+ frontend.SendTextCheckDialog(
+ Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
+ [this] { broker.SignalStateChanged(); });
+ }
+}
+
+void SoftwareKeyboard::Execute() {
+ if (complete) {
+ broker.PushNormalDataFromApplet(IStorage{final_data});
+ return;
+ }
+
+ const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
+
+ const auto parameters = ConvertToFrontendParameters(config, initial_text);
+
+ frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
+ parameters);
+}
+
+void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
+ std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE);
+
+ if (text.has_value()) {
+ std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
+
+ if (config.utf_8) {
+ const u64 size = text->size() + 8;
+ const auto new_text = Common::UTF16ToUTF8(*text);
+
+ std::memcpy(output_sub.data(), &size, sizeof(u64));
+ std::memcpy(output_sub.data() + 8, new_text.data(),
+ std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8));
+
+ output_main[0] = INTERACTIVE_STATUS_OK;
+ std::memcpy(output_main.data() + 4, new_text.data(),
+ std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
+ } else {
+ const u64 size = text->size() * 2 + 8;
+ std::memcpy(output_sub.data(), &size, sizeof(u64));
+ std::memcpy(output_sub.data() + 8, text->data(),
+ std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
+
+ output_main[0] = INTERACTIVE_STATUS_OK;
+ std::memcpy(output_main.data() + 4, text->data(),
+ std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
+ }
+
+ complete = !config.text_check;
+ final_data = output_main;
+
+ if (complete) {
+ broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.SignalStateChanged();
+ } else {
+ broker.PushInteractiveDataFromApplet(IStorage{output_sub});
+ }
+ } else {
+ output_main[0] = 1;
+ complete = true;
+ broker.PushNormalDataFromApplet(IStorage{output_main});
+ broker.SignalStateChanged();
+ }
+}
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
new file mode 100644
index 000000000..efd5753a1
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -0,0 +1,74 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <string>
+#include <vector>
+
+#include "common/common_funcs.h"
+#include "common/swap.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/applets.h"
+
+namespace Service::AM::Applets {
+
+enum class KeysetDisable : u32 {
+ Space = 0x02,
+ Address = 0x04,
+ Percent = 0x08,
+ Slashes = 0x10,
+ Numbers = 0x40,
+ DownloadCode = 0x80,
+};
+
+struct KeyboardConfig {
+ INSERT_PADDING_BYTES(4);
+ std::array<char16_t, 9> submit_text;
+ u16_le left_symbol_key;
+ u16_le right_symbol_key;
+ INSERT_PADDING_BYTES(1);
+ KeysetDisable keyset_disable_bitmask;
+ u32_le initial_cursor_position;
+ std::array<char16_t, 65> header_text;
+ std::array<char16_t, 129> sub_text;
+ std::array<char16_t, 257> guide_text;
+ u32_le length_limit;
+ INSERT_PADDING_BYTES(4);
+ u32_le is_password;
+ INSERT_PADDING_BYTES(5);
+ bool utf_8;
+ bool draw_background;
+ u32_le initial_string_offset;
+ u32_le initial_string_size;
+ u32_le user_dictionary_offset;
+ u32_le user_dictionary_size;
+ bool text_check;
+ u64_le text_check_callback;
+};
+static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
+
+class SoftwareKeyboard final : public Applet {
+public:
+ SoftwareKeyboard();
+ ~SoftwareKeyboard() override;
+
+ void Initialize() override;
+
+ bool TransactionComplete() const override;
+ ResultCode GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+
+ void WriteText(std::optional<std::u16string> text);
+
+private:
+ KeyboardConfig config;
+ std::u16string initial_text;
+ bool complete = false;
+ std::vector<u8> final_data;
+};
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/stub_applet.cpp
new file mode 100644
index 000000000..ed166b87d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.cpp
@@ -0,0 +1,70 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <string>
+
+#include "common/hex_util.h"
+#include "common/logging/log.h"
+#include "core/hle/result.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/stub_applet.h"
+
+namespace Service::AM::Applets {
+
+static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
+ std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
+ for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
+ const auto data = storage->GetData();
+ LOG_INFO(Service_AM,
+ "called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
+ prefix, data.size(), Common::HexVectorToString(data));
+ }
+
+ storage = broker.PopInteractiveDataToApplet();
+ for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
+ const auto data = storage->GetData();
+ LOG_INFO(Service_AM,
+ "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
+ prefix, data.size(), Common::HexVectorToString(data));
+ }
+}
+
+StubApplet::StubApplet() = default;
+
+StubApplet::~StubApplet() = default;
+
+void StubApplet::Initialize() {
+ LOG_WARNING(Service_AM, "called (STUBBED)");
+ Applet::Initialize();
+ LogCurrentStorage(broker, "Initialize");
+}
+
+bool StubApplet::TransactionComplete() const {
+ LOG_WARNING(Service_AM, "called (STUBBED)");
+ return true;
+}
+
+ResultCode StubApplet::GetStatus() const {
+ LOG_WARNING(Service_AM, "called (STUBBED)");
+ return RESULT_SUCCESS;
+}
+
+void StubApplet::ExecuteInteractive() {
+ LOG_WARNING(Service_AM, "called (STUBBED)");
+ LogCurrentStorage(broker, "ExecuteInteractive");
+
+ broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.SignalStateChanged();
+}
+
+void StubApplet::Execute() {
+ LOG_WARNING(Service_AM, "called (STUBBED)");
+ LogCurrentStorage(broker, "Execute");
+
+ broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
+ broker.SignalStateChanged();
+}
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h
new file mode 100644
index 000000000..7d8dc968d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.h
@@ -0,0 +1,24 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/am/applets/applets.h"
+
+namespace Service::AM::Applets {
+
+class StubApplet final : public Applet {
+public:
+ StubApplet();
+ ~StubApplet() override;
+
+ void Initialize() override;
+
+ bool TransactionComplete() const override;
+ ResultCode GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+};
+
+} // 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 54305cf05..b506bc3dd 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -13,11 +13,14 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#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 {
@@ -32,14 +35,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
std::vector<u64> add_on_content;
const auto rcu = FileSystem::GetUnionContents();
const auto list =
- rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
+ rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
[&rcu](u64 tid) {
- return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
+ return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
Loader::ResultStatus::Success;
}),
add_on_content.end());
@@ -61,17 +64,26 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
- "GetAddOnContentListChanged:Event");
+ aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "GetAddOnContentListChanged:Event");
}
AOC_U::~AOC_U() = default;
void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AOC, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
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); })));
@@ -82,6 +94,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
const auto offset = rp.PopRaw<u32>();
auto count = rp.PopRaw<u32>();
+ LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
@@ -91,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.
@@ -110,6 +127,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
}
void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AOC, "called");
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
@@ -128,7 +147,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto aoc_id = rp.PopRaw<u32>();
-
LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
IPC::ResponseBuilder rb{ctx, 2};
@@ -140,7 +158,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(aoc_change_event);
+ rb.PushCopyObjects(aoc_change_event.readable);
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 68d94fdaa..5effea730 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,6 +6,10 @@
#include "core/hle/service/service.h"
+namespace Kernel {
+class WritableEvent;
+}
+
namespace Service::AOC {
class AOC_U final : public ServiceFramework<AOC_U> {
@@ -21,7 +25,7 @@ private:
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
std::vector<u64> add_on_content;
- Kernel::SharedPtr<Kernel::Event> aoc_change_event;
+ Kernel::EventPair aoc_change_event;
};
/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index c22bd3859..fcacbab72 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -40,24 +40,22 @@ private:
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
u32 config = rp.Pop<u32>();
+ LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
+ config);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
- config);
}
void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
+ LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
-
- LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
}
};
@@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
APM::~APM() = default;
void APM::OpenSession(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_APM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
-
- LOG_DEBUG(Service_APM, "called");
}
APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
@@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
APM_Sys::~APM_Sys() = default;
void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_APM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISession>();
-
- LOG_DEBUG(Service_APM, "called");
}
} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
index 358ef2576..e675b0188 100644
--- a/src/core/hle/service/arp/arp.cpp
+++ b/src/core/hle/service/arp/arp.cpp
@@ -59,11 +59,11 @@ public:
private:
void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_ARP, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRegistrar>();
-
- LOG_DEBUG(Service_ARP, "called");
}
};
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index ff1edefbb..dc6a6b188 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -13,8 +13,10 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/audio/audout_u.h"
#include "core/memory.h"
@@ -44,8 +46,10 @@ enum class AudioState : u32 {
class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
- IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core)
- : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) {
+ IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
+ std::string&& unique_name)
+ : ServiceFramework("IAudioOut"), audio_core(audio_core),
+ device_name(std::move(device_name)), audio_params(audio_params) {
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -65,11 +69,12 @@ public:
// This is the event handle used to check if the audio buffer was released
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
+ buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "IAudioOutBufferReleased");
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
- "IAudioOut", [=]() { buffer_event->Signal(); });
+ std::move(unique_name),
+ [=]() { buffer_event.writable->Signal(); });
}
private:
@@ -84,6 +89,7 @@ private:
void GetAudioOutState(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
@@ -118,7 +124,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event);
+ rb.PushCopyObjects(buffer_event.readable);
}
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -146,6 +152,7 @@ private:
void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
+
IPC::RequestParser rp{ctx};
const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
@@ -161,6 +168,7 @@ private:
void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
+
IPC::RequestParser rp{ctx};
const u64 tag{rp.Pop<u64>()};
IPC::ResponseBuilder rb{ctx, 3};
@@ -170,6 +178,7 @@ private:
void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u32>(stream->GetQueueSize()));
@@ -177,15 +186,17 @@ private:
AudioCore::AudioOut& audio_core;
AudioCore::StreamPtr stream;
+ std::string device_name;
AudoutParams audio_params{};
- /// This is the evend handle used to check if the audio buffer was released
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ /// This is the event handle used to check if the audio buffer was released
+ Kernel::EventPair buffer_event;
};
void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
+
IPC::RequestParser rp{ctx};
ctx.WriteBuffer(DefaultDevice);
@@ -199,7 +210,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
- ctx.WriteBuffer(DefaultDevice);
+ const auto device_name_data{ctx.ReadBuffer()};
+ std::string device_name;
+ if (device_name_data[0] != '\0') {
+ device_name.assign(device_name_data.begin(), device_name_data.end());
+ } else {
+ device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
+ }
+ ctx.WriteBuffer(device_name);
+
IPC::RequestParser rp{ctx};
auto params{rp.PopRaw<AudoutParams>()};
if (params.channel_count <= 2) {
@@ -212,10 +231,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
params.sample_rate = DefaultSampleRate;
}
- // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl
- // will likely need to be updated as well.
- ASSERT_MSG(!audio_out_interface, "Unimplemented");
- audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
+ std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
+ auto audio_out_interface = std::make_shared<IAudioOut>(
+ params, *audio_core, std::move(device_name), std::move(unique_name));
IPC::ResponseBuilder rb{ctx, 6, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -224,6 +242,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
+
+ audio_out_interfaces.push_back(std::move(audio_out_interface));
}
AudOutU::AudOutU() : ServiceFramework("audout:u") {
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index dcaf64708..aed4c43b2 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,6 +4,7 @@
#pragma once
+#include <vector>
#include "core/hle/service/service.h"
namespace AudioCore {
@@ -24,7 +25,7 @@ public:
~AudOutU() override;
private:
- std::shared_ptr<IAudioOut> audio_out_interface;
+ std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
std::unique_ptr<AudioCore::AudioOut> audio_core;
void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fac6785a5..945259c7d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -12,8 +12,10 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/audio/audren_u.h"
namespace Service::Audio {
@@ -28,90 +30,116 @@ public:
{1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
{2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
{3, &IAudioRenderer::GetState, "GetState"},
- {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"},
+ {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"},
{5, &IAudioRenderer::Start, "Start"},
{6, &IAudioRenderer::Stop, "Stop"},
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
- {8, nullptr, "SetRenderingTimeLimit"},
- {9, nullptr, "GetRenderingTimeLimit"},
- {10, nullptr, "RequestUpdateAuto"},
+ {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
+ {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
+ {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
{11, nullptr, "ExecuteAudioRendererRendering"},
};
// clang-format on
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- system_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
- renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
+ system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "IAudioRenderer:SystemEvent");
+ renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
}
private:
void UpdateAudioCallback() {
- system_event->Signal();
+ system_event.writable->Signal();
}
void GetSampleRate(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(renderer->GetSampleRate());
- LOG_DEBUG(Service_Audio, "called");
}
void GetSampleCount(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(renderer->GetSampleCount());
- LOG_DEBUG(Service_Audio, "called");
}
void GetState(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
- LOG_DEBUG(Service_Audio, "called");
}
void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(renderer->GetMixBufferCount());
- LOG_DEBUG(Service_Audio, "called");
}
- void RequestUpdate(Kernel::HLERequestContext& ctx) {
+ void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void Start(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void Stop(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_WARNING(Service_Audio, "(STUBBED) called");
}
void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(system_event);
+ rb.PushCopyObjects(system_event.readable);
+ }
- LOG_WARNING(Service_Audio, "(STUBBED) called");
+ void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rendering_time_limit_percent = rp.Pop<u32>();
+ LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
+ rendering_time_limit_percent);
+
+ ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
}
- Kernel::SharedPtr<Kernel::Event> system_event;
+ void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(rendering_time_limit_percent);
+ }
+
+ Kernel::EventPair system_event;
std::unique_ptr<AudioCore::AudioRenderer> renderer;
+ u32 rendering_time_limit_percent = 100;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -136,8 +164,8 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IAudioOutBufferReleasedEvent");
+ buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IAudioOutBufferReleasedEvent");
}
private:
@@ -181,21 +209,22 @@ private:
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- buffer_event->Signal();
+ buffer_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event);
+ rb.PushCopyObjects(buffer_event.readable);
}
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1);
}
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ Kernel::EventPair buffer_event;
}; // namespace Audio
@@ -214,19 +243,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
AudRenU::~AudRenU() = default;
void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::RequestParser rp{ctx};
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
-
- LOG_DEBUG(Service_Audio, "called");
}
void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
+ LOG_DEBUG(Service_Audio, "called");
u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
buffer_sz += params.unknown_c * 1024;
@@ -280,26 +310,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(output_sz);
- LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz);
+ LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
}
void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Audio, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<Audio::IAudioDevice>();
-
- LOG_DEBUG(Service_Audio, "called");
}
void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Audio::IAudioDevice>();
-
- LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
- // based on the current revision
+ rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
+ // based on the current revision
}
bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 7168c6a10..a850cadc8 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -46,10 +46,13 @@ public:
private:
void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Audio, "called");
+
u32 consumed = 0;
u32 sample_count = 0;
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
+ LOG_ERROR(Audio, "Failed to decode opus data");
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultCode(-1));
@@ -63,12 +66,15 @@ private:
}
void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Audio, "called");
+
u32 consumed = 0;
u32 sample_count = 0;
u64 performance = 0;
std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
performance)) {
+ LOG_ERROR(Audio, "Failed to decode opus data");
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultCode(-1));
@@ -77,8 +83,8 @@ private:
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(consumed);
- rb.Push<u64>(performance);
rb.Push<u32>(sample_count);
+ rb.Push<u64>(performance);
ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
}
@@ -88,24 +94,39 @@ private:
std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
const auto start_time = std::chrono::high_resolution_clock::now();
std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
- if (sizeof(OpusHeader) > input.size())
+ if (sizeof(OpusHeader) > input.size()) {
+ LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
+ sizeof(OpusHeader), input.size());
return false;
+ }
OpusHeader hdr{};
std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
+ LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}",
+ sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
return false;
}
auto frame = input.data() + sizeof(OpusHeader);
auto decoded_sample_count = opus_packet_get_nb_samples(
frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
static_cast<opus_int32>(sample_rate));
- if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz)
+ if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
+ LOG_ERROR(
+ Audio,
+ "Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}",
+ decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
return false;
+ }
+ const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
auto out_sample_count =
- opus_decode(decoder.get(), frame, hdr.sz, output.data(),
- (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
- if (out_sample_count < 0)
+ opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
+ if (out_sample_count < 0) {
+ LOG_ERROR(Audio,
+ "Incorrect sample count received from opus_decode, "
+ "output_sample_count={}, frame_size={}, data_sz_from_hdr={}",
+ out_sample_count, frame_size, static_cast<u32>(hdr.sz));
return false;
+ }
const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
sample_count = out_sample_count;
consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
@@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) {
void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto sample_rate = rp.Pop<u32>();
- auto channel_count = rp.Pop<u32>();
+ const auto sample_rate = rp.Pop<u32>();
+ const auto channel_count = rp.Pop<u32>();
+ LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
+
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
sample_rate == 12000 || sample_rate == 8000,
"Invalid sample rate");
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
- u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
- LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz);
+
+ const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
+ LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
@@ -155,16 +179,18 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
auto buffer_sz = rp.Pop<u32>();
LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
channel_count, buffer_sz);
+
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
sample_rate == 12000 || sample_rate == 8000,
"Invalid sample rate");
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
std::size_t worker_sz = WorkerBufferSize(channel_count);
- ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
+ ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
static_cast<OpusDecoder*>(operator new(worker_sz))};
- if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
+ if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
+ LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultCode(-1));
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 6e7b795fb..b7bd738fc 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -33,10 +33,11 @@ public:
};
void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BCAT, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IBcatService>();
- LOG_DEBUG(Service_BCAT, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index d0a15cc4c..5704ca0ab 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -2,12 +2,54 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/btdrv/btdrv.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
namespace Service::BtDrv {
+class Bt final : public ServiceFramework<Bt> {
+public:
+ explicit Bt() : ServiceFramework{"bt"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "Unknown0"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ {9, &Bt::RegisterEvent, "RegisterEvent"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "BT:RegisterEvent");
+ }
+
+private:
+ void RegisterEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(register_event.readable);
+ }
+
+ Kernel::EventPair register_event;
+};
+
class BtDrv final : public ServiceFramework<BtDrv> {
public:
explicit BtDrv() : ServiceFramework{"btdrv"} {
@@ -67,6 +109,7 @@ public:
void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<BtDrv>()->InstallAsService(sm);
+ std::make_shared<Bt>()->InstallAsService(sm);
}
} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index b949bfabd..ef7398a23 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -7,12 +7,126 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/btm/btm.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::BTM {
+class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
+public:
+ explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IBtmUserCore::GetScanEvent, "GetScanEvent"},
+ {1, nullptr, "Unknown1"},
+ {2, nullptr, "Unknown2"},
+ {3, nullptr, "Unknown3"},
+ {4, nullptr, "Unknown4"},
+ {5, nullptr, "Unknown5"},
+ {6, nullptr, "Unknown6"},
+ {7, nullptr, "Unknown7"},
+ {8, nullptr, "Unknown8"},
+ {9, nullptr, "Unknown9"},
+ {10, nullptr, "Unknown10"},
+ {17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"},
+ {18, nullptr, "Unknown18"},
+ {19, nullptr, "Unknown19"},
+ {20, nullptr, "Unknown20"},
+ {21, nullptr, "Unknown21"},
+ {22, nullptr, "Unknown22"},
+ {23, nullptr, "Unknown23"},
+ {24, nullptr, "Unknown24"},
+ {25, nullptr, "Unknown25"},
+ {26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"},
+ {27, nullptr, "Unknown27"},
+ {28, nullptr, "Unknown28"},
+ {29, nullptr, "Unknown29"},
+ {30, nullptr, "Unknown30"},
+ {31, nullptr, "Unknown31"},
+ {32, nullptr, "Unknown32"},
+ {33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"},
+ {34, nullptr, "Unknown34"},
+ {35, nullptr, "Unknown35"},
+ {36, nullptr, "Unknown36"},
+ {37, nullptr, "Unknown37"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IBtmUserCore:ScanEvent");
+ connection_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
+ service_discovery = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
+ config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IBtmUserCore:ConfigEvent");
+ }
+
+private:
+ void GetScanEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(scan_event.readable);
+ }
+
+ void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(connection_event.readable);
+ }
+
+ void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(service_discovery.readable);
+ }
+
+ void GetConfigEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(config_event.readable);
+ }
+
+ Kernel::EventPair scan_event;
+ Kernel::EventPair connection_event;
+ Kernel::EventPair service_discovery;
+ Kernel::EventPair config_event;
+};
+
+class BTM_USR final : public ServiceFramework<BTM_USR> {
+public:
+ explicit BTM_USR() : ServiceFramework{"btm:u"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &BTM_USR::GetCoreImpl, "GetCoreImpl"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+ }
+
+private:
+ void GetCoreImpl(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BTM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<IBtmUserCore>();
+ }
+};
+
class BTM final : public ServiceFramework<BTM> {
public:
explicit BTM() : ServiceFramework{"btm"} {
@@ -104,11 +218,11 @@ public:
private:
void GetCoreImpl(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BTM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IBtmSystemCore>();
-
- LOG_DEBUG(Service_BTM, "called");
}
};
@@ -116,6 +230,7 @@ void InstallInterfaces(SM::ServiceManager& sm) {
std::make_shared<BTM>()->InstallAsService(sm);
std::make_shared<BTM_DBG>()->InstallAsService(sm);
std::make_shared<BTM_SYS>()->InstallAsService(sm);
+ std::make_shared<BTM_USR>()->InstallAsService(sm);
}
} // namespace Service::BTM
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index ee11cd78e..d9b32954e 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -17,11 +17,13 @@ public:
static const FunctionInfo functions[] = {
{0, nullptr, "SubmitContext"},
{1, nullptr, "CreateReport"},
- {2, nullptr, "Unknown1"},
- {3, nullptr, "Unknown2"},
- {4, nullptr, "Unknown3"},
- {5, nullptr, "Unknown4"},
- {6, nullptr, "Unknown5"},
+ {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
+ {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
+ {4, nullptr, "UpdatePowerOnTime"},
+ {5, nullptr, "UpdateAwakeTime"},
+ {6, nullptr, "SubmitMultipleCategoryContext"},
+ {7, nullptr, "UpdateApplicationLaunchTime"},
+ {8, nullptr, "ClearApplicationLaunchTime"},
};
// clang-format on
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/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index 566fbf924..e461274c1 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -42,11 +42,11 @@ public:
private:
void Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FGM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRequest>();
-
- LOG_DEBUG(Service_FGM, "called");
}
};
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e32a7c48e..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_));
@@ -113,6 +122,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
return RESULT_SUCCESS;
}
+ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
+ const std::string sanitized_path(FileUtil::SanitizePath(path));
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
+
+ if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+
+ return RESULT_SUCCESS;
+}
+
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
const std::string& dest_path_) const {
std::string src_path(FileUtil::SanitizePath(src_path_));
@@ -303,25 +324,73 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
static_cast<u8>(space), save_struct.DebugInfo());
if (save_data_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
}
return save_data_factory->Open(space, save_struct);
}
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+ LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
+
+ if (save_data_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
+}
+
ResultVal<FileSys::VirtualDir> OpenSDMC() {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
- return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound);
+ return FileSys::ERROR_SD_CARD_NOT_FOUND;
}
return sdmc_factory->Open();
}
-std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
- return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
- GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
+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()}};
}
FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -360,6 +429,15 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
return bis_factory->GetModificationLoadRoot(title_id);
}
+FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
+ LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetModificationDumpRoot(title_id);
+}
+
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
@@ -373,13 +451,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
FileSys::Mode::ReadWrite);
auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
FileSys::Mode::ReadWrite);
+ auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
+ FileSys::Mode::ReadWrite);
- if (bis_factory == nullptr)
- bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory);
- if (save_data_factory == nullptr)
+ if (bis_factory == nullptr) {
+ bis_factory =
+ std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
+ }
+
+ if (save_data_factory == nullptr) {
save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
- if (sdmc_factory == nullptr)
+ }
+
+ if (sdmc_factory == nullptr) {
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
+ }
}
void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6ca5c5636..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 {
@@ -45,15 +47,21 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
FileSys::ContentRecordType type);
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
FileSys::SaveDataDescriptor save_struct);
+ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
-std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
+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();
FileSys::RegisteredCache* GetUserNANDContents();
FileSys::RegisteredCache* GetSDMCContents();
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
+FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
// above is called.
@@ -111,6 +119,18 @@ public:
ResultCode DeleteDirectoryRecursively(const std::string& path) const;
/**
+ * Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
+ * in that it deletes all the contents of the specified directory, however, this
+ * function does *not* delete the directory itself. It only deletes everything
+ * within it.
+ *
+ * @param path Path relative to the archive.
+ *
+ * @return Result of the operation.
+ */
+ ResultCode CleanDirectoryRecursively(const std::string& path) const;
+
+ /**
* Rename a File specified by its path
* @param src_path Source path relative to the archive
* @param dest_path Destination path relative to the archive
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index c1c83a11d..74c4e583b 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -11,6 +11,7 @@
#include "common/assert.h"
#include "common/common_types.h"
+#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/file_sys/directory.h"
@@ -19,6 +20,7 @@
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
@@ -43,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);
}
@@ -61,13 +67,15 @@ private:
// Error checking
if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -79,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> {
@@ -106,13 +123,15 @@ private:
// Error checking
if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -137,13 +156,15 @@ private:
// Error checking
if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength));
+ rb.Push(FileSys::ERROR_INVALID_SIZE);
return;
}
if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset));
+ rb.Push(FileSys::ERROR_INVALID_OFFSET);
return;
}
@@ -179,9 +200,10 @@ private:
void SetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
- backend->Resize(size);
LOG_DEBUG(Service_FS, "called, size={}", size);
+ backend->Resize(size);
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -283,7 +305,7 @@ public:
{10, &IFileSystem::Commit, "Commit"},
{11, nullptr, "GetFreeSpaceSize"},
{12, nullptr, "GetTotalSpaceSize"},
- {13, nullptr, "CleanDirectoryRecursively"},
+ {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
{14, nullptr, "GetFileTimeStampRaw"},
{15, nullptr, "QueryEntry"},
};
@@ -353,6 +375,16 @@ public:
rb.Push(backend.DeleteDirectoryRecursively(name));
}
+ void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. Directory: {}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.CleanDirectoryRecursively(name));
+ }
+
void RenameFile(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -451,7 +483,149 @@ private:
VfsDirectoryServiceWrapper backend;
};
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
+ : ServiceFramework("ISaveDataInfoReader") {
+ static const FunctionInfo functions[] = {
+ {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+ }
+
+ void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ ctx.WriteBuffer(begin, range_size);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(actual_entries));
+ }
+
+private:
+ static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16)
+ return 0;
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+ }
+
+ void FindAllSaves(FileSys::SaveDataSpaceId space) {
+ const auto save_root = OpenSaveDataSpace(space);
+ ASSERT(save_root.Succeeded());
+
+ for (const auto& type : (*save_root)->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::SystemSaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device =
+ std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::DeviceSaveData
+ : FileSys::SaveDataType::SaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
+ // Temporary Storage
+ for (const auto& user_id : type->GetSubdirectories()) {
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() ||
+ !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric =
+ Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::TemporaryStorage,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ INSERT_PADDING_BYTES(0x28);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
+ // clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "MountContent"},
{1, &FSP_SRV::Initialize, "Initialize"},
@@ -485,7 +659,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
- {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
{62, nullptr, "OpenCacheStorageList"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
@@ -544,6 +718,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
{1009, nullptr, "GetAndClearMemoryReportInfo"},
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
};
+ // clang-format on
RegisterHandlers(functions);
}
@@ -561,6 +736,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
const auto type = rp.PopRaw<FileSystemType>();
const auto title_id = rp.PopRaw<u64>();
+ LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}",
+ static_cast<u8>(type), title_id);
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(ResultCode(-1));
@@ -596,13 +773,14 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
auto unk = rp.Pop<u32>();
LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
+
auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
auto dir = OpenSaveData(space_id, save_struct);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
+ rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
}
@@ -618,12 +796,31 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
MountSaveData(ctx);
}
+void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+ LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space));
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
+}
+
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) {
@@ -657,6 +854,15 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
+ const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
+
+ if (archive != nullptr) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface(std::make_shared<IStorage>(archive));
+ return;
+ }
+
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
"could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
@@ -685,7 +891,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
static_cast<u8>(storage_id), title_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound));
+ rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4aa0358cb..e7abec0a3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -25,6 +25,7 @@ private:
void CreateSaveData(Kernel::HLERequestContext& ctx);
void MountSaveData(Kernel::HLERequestContext& ctx);
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 3d100763f..c22357d8c 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -6,9 +6,14 @@
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
+#include "core/settings.h"
namespace Service::HID {
+constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
+constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
+enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
+
Controller_DebugPad::Controller_DebugPad() = default;
Controller_DebugPad::~Controller_DebugPad() = default;
@@ -33,10 +38,44 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
- // TODO(ogniK): Update debug pad states
+ cur_entry.attribute.connected.Assign(1);
+ auto& pad = cur_entry.pad_state;
+
+ using namespace Settings::NativeButton;
+ pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
+ pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
+ pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
+ pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
+ pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
+ pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
+ pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
+ pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
+ pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
+ pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
+ pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
+
+ const auto [stick_l_x_f, stick_l_y_f] =
+ analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
+ const auto [stick_r_x_f, stick_r_y_f] =
+ analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
+ cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
+ cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+ cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+ cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
std::memcpy(data, &shared_memory, sizeof(SharedMemory));
}
-void Controller_DebugPad::OnLoadInputDevices() {}
+void Controller_DebugPad::OnLoadInputDevices() {
+ std::transform(Settings::values.debug_pad_buttons.begin(),
+ Settings::values.debug_pad_buttons.begin() +
+ Settings::NativeButton::NUM_BUTTONS_HID,
+ buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
+ std::transform(Settings::values.debug_pad_analogs.begin(),
+ Settings::values.debug_pad_analogs.end(), analogs.begin(),
+ Input::CreateDevice<Input::AnalogDevice>);
+}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 62b4f2682..68b734248 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -5,10 +5,13 @@
#pragma once
#include <array>
+#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
+#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/settings.h"
namespace Service::HID {
class Controller_DebugPad final : public ControllerBase {
@@ -35,11 +38,40 @@ private:
};
static_assert(sizeof(AnalogStick) == 0x8);
+ struct PadState {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32_le> a;
+ BitField<1, 1, u32_le> b;
+ BitField<2, 1, u32_le> x;
+ BitField<3, 1, u32_le> y;
+ BitField<4, 1, u32_le> l;
+ BitField<5, 1, u32_le> r;
+ BitField<6, 1, u32_le> zl;
+ BitField<7, 1, u32_le> zr;
+ BitField<8, 1, u32_le> plus;
+ BitField<9, 1, u32_le> minus;
+ BitField<10, 1, u32_le> d_left;
+ BitField<11, 1, u32_le> d_up;
+ BitField<12, 1, u32_le> d_right;
+ BitField<13, 1, u32_le> d_down;
+ };
+ };
+ static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
+
+ struct Attributes {
+ union {
+ u32_le raw{};
+ BitField<0, 1, u32_le> connected;
+ };
+ };
+ static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
+
struct PadStates {
s64_le sampling_number;
s64_le sampling_number2;
- u32_le attribute;
- u32_le button_state;
+ Attributes attribute;
+ PadState pad_state;
AnalogStick r_stick;
AnalogStick l_stick;
};
@@ -52,5 +84,10 @@ private:
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
+
+ std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
+ buttons;
+ std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
+ analogs;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ccfbce9ac..ca75adc2b 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -6,9 +6,11 @@
#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/settings.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
+constexpr u8 KEYS_PER_BYTE = 8;
Controller_Keyboard::Controller_Keyboard() = default;
Controller_Keyboard::~Controller_Keyboard() = default;
@@ -34,10 +36,24 @@ void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
- // TODO(ogniK): Update keyboard states
+
+ for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
+ for (std::size_t k = 0; k < KEYS_PER_BYTE; ++k) {
+ cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << k);
+ }
+ }
+
+ for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
+ cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
+ }
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
}
-void Controller_Keyboard::OnLoadInputDevices() {}
+void Controller_Keyboard::OnLoadInputDevices() {
+ std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
+ keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
+ std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
+ keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
+}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 493e68fce..f52775456 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -8,7 +8,9 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
+#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/settings.h"
namespace Service::HID {
class Controller_Keyboard final : public ControllerBase {
@@ -46,5 +48,10 @@ private:
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
+
+ std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys>
+ keyboard_keys;
+ std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
+ keyboard_mods;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4e246a57d..63391dbe9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -5,6 +5,7 @@
#include <cstring>
#include "common/common_types.h"
#include "core/core_timing.h"
+#include "core/frontend/emu_window.h"
#include "core/hle/service/hid/controllers/mouse.h"
namespace Service::HID {
@@ -14,7 +15,6 @@ Controller_Mouse::Controller_Mouse() = default;
Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {}
-
void Controller_Mouse::OnRelease() {}
void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
@@ -34,10 +34,29 @@ void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
- // TODO(ogniK): Update mouse states
+
+ if (Settings::values.mouse_enabled) {
+ const auto [px, py, sx, sy] = mouse_device->GetStatus();
+ const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width);
+ const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height);
+ cur_entry.x = x;
+ cur_entry.y = y;
+ cur_entry.delta_x = x - last_entry.x;
+ cur_entry.delta_y = y - last_entry.y;
+ cur_entry.mouse_wheel_x = sx;
+ cur_entry.mouse_wheel_y = sy;
+
+ for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) {
+ cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i);
+ }
+ }
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
}
-void Controller_Mouse::OnLoadInputDevices() {}
+void Controller_Mouse::OnLoadInputDevices() {
+ mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device);
+ std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
+ mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>);
+}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 543b0b71f..70b654d07 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -7,7 +7,9 @@
#include <array>
#include "common/common_types.h"
#include "common/swap.h"
+#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/settings.h"
namespace Service::HID {
class Controller_Mouse final : public ControllerBase {
@@ -35,7 +37,8 @@ private:
s32_le y;
s32_le delta_x;
s32_le delta_y;
- s32_le mouse_wheel;
+ s32_le mouse_wheel_x;
+ s32_le mouse_wheel_y;
s32_le button;
s32_le attribute;
};
@@ -46,5 +49,9 @@ private:
std::array<MouseState, 17> mouse_states;
};
SharedMemory shared_memory{};
+
+ std::unique_ptr<Input::MouseDevice> mouse_device;
+ std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
+ mouse_button_devices;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 4b4d1324f..75fdb861a 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,27 +12,20 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/input.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/settings.h"
namespace Service::HID {
-
-constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
-constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
-constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
-constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr u32 BATTERY_FULL = 2;
-constexpr u32 NPAD_HANDHELD = 32;
-constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
constexpr u32 MAX_NPAD_ID = 7;
-constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER =
- Controller_NPad::NPadControllerType::JoyDual;
constexpr std::array<u32, 10> npad_id_list{
- 0, 1, 2, 3, 4, 5, 6, 7, 32, 16,
+ 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
};
enum class JoystickId : std::size_t {
@@ -40,6 +33,66 @@ enum class JoystickId : std::size_t {
Joystick_Right,
};
+static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) {
+ switch (type) {
+ case Settings::ControllerType::ProController:
+ return Controller_NPad::NPadControllerType::ProController;
+ case Settings::ControllerType::DualJoycon:
+ return Controller_NPad::NPadControllerType::JoyDual;
+ case Settings::ControllerType::LeftJoycon:
+ return Controller_NPad::NPadControllerType::JoyLeft;
+ case Settings::ControllerType::RightJoycon:
+ return Controller_NPad::NPadControllerType::JoyRight;
+ default:
+ UNREACHABLE();
+ return Controller_NPad::NPadControllerType::JoyDual;
+ }
+}
+
+std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
+ switch (npad_id) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return npad_id;
+ case 8:
+ case NPAD_HANDHELD:
+ return 8;
+ case 9:
+ case NPAD_UNKNOWN:
+ return 9;
+ default:
+ UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
+ return 0;
+ }
+}
+
+u32 Controller_NPad::IndexToNPad(std::size_t index) {
+ switch (index) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return static_cast<u32>(index);
+ case 8:
+ return NPAD_HANDHELD;
+ case 9:
+ return NPAD_UNKNOWN;
+ default:
+ UNIMPLEMENTED_MSG("Unknown npad index {}", index);
+ return 0;
+ };
+}
+
Controller_NPad::Controller_NPad() = default;
Controller_NPad::~Controller_NPad() = default;
@@ -56,22 +109,32 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
controller.joy_styles.handheld.Assign(1);
controller.device_type.handheld.Assign(1);
controller.pad_assignment = NPadAssignments::Dual;
+ controller.properties.is_vertical.Assign(1);
+ controller.properties.use_plus.Assign(1);
+ controller.properties.use_minus.Assign(1);
break;
case NPadControllerType::JoyDual:
controller.joy_styles.joycon_dual.Assign(1);
controller.device_type.joycon_left.Assign(1);
controller.device_type.joycon_right.Assign(1);
+ controller.properties.is_vertical.Assign(1);
+ controller.properties.use_plus.Assign(1);
+ controller.properties.use_minus.Assign(1);
controller.pad_assignment = NPadAssignments::Dual;
break;
case NPadControllerType::JoyLeft:
controller.joy_styles.joycon_left.Assign(1);
controller.device_type.joycon_left.Assign(1);
- controller.pad_assignment = NPadAssignments::Dual;
+ controller.properties.is_horizontal.Assign(1);
+ controller.properties.use_minus.Assign(1);
+ controller.pad_assignment = NPadAssignments::Single;
break;
case NPadControllerType::JoyRight:
controller.joy_styles.joycon_right.Assign(1);
controller.device_type.joycon_right.Assign(1);
- controller.pad_assignment = NPadAssignments::Dual;
+ controller.properties.is_horizontal.Assign(1);
+ controller.properties.use_plus.Assign(1);
+ controller.pad_assignment = NPadAssignments::Single;
break;
case NPadControllerType::Pokeball:
controller.joy_styles.pokeball.Assign(1);
@@ -81,6 +144,9 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
case NPadControllerType::ProController:
controller.joy_styles.pro_controller.Assign(1);
controller.device_type.pro_controller.Assign(1);
+ controller.properties.is_vertical.Assign(1);
+ controller.properties.use_plus.Assign(1);
+ controller.properties.use_minus.Assign(1);
controller.pad_assignment = NPadAssignments::Single;
break;
}
@@ -90,14 +156,12 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
controller.single_color.button_color = 0;
controller.dual_color_error = ColorReadError::ReadOk;
- controller.left_color.body_color = JOYCON_BODY_NEON_BLUE;
- controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE;
- controller.right_color.body_color = JOYCON_BODY_NEON_RED;
- controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED;
-
- controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations
- controller.properties.use_plus.Assign(1);
- controller.properties.use_minus.Assign(1);
+ controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left;
+ controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left;
+ controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right;
+ controller.right_color.button_color =
+ Settings::values.players[controller_idx].button_color_right;
+
controller.battery_level[0] = BATTERY_FULL;
controller.battery_level[1] = BATTERY_FULL;
controller.battery_level[2] = BATTERY_FULL;
@@ -105,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
void Controller_NPad::OnInit() {
auto& kernel = Core::System::GetInstance().Kernel();
- styleset_changed_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
+ styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
if (!IsControllerActivated()) {
return;
@@ -121,26 +185,109 @@ void Controller_NPad::OnInit() {
style.pro_controller.Assign(1);
style.pokeball.Assign(1);
}
+
+ std::transform(
+ Settings::values.players.begin(), Settings::values.players.end(),
+ connected_controllers.begin(), [](const Settings::PlayerInput& player) {
+ return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected};
+ });
+
+ std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
+ [](const ControllerHolder& holder) { return holder.is_connected; });
+
+ // Account for handheld
+ if (connected_controllers[8].is_connected)
+ connected_controllers[8].type = NPadControllerType::Handheld;
+
+ supported_npad_id_types.resize(npad_id_list.size());
+ std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
+ npad_id_list.size() * sizeof(u32));
+
+ // Add a default dual joycon controller if none are present.
if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
[](const ControllerHolder& controller) { return controller.is_connected; })) {
supported_npad_id_types.resize(npad_id_list.size());
std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
npad_id_list.size() * sizeof(u32));
- AddNewController(PREFERRED_CONTROLLER);
+ AddNewController(NPadControllerType::JoyDual);
+ }
+
+ for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
+ const auto& controller = connected_controllers[i];
+ if (controller.is_connected) {
+ AddNewControllerAt(controller.type, IndexToNPad(i));
+ }
}
}
void Controller_NPad::OnLoadInputDevices() {
- std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
- Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
- buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
- std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
- Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
- sticks.begin(), Input::CreateDevice<Input::AnalogDevice>);
+ const auto& players = Settings::values.players;
+ for (std::size_t i = 0; i < players.size(); ++i) {
+ std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
+ players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
+ buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
+ std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
+ players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
+ sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
+ }
}
void Controller_NPad::OnRelease() {}
+void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
+ const auto controller_idx = NPadIdToIndex(npad_id);
+ const auto controller_type = connected_controllers[controller_idx].type;
+ if (!connected_controllers[controller_idx].is_connected) {
+ return;
+ }
+ auto& pad_state = npad_pad_states[controller_idx].pad_states;
+ auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
+ auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
+ const auto& button_state = buttons[controller_idx];
+ const auto& analog_state = sticks[controller_idx];
+
+ using namespace Settings::NativeButton;
+ pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
+
+ pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
+ pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
+
+ const auto [stick_l_x_f, stick_l_y_f] =
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
+ const auto [stick_r_x_f, stick_r_y_f] =
+ analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
+ lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
+ lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
+ rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+ rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
+}
+
void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
if (!IsControllerActivated())
return;
@@ -176,97 +323,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
continue;
}
-
- // Pad states
- ControllerPadState pad_state{};
- using namespace Settings::NativeButton;
- pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
-
- pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
- pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
-
- AnalogPosition lstick_entry{};
- AnalogPosition rstick_entry{};
-
- const auto [stick_l_x_f, stick_l_y_f] =
- sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
- const auto [stick_r_x_f, stick_r_y_f] =
- sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
- lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
- lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
- rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
- rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
-
- if (controller_type == NPadControllerType::JoyLeft ||
- controller_type == NPadControllerType::JoyRight) {
- if (npad.properties.is_horizontal) {
- ControllerPadState state{};
- AnalogPosition temp_lstick_entry{};
- AnalogPosition temp_rstick_entry{};
- if (controller_type == NPadControllerType::JoyLeft) {
- state.d_down.Assign(pad_state.d_left.Value());
- state.d_left.Assign(pad_state.d_up.Value());
- state.d_right.Assign(pad_state.d_down.Value());
- state.d_up.Assign(pad_state.d_right.Value());
- state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
- state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
-
- state.zl.Assign(pad_state.zl.Value());
- state.plus.Assign(pad_state.minus.Value());
-
- temp_lstick_entry = lstick_entry;
- temp_rstick_entry = rstick_entry;
- 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.a.Value());
- state.a.Assign(pad_state.b.Value());
- state.b.Assign(pad_state.y.Value());
- state.y.Assign(pad_state.b.Value());
-
- state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
- state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
- state.zr.Assign(pad_state.zr.Value());
- state.plus.Assign(pad_state.plus.Value());
-
- temp_lstick_entry = lstick_entry;
- temp_rstick_entry = rstick_entry;
- 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.raw = state.raw;
- lstick_entry = temp_lstick_entry;
- rstick_entry = temp_rstick_entry;
- }
- }
+ const u32 npad_index = static_cast<u32>(i);
+ RequestPadStateUpdate(npad_index);
+ auto& pad_state = npad_pad_states[npad_index];
auto& main_controller =
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
@@ -280,21 +339,19 @@ 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) {
- // TODO(ogniK): Remap buttons for different orientations
- }
libnx_entry.connection_status.raw = 0;
switch (controller_type) {
case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
- handheld_entry.connection_status.IsConnected.Assign(1);
- if (!Settings::values.use_docked_mode) {
- handheld_entry.connection_status.IsWired.Assign(1);
- }
- handheld_entry.pad_states.raw = pad_state.raw;
- handheld_entry.l_stick = lstick_entry;
- handheld_entry.r_stick = rstick_entry;
+ handheld_entry.connection_status.IsWired.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
+ handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
+ handheld_entry.connection_status.IsRightJoyWired.Assign(1);
+ handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ handheld_entry.pad.l_stick = pad_state.l_stick;
+ handheld_entry.pad.r_stick = pad_state.r_stick;
break;
case NPadControllerType::JoyDual:
dual_entry.connection_status.raw = 0;
@@ -307,24 +364,25 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
libnx_entry.connection_status.IsConnected.Assign(1);
- dual_entry.pad_states.raw = pad_state.raw;
- dual_entry.l_stick = lstick_entry;
- dual_entry.r_stick = rstick_entry;
+ dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ dual_entry.pad.l_stick = pad_state.l_stick;
+ dual_entry.pad.r_stick = pad_state.r_stick;
+ break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
left_entry.connection_status.IsConnected.Assign(1);
- left_entry.pad_states.raw = pad_state.raw;
- left_entry.l_stick = lstick_entry;
- left_entry.r_stick = rstick_entry;
+ left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ left_entry.pad.l_stick = pad_state.l_stick;
+ left_entry.pad.r_stick = pad_state.r_stick;
break;
case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
right_entry.connection_status.IsConnected.Assign(1);
- right_entry.pad_states.raw = pad_state.raw;
- right_entry.l_stick = lstick_entry;
- right_entry.r_stick = rstick_entry;
+ right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ right_entry.pad.l_stick = pad_state.l_stick;
+ right_entry.pad.r_stick = pad_state.r_stick;
break;
case NPadControllerType::Pokeball:
pokeball_entry.connection_status.raw = 0;
@@ -332,30 +390,30 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
pokeball_entry.connection_status.IsConnected.Assign(1);
pokeball_entry.connection_status.IsWired.Assign(1);
- pokeball_entry.pad_states.raw = pad_state.raw;
- pokeball_entry.l_stick = lstick_entry;
- pokeball_entry.r_stick = rstick_entry;
+ pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
+ pokeball_entry.pad.l_stick = pad_state.l_stick;
+ pokeball_entry.pad.r_stick = pad_state.r_stick;
break;
case NPadControllerType::ProController:
main_controller.connection_status.raw = 0;
main_controller.connection_status.IsConnected.Assign(1);
main_controller.connection_status.IsWired.Assign(1);
- main_controller.pad_states.raw = pad_state.raw;
- main_controller.l_stick = lstick_entry;
- main_controller.r_stick = rstick_entry;
+ main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
+ main_controller.pad.l_stick = pad_state.l_stick;
+ main_controller.pad.r_stick = pad_state.r_stick;
break;
}
// LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
// any controllers.
- libnx_entry.pad_states.raw = pad_state.raw;
- libnx_entry.l_stick = lstick_entry;
- libnx_entry.r_stick = rstick_entry;
+ 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;
}
std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
shared_memory_entries.size() * sizeof(NPadEntry));
-} // namespace Service::HID
+}
void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
style.raw = style_set.raw;
@@ -370,14 +428,29 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
supported_npad_id_types.clear();
supported_npad_id_types.resize(length / sizeof(u32));
std::memcpy(supported_npad_id_types.data(), data, length);
+ bool had_controller_update = false;
for (std::size_t i = 0; i < connected_controllers.size(); i++) {
auto& controller = connected_controllers[i];
if (!controller.is_connected) {
continue;
}
- if (!IsControllerSupported(PREFERRED_CONTROLLER)) {
- controller.type = DecideBestController(PREFERRED_CONTROLLER);
- InitNewlyAddedControler(i);
+ const auto requested_controller =
+ i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
+ : NPadControllerType::Handheld;
+ if (!IsControllerSupported(requested_controller)) {
+ const auto is_handheld = requested_controller == NPadControllerType::Handheld;
+ if (is_handheld) {
+ controller.type = NPadControllerType::None;
+ controller.is_connected = false;
+ AddNewController(requested_controller);
+ } else {
+ controller.type = requested_controller;
+ InitNewlyAddedControler(i);
+ }
+ had_controller_update = true;
+ }
+ if (had_controller_update) {
+ styleset_changed_event.writable->Signal();
}
}
}
@@ -392,48 +465,49 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
}
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
+ styleset_changed_event.writable->Signal();
hold_type = joy_hold_type;
}
+
Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
return hold_type;
}
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
- ASSERT(npad_id < shared_memory_entries.size());
- shared_memory_entries[npad_id].pad_assignment = assignment_mode;
+ const std::size_t npad_index = NPadIdToIndex(npad_id);
+ ASSERT(npad_index < shared_memory_entries.size());
+ shared_memory_entries[npad_index].pad_assignment = assignment_mode;
}
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
if (!can_controllers_vibrate) {
return;
}
for (std::size_t i = 0; i < controller_ids.size(); i++) {
- std::size_t controller_pos = i;
- // Handheld controller conversion
- if (controller_pos == NPAD_HANDHELD) {
- controller_pos = 8;
- }
- // Unknown controller conversion
- if (controller_pos == NPAD_UNKNOWN) {
- controller_pos = 9;
- }
+ std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
if (connected_controllers[controller_pos].is_connected) {
// TODO(ogniK): Vibrate the physical controller
}
}
- LOG_WARNING(Service_HID, "(STUBBED) called");
last_processed_vibration = vibrations.back();
}
-Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
- return styleset_changed_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
+ // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
+ // be signalled at least once, and signaled after a new controller is connected?
+ styleset_changed_event.writable->Signal();
+ return styleset_changed_event.readable;
}
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
return last_processed_vibration;
}
+
void Controller_NPad::AddNewController(NPadControllerType controller) {
+ controller = DecideBestController(controller);
if (controller == NPadControllerType::Handheld) {
connected_controllers[8] = {controller, true};
InitNewlyAddedControler(8);
@@ -451,16 +525,54 @@ void Controller_NPad::AddNewController(NPadControllerType controller) {
InitNewlyAddedControler(controller_id);
}
-void Controller_NPad::ConnectNPad(u32 npad_id) {
- if (npad_id >= connected_controllers.size())
+void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
+ controller = DecideBestController(controller);
+ if (controller == NPadControllerType::Handheld) {
+ connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true};
+ InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD));
return;
- connected_controllers[npad_id].is_connected = true;
+ }
+
+ connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
+ InitNewlyAddedControler(NPadIdToIndex(npad_id));
+}
+
+void Controller_NPad::ConnectNPad(u32 npad_id) {
+ connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
}
void Controller_NPad::DisconnectNPad(u32 npad_id) {
- if (npad_id >= connected_controllers.size())
- return;
- connected_controllers[npad_id].is_connected = false;
+ connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
+}
+
+bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
+ if (controller == NPadControllerType::Handheld) {
+ // Handheld is not even a supported type, lets stop here
+ if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
+ NPAD_HANDHELD) == supported_npad_id_types.end()) {
+ return false;
+ }
+ // Handheld should not be supported in docked mode
+ if (Settings::values.use_docked_mode) {
+ return false;
+ }
+ }
+ switch (controller) {
+ case NPadControllerType::ProController:
+ return style.pro_controller;
+ case NPadControllerType::Handheld:
+ return style.handheld;
+ case NPadControllerType::JoyDual:
+ return style.joycon_dual;
+ case NPadControllerType::JoyLeft:
+ return style.joycon_left;
+ case NPadControllerType::JoyRight:
+ return style.joycon_right;
+ case NPadControllerType::Pokeball:
+ return style.pokeball;
+ default:
+ return false;
+ }
}
Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
@@ -494,6 +606,36 @@ void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
can_controllers_vibrate = can_vibrate;
}
+void Controller_NPad::ClearAllConnectedControllers() {
+ for (auto& controller : connected_controllers) {
+ if (controller.is_connected && controller.type != NPadControllerType::None) {
+ controller.type = NPadControllerType::None;
+ controller.is_connected = false;
+ }
+ }
+}
+void Controller_NPad::DisconnectAllConnectedControllers() {
+ std::for_each(connected_controllers.begin(), connected_controllers.end(),
+ [](ControllerHolder& controller) { controller.is_connected = false; });
+}
+
+void Controller_NPad::ConnectAllDisconnectedControllers() {
+ std::for_each(connected_controllers.begin(), connected_controllers.end(),
+ [](ControllerHolder& controller) {
+ if (controller.type != NPadControllerType::None && !controller.is_connected) {
+ controller.is_connected = false;
+ }
+ });
+}
+
+void Controller_NPad::ClearAllControllers() {
+ std::for_each(connected_controllers.begin(), connected_controllers.end(),
+ [](ControllerHolder& controller) {
+ controller.type = NPadControllerType::None;
+ controller.is_connected = false;
+ });
+}
+
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 ac86985ff..29851f16a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -5,13 +5,19 @@
#pragma once
#include <array>
+#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/frontend/input.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/settings.h"
namespace Service::HID {
+constexpr u32 NPAD_HANDHELD = 32;
+constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
+
class Controller_NPad final : public ControllerBase {
public:
Controller_NPad();
@@ -75,9 +81,9 @@ public:
struct LedPattern {
explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
position1.Assign(light1);
- position1.Assign(light2);
- position1.Assign(light3);
- position1.Assign(light4);
+ position2.Assign(light2);
+ position3.Assign(light3);
+ position4.Assign(light4);
}
union {
u64 raw{};
@@ -103,15 +109,23 @@ public:
void VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations);
- Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
+ void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
void ConnectNPad(u32 npad_id);
void DisconnectNPad(u32 npad_id);
LedPattern GetLedPattern(u32 npad_id);
void SetVibrationEnabled(bool can_vibrate);
+ void ClearAllConnectedControllers();
+ void DisconnectAllConnectedControllers();
+ void ConnectAllDisconnectedControllers();
+ void ClearAllControllers();
+
+ static std::size_t NPadIdToIndex(u32 npad_id);
+ static u32 IndexToNPad(std::size_t index);
private:
struct CommonHeader {
@@ -164,8 +178,11 @@ private:
BitField<23, 1, u64_le> r_stick_down;
// Not always active?
- BitField<24, 1, u64_le> sl;
- BitField<25, 1, u64_le> sr;
+ BitField<24, 1, u64_le> left_sl;
+ BitField<25, 1, u64_le> left_sr;
+
+ BitField<26, 1, u64_le> right_sl;
+ BitField<27, 1, u64_le> right_sr;
};
};
static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
@@ -189,12 +206,17 @@ private:
};
static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
- struct GenericStates {
- s64_le timestamp;
- s64_le timestamp2;
+ struct ControllerPad {
ControllerPadState pad_states;
AnalogPosition l_stick;
AnalogPosition r_stick;
+ };
+ static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
+
+ struct GenericStates {
+ s64_le timestamp;
+ s64_le timestamp2;
+ ControllerPad pad;
ConnectionState connection_status;
};
static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
@@ -266,18 +288,23 @@ private:
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
struct ControllerHolder {
- Controller_NPad::NPadControllerType type;
+ NPadControllerType type;
bool is_connected;
};
NPadType style{};
std::array<NPadEntry, 10> shared_memory_entries{};
- std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
+ std::array<
+ std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
+ 10>
buttons;
- std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks;
+ std::array<
+ std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
+ 10>
+ sticks;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
- Kernel::SharedPtr<Kernel::Event> styleset_changed_event;
+ Kernel::EventPair styleset_changed_event;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
bool can_controllers_vibrate{true};
@@ -285,5 +312,8 @@ private:
void InitNewlyAddedControler(std::size_t controller_idx);
bool IsControllerSupported(NPadControllerType controller) const;
NPadControllerType DecideBestController(NPadControllerType priority) const;
+ void RequestPadStateUpdate(u32 npad_id);
+ std::array<ControllerPad, 10> npad_pad_states{};
+ bool IsControllerSupported(NPadControllerType controller);
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 43efef803..f666b1bd8 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -41,16 +41,17 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
const auto [x, y, pressed] = touch_device->GetStatus();
auto& touch_entry = cur_entry.states[0];
- if (pressed) {
+ touch_entry.attribute.raw = 0;
+ if (pressed && Settings::values.touchscreen.enabled) {
touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
- touch_entry.diameter_x = 15;
- touch_entry.diameter_y = 15;
- touch_entry.rotation_angle = 0;
+ touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
+ touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
+ touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
const u64 tick = CoreTiming::GetTicks();
touch_entry.delta_time = tick - last_touch;
last_touch = tick;
- touch_entry.finger = 0;
+ touch_entry.finger = Settings::values.touchscreen.finger;
cur_entry.entry_count = 1;
} else {
cur_entry.entry_count = 0;
@@ -60,6 +61,6 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
}
void Controller_Touchscreen::OnLoadInputDevices() {
- touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device);
+ touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index e5db6e6ba..94cd0eba9 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -4,6 +4,7 @@
#pragma once
+#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
@@ -29,9 +30,18 @@ public:
void OnLoadInputDevices() override;
private:
+ struct Attributes {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32_le> start_touch;
+ BitField<1, 1, u32_le> end_touch;
+ };
+ };
+ static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
+
struct TouchState {
u64_le delta_time;
- u32_le attribute;
+ Attributes attribute;
u32_le finger;
u32_le x;
u32_le y;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a9aa9ec78..268409257 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,8 +13,9 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
@@ -34,8 +35,8 @@
namespace Service::HID {
// Updating period for each HID device.
-// TODO(shinyquagsire23): These need better values.
-constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
+// TODO(ogniK): Find actual polling rate of hid
+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;
@@ -96,6 +97,8 @@ public:
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
+
+ ReloadInputDevices();
}
void ActivateController(HidController controller) {
@@ -122,10 +125,11 @@ public:
private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_mem);
- LOG_DEBUG(Service_HID, "called");
}
void UpdateControllers(u64 userdata, int cycles_late) {
@@ -161,9 +165,10 @@ public:
private:
void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
};
@@ -284,10 +289,10 @@ public:
{519, nullptr, "GetPalmaOperationResult"},
{520, nullptr, "ReadPalmaPlayLog"},
{521, nullptr, "ResetPalmaPlayLog"},
- {522, nullptr, "SetIsPalmaAllConnectable"},
+ {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
{523, nullptr, "SetIsPalmaPairedConnectable"},
{524, nullptr, "PairPalma"},
- {525, nullptr, "SetPalmaBoostMode"},
+ {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
{1000, nullptr, "SetNpadCommunicationMode"},
{1001, nullptr, "GetNpadCommunicationMode"},
};
@@ -301,6 +306,11 @@ private:
std::shared_ptr<IAppletResource> applet_resource;
void CreateAppletResource(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
if (applet_resource == nullptr) {
applet_resource = std::make_shared<IAppletResource>();
}
@@ -308,206 +318,306 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAppletResource>(applet_resource);
- LOG_DEBUG(Service_HID, "called");
}
void 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>()};
+
+ LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
+ basic_xpad_id, applet_resource_user_id);
+
applet_resource->ActivateController(HidController::XPad);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->ActivateController(HidController::DebugPad);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->ActivateController(HidController::Touchscreen);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateMouse(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->ActivateController(HidController::Mouse);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->ActivateController(HidController::Keyboard);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateGesture(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto unknown{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+ applet_resource_user_id);
+
applet_resource->ActivateController(HidController::Gesture);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void 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>()};
+
+ LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown,
+ applet_resource_user_id);
+
applet_resource->ActivateController(HidController::NPad);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto handle = rp.PopRaw<u32>();
+ 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void 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>()};
+
+ 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void IsSixAxisSensorAtRest(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, 3};
rb.Push(RESULT_SUCCESS);
// TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
rb.Push(true);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto supported_styleset = rp.PopRaw<u32>();
+ const auto supported_styleset{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
+
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedStyleSet({supported_styleset});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_DEBUG(Service_HID, "called");
}
void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(controller.GetSupportedStyleSet().raw);
- LOG_DEBUG(Service_HID, "called");
}
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void ActivateNpad(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ 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::NPad);
- LOG_DEBUG(Service_HID, "called");
}
void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto npad_id = rp.PopRaw<u32>();
+ const auto npad_id{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto unknown{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
+ npad_id, applet_resource_user_id, unknown);
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetStyleSetChangedEvent());
- LOG_DEBUG(Service_HID, "called");
}
void DisconnectNpad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto npad_id = rp.PopRaw<u32>();
+ 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);
+
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.DisconnectNPad(npad_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto npad_id = rp.PopRaw<u32>();
+ const auto npad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetLedPattern(npad_id)
.raw);
- LOG_DEBUG(Service_HID, "called");
}
void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
- auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
IPC::RequestParser rp{ctx};
- const auto hold_type = rp.PopRaw<u64>();
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto hold_type{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
+ applet_resource_user_id, hold_type);
+
+ auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
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()));
- LOG_DEBUG(Service_HID, "called");
}
void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto npad_id = rp.PopRaw<u32>();
+ const auto npad_id{rp.Pop<u32>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+ npad_id, applet_resource_user_id);
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetVibrationEnabled(true);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetVibrationEnabled(false);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
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>();
+ 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>()};
+
+ LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}",
+ controller_id, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.VibrateController({controller_id}, {vibration_values});
- LOG_DEBUG(Service_HID, "called");
}
void SendVibrationValues(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
const auto controllers = ctx.ReadBuffer(0);
const auto vibrations = ctx.ReadBuffer(1);
@@ -525,74 +635,134 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_HID, "called");
}
void 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());
- LOG_DEBUG(Service_HID, "called");
}
void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- const auto npad_id = rp.PopRaw<u32>();
+ 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);
- LOG_DEBUG(Service_HID, "called");
}
void 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- auto mode = rp.PopRaw<u32>();
+ 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void 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);
- LOG_DEBUG(Service_HID, "called");
}
void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IActiveVibrationDeviceList>();
- LOG_DEBUG(Service_HID, "called");
}
void 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
void 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 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 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);
- LOG_WARNING(Service_HID, "(STUBBED) called");
}
};
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 872e3c344..3c7f8b1ee 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} {
}
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_IRS, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(shared_mem);
- LOG_DEBUG(Service_IRS, "called");
}
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u64>(CoreTiming::GetTicks());
rb.PushRaw<u32>(0);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u32>(device_handle);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_IRS, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_IRS, "(STUBBED) called");
}
IRS::~IRS() = default;
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 164c57e18..e8f9f2d29 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -55,29 +55,29 @@ public:
private:
void EnableVrMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LBL, "called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
vr_mode_enabled = true;
-
- LOG_DEBUG(Service_LBL, "called");
}
void DisableVrMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LBL, "called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
vr_mode_enabled = false;
-
- LOG_DEBUG(Service_LBL, "called");
}
void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LBL, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(vr_mode_enabled);
-
- LOG_DEBUG(Service_LBL, "called");
}
bool vr_mode_enabled = false;
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 167f2c66a..e250595e3 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -44,11 +44,11 @@ public:
}
void CreateMonitorService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDN, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IMonitorService>();
-
- LOG_DEBUG(Service_LDN, "called");
}
};
@@ -104,11 +104,11 @@ public:
}
void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDN, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
-
- LOG_DEBUG(Service_LDN, "called");
}
};
@@ -125,11 +125,11 @@ public:
}
void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDN, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
-
- LOG_DEBUG(Service_LDN, "called");
}
};
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d607d985e..9df7ac50f 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -4,7 +4,10 @@
#include <memory>
#include <fmt/format.h>
+#include <mbedtls/sha256.h>
+#include "common/alignment.h"
+#include "common/hex_util.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/ldr/ldr.h"
@@ -13,6 +16,21 @@
namespace Service::LDR {
+constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
+constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
+constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
+constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
+constexpr ResultCode ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55};
+constexpr ResultCode ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56};
+constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
+constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
+constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
+constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
+constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
+constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
+
+constexpr u64 MAXIMUM_LOADED_RO = 0x40;
+
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
@@ -64,9 +82,9 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, &RelocatableObject::LoadNro, "LoadNro"},
- {1, nullptr, "UnloadNro"},
+ {1, &RelocatableObject::UnloadNro, "UnloadNro"},
{2, &RelocatableObject::LoadNrr, "LoadNrr"},
- {3, nullptr, "UnloadNrr"},
+ {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
{4, &RelocatableObject::Initialize, "Initialize"},
};
// clang-format on
@@ -75,9 +93,126 @@ public:
}
void LoadNrr(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rp.Skip(2, false);
+ const VAddr nrr_addr{rp.Pop<VAddr>()};
+ const u64 nrr_size{rp.Pop<u64>()};
+ LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr,
+ nrr_size);
+
+ if (!initialized) {
+ LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_NOT_INITIALIZED);
+ return;
+ }
+
+ if (nrr.size() >= MAXIMUM_LOADED_RO) {
+ LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
+ "(0x40)! Failing...");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_MAXIMUM_NRR);
+ return;
+ }
+
+ // NRR Address does not fall on 0x1000 byte boundary
+ if (!Common::Is4KBAligned(nrr_addr)) {
+ LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ALIGNMENT);
+ return;
+ }
+
+ // NRR Size is zero or causes overflow
+ if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) {
+ LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
+ nrr_addr, nrr_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_SIZE);
+ return;
+ }
+ // Read NRR data from memory
+ std::vector<u8> nrr_data(nrr_size);
+ Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
+ NRRHeader header;
+ std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
+
+ if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
+ LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRR);
+ return;
+ }
+
+ if (header.size != nrr_size) {
+ LOG_ERROR(Service_LDR,
+ "NRR header reported size did not match LoadNrr parameter size! "
+ "(header_size={:016X}, loadnrr_size={:016X})",
+ header.size, nrr_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_SIZE);
+ return;
+ }
+
+ if (Core::CurrentProcess()->GetTitleID() != header.title_id) {
+ LOG_ERROR(Service_LDR,
+ "Attempting to load NRR with title ID other than current process. (actual "
+ "{:016X})!",
+ header.title_id);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRR);
+ return;
+ }
+
+ std::vector<SHA256Hash> hashes;
+
+ // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
+ for (std::size_t i = header.hash_offset;
+ i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
+ SHA256Hash hash;
+ std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
+ hashes.emplace_back(hash);
+ }
+
+ nrr.insert_or_assign(nrr_addr, std::move(hashes));
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void UnloadNrr(Kernel::HLERequestContext& ctx) {
+ if (!initialized) {
+ LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_NOT_INITIALIZED);
+ return;
+ }
+
+ IPC::RequestParser rp{ctx};
+ rp.Skip(2, false);
+ const auto nrr_addr{rp.Pop<VAddr>()};
+ LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr);
+
+ if (!Common::Is4KBAligned(nrr_addr)) {
+ LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ALIGNMENT);
+ return;
+ }
+
+ const auto iter = nrr.find(nrr_addr);
+ if (iter == nrr.end()) {
+ LOG_ERROR(Service_LDR,
+ "Attempting to unload NRR which has not been loaded! (addr={:016X})",
+ nrr_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRR_ADDRESS);
+ return;
+ }
+
+ nrr.erase(iter);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_LDR, "(STUBBED) called");
}
void LoadNro(Kernel::HLERequestContext& ctx) {
@@ -87,33 +222,260 @@ public:
const u64 nro_size{rp.Pop<u64>()};
const VAddr bss_addr{rp.Pop<VAddr>()};
const u64 bss_size{rp.Pop<u64>()};
+ LOG_DEBUG(
+ Service_LDR,
+ "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}",
+ nro_addr, nro_size, bss_addr, bss_size);
+
+ if (!initialized) {
+ LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_NOT_INITIALIZED);
+ return;
+ }
+
+ if (nro.size() >= MAXIMUM_LOADED_RO) {
+ LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
+ "(0x40)! Failing...");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_MAXIMUM_NRO);
+ return;
+ }
+
+ // NRO Address does not fall on 0x1000 byte boundary
+ if (!Common::Is4KBAligned(nro_addr)) {
+ LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ALIGNMENT);
+ return;
+ }
+
+ // NRO Size or BSS Size is zero or causes overflow
+ const auto nro_size_valid =
+ nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size);
+ const auto bss_size_valid =
+ nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr);
+
+ if (!nro_size_valid || !bss_size_valid) {
+ LOG_ERROR(Service_LDR,
+ "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
+ "bss_address={:016X}, bss_size={:016X})",
+ nro_addr, nro_size, bss_addr, bss_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_SIZE);
+ return;
+ }
// Read NRO data from memory
std::vector<u8> nro_data(nro_size);
Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
+ SHA256Hash hash{};
+ mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
+
+ // NRO Hash is already loaded
+ if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
+ return info.second.hash == hash;
+ })) {
+ LOG_ERROR(Service_LDR, "NRO is already loaded!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_ALREADY_LOADED);
+ return;
+ }
+
+ // NRO Hash is not in any loaded NRR
+ if (!IsValidNROHash(hash)) {
+ LOG_ERROR(Service_LDR,
+ "NRO hash is not present in any currently loaded NRRs (hash={})!",
+ Common::HexArrayToString(hash));
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_MISSING_NRR_HASH);
+ return;
+ }
+
+ NROHeader header;
+ std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
+
+ if (!IsValidNRO(header, nro_size, bss_size)) {
+ LOG_ERROR(Service_LDR, "NRO was invalid!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRO);
+ return;
+ }
+
// Load NRO as new executable module
- const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)};
- Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr);
+ auto* process = Core::CurrentProcess();
+ auto& vm_manager = process->VMManager();
+ auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size);
+
+ if (!map_address.Succeeded() ||
+ *map_address + nro_size + bss_size > vm_manager.GetAddressSpaceEndAddress()) {
+
+ LOG_ERROR(Service_LDR,
+ "General error while allocation memory or no available memory to allocate!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_MEMORY_STATE);
+ return;
+ }
+
+ 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(vm_manager
+ .MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
+ Kernel::MemoryState::ModuleCodeStatic)
+ .IsSuccess());
+ ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess());
+ }
- // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party.
- // It is currently missing:
- // - Signature checks with LoadNRR
- // - Checking if a module has already been loaded
- // - Using/validating BSS, etc. params (these are used from NRO header instead)
- // - Error checking
- // - ...Probably other things
+ vm_manager.ReprotectRange(*map_address, header.text_size,
+ Kernel::VMAPermission::ReadExecute);
+ vm_manager.ReprotectRange(*map_address + header.ro_offset, header.ro_size,
+ Kernel::VMAPermission::Read);
+ vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
+ Kernel::VMAPermission::ReadWrite);
+
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
+
+ nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(addr);
- LOG_WARNING(Service_LDR, "(STUBBED) called");
+ rb.Push(*map_address);
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void UnloadNro(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ rp.Skip(2, false);
+ const VAddr mapped_addr{rp.PopRaw<VAddr>()};
+ const VAddr heap_addr{rp.PopRaw<VAddr>()};
+ LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr,
+ heap_addr);
+
+ if (!initialized) {
+ LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_NOT_INITIALIZED);
+ return;
+ }
+
+ if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) {
+ LOG_ERROR(Service_LDR,
+ "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, "
+ "bss_addr={:016X})!",
+ mapped_addr, heap_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_ALIGNMENT);
+ return;
+ }
+
+ const auto iter = nro.find(mapped_addr);
+ if (iter == nro.end()) {
+ LOG_ERROR(Service_LDR,
+ "The NRO attempting to unmap was not mapped or has an invalid address "
+ "(actual {:016X})!",
+ mapped_addr);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERROR_INVALID_NRO_ADDRESS);
+ return;
+ }
+
+ auto& vm_manager = Core::CurrentProcess()->VMManager();
+ const auto& nro_size = iter->second.size;
+
+ 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();
+
+ nro.erase(iter);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
+ }
+
+ void Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_LDR, "(STUBBED) called");
+
+ initialized = true;
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+private:
+ using SHA256Hash = std::array<u8, 0x20>;
+
+ struct NROHeader {
+ INSERT_PADDING_WORDS(1);
+ u32_le mod_offset;
+ INSERT_PADDING_WORDS(2);
+ u32_le magic;
+ u32_le version;
+ u32_le nro_size;
+ u32_le flags;
+ u32_le text_offset;
+ u32_le text_size;
+ u32_le ro_offset;
+ u32_le ro_size;
+ u32_le rw_offset;
+ u32_le rw_size;
+ u32_le bss_size;
+ INSERT_PADDING_WORDS(1);
+ std::array<u8, 0x20> build_id;
+ INSERT_PADDING_BYTES(0x20);
+ };
+ static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
+
+ struct NRRHeader {
+ u32_le magic;
+ 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;
+ u64_le title_id;
+ u32_le size;
+ INSERT_PADDING_BYTES(4);
+ u32_le hash_offset;
+ u32_le hash_count;
+ INSERT_PADDING_BYTES(8);
+ };
+ static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size.");
+
+ struct NROInfo {
+ SHA256Hash hash;
+ u64 size;
+ };
+
+ bool initialized = false;
+
+ std::map<VAddr, NROInfo> nro;
+ std::map<VAddr, std::vector<SHA256Hash>> nrr;
+
+ bool IsValidNROHash(const SHA256Hash& hash) {
+ return std::any_of(
+ nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) {
+ return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
+ });
+ }
+
+ static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
+ return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
+ header.nro_size == nro_size && header.bss_size == bss_size &&
+ header.ro_offset == header.text_offset + header.text_size &&
+ header.rw_offset == header.ro_offset + header.ro_size &&
+ nro_size == header.rw_offset + header.rw_size &&
+ Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
+ Common::Is4KBAligned(header.rw_size);
}
};
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index c89157a4d..1f462e087 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -18,7 +18,7 @@ public:
ILogger() : ServiceFramework("ILogger") {
static const FunctionInfo functions[] = {
{0x00000000, &ILogger::Initialize, "Initialize"},
- {0x00000001, nullptr, "SetDestination"},
+ {0x00000001, &ILogger::SetDestination, "SetDestination"},
};
RegisterHandlers(functions);
}
@@ -178,6 +178,17 @@ private:
}
}
+ // This service function is intended to be used as a way to
+ // redirect logging output to different destinations, however,
+ // given we always want to see the logging output, it's sufficient
+ // to do nothing and return success here.
+ void SetDestination(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
std::ostringstream log_stream;
};
@@ -198,11 +209,11 @@ public:
* 0: ResultCode
*/
void OpenLogger(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILogger>();
-
- LOG_DEBUG(Service_LM, "called");
}
};
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index e1f17a926..def63dc8a 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -31,12 +31,14 @@ public:
private:
void Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Finalize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -45,15 +47,16 @@ private:
IPC::RequestParser rp{ctx};
min = rp.Pop<u32>();
max = rp.Pop<u32>();
- current = min;
-
LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
+
+ current = min;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Get(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(current);
@@ -61,6 +64,7 @@ private:
void InitializeWithId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(id); // Any non zero value
@@ -68,6 +72,7 @@ private:
void FinalizeWithId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -77,16 +82,17 @@ private:
u32 input_id = rp.Pop<u32>();
min = rp.Pop<u32>();
max = rp.Pop<u32>();
- current = min;
-
LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}",
input_id, min, max);
+
+ current = min;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetWithId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push(current);
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 30e542542..5c62d42ba 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -43,11 +43,11 @@ public:
private:
void CreateAmInterface(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAm>();
-
- LOG_DEBUG(Service_NFC, "called");
}
};
@@ -91,11 +91,11 @@ public:
private:
void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<MFIUser>();
-
- LOG_DEBUG(Service_NFC, "called");
}
};
@@ -138,19 +138,19 @@ private:
};
void InitializeOld(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0};
rb.Push(RESULT_SUCCESS);
-
// We don't deal with hardware initialization so we can just stub this.
- LOG_DEBUG(Service_NFC, "called");
}
void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u8>(Settings::values.enable_nfc);
-
- LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
}
void GetStateOld(Kernel::HLERequestContext& ctx) {
@@ -183,11 +183,11 @@ public:
private:
void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IUser>();
-
- LOG_DEBUG(Service_NFC, "called");
}
};
@@ -241,11 +241,11 @@ public:
private:
void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystem>();
-
- LOG_DEBUG(Service_NFC, "called");
}
};
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index c1af878fe..2254fb46b 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,9 +7,11 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.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"
@@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {
auto& kernel = Core::System::GetInstance().Kernel();
- nfc_tag_load =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected");
+ nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IUser:NFCTagDetected");
}
Module::Interface::~Interface() = default;
@@ -63,10 +65,10 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- deactivate_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
- availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IUser:AvailabilityChangeEvent");
+ deactivate_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
+ availability_change_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
}
private:
@@ -108,30 +110,29 @@ private:
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
void Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0};
rb.Push(RESULT_SUCCESS);
state = State::Initialized;
-
- LOG_DEBUG(Service_NFC, "called");
}
void GetState(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
IPC::ResponseBuilder rb{ctx, 3, 0};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u32>(static_cast<u32>(state));
-
- LOG_DEBUG(Service_NFC, "called");
}
void ListDevices(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 array_size = rp.Pop<u32>();
+ LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
ctx.WriteBuffer(&device_handle, sizeof(device_handle));
- LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
-
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1);
@@ -141,6 +142,7 @@ private:
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(npad_id);
@@ -150,6 +152,7 @@ private:
IPC::RequestParser rp{ctx};
const u64 dev_handle = rp.Pop<u64>();
LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(nfp_interface.GetNFCEvent());
@@ -163,15 +166,16 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(deactivate_event);
+ rb.PushCopyObjects(deactivate_event.readable);
}
void StopDetection(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NFP, "called");
+
switch (device_state) {
case DeviceState::TagFound:
case DeviceState::TagNearby:
- deactivate_event->Signal();
+ deactivate_event.writable->Signal();
device_state = DeviceState::Initialized;
break;
case DeviceState::SearchingForTag:
@@ -185,6 +189,7 @@ private:
void GetDeviceState(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NFP, "called");
+
auto nfc_event = nfp_interface.GetNFCEvent();
if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
device_state = DeviceState::TagFound;
@@ -212,7 +217,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
auto amiibo = nfp_interface.GetAmiiboBuffer();
TagInfo tag_info{};
- std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size()));
+ tag_info.uuid = amiibo.uuid;
tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
@@ -261,7 +266,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(availability_change_event);
+ rb.PushCopyObjects(availability_change_event.readable);
}
void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -312,17 +317,18 @@ 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::SharedPtr<Kernel::Event> deactivate_event;
- Kernel::SharedPtr<Kernel::Event> availability_change_event;
+ Kernel::EventPair deactivate_event;
+ Kernel::EventPair availability_change_event;
const Module::Interface& nfp_interface;
};
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NFP, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IUser>(*this);
@@ -335,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
}
std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
- nfc_tag_load->Signal();
+ nfc_tag_load.writable->Signal();
return true;
}
-const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const {
- return nfc_tag_load;
+
+const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
+ return nfc_tag_load.readable;
}
+
const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
return amiibo;
}
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 5c0ae8a54..a1817e991 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -6,7 +6,8 @@
#include <array>
#include <vector>
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
namespace Service::NFP {
@@ -33,11 +34,11 @@ public:
void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer);
- const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const;
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
const AmiiboFile& GetAmiiboBuffer() const;
private:
- Kernel::SharedPtr<Kernel::Event> nfc_tag_load{};
+ Kernel::EventPair nfc_tag_load{};
AmiiboFile amiibo{};
protected:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 75dcd94a3..60479bb45 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -4,7 +4,9 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
@@ -56,19 +58,23 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1");
- event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2");
+ event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IRequest:Event1");
+ event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IRequest:Event2");
}
private:
void Submit(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetRequestState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
@@ -76,30 +82,34 @@ private:
void GetResult(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2, 2};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event1, event2);
+ rb.PushCopyObjects(event1.readable, event2.readable);
}
void Cancel(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
- Kernel::SharedPtr<Kernel::Event> event1, event2;
+ Kernel::EventPair event1, event2;
};
class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -122,32 +132,36 @@ private:
void GetClientId(Kernel::HLERequestContext& ctx) {
static constexpr u32 client_id = 1;
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
}
void CreateScanRequest(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IScanRequest>();
-
- LOG_DEBUG(Service_NIFM, "called");
}
void CreateRequest(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IRequest>();
-
- LOG_DEBUG(Service_NIFM, "called");
}
void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
+
ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
u128 uuid{};
auto buffer = ctx.ReadBuffer();
@@ -158,23 +172,24 @@ private:
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<INetworkProfile>();
rb.PushRaw<u128>(uuid);
-
- LOG_DEBUG(Service_NIFM, "called");
}
void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
}
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(0);
@@ -235,17 +250,19 @@ public:
}
void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
- LOG_DEBUG(Service_NIFM, "called");
}
void CreateGeneralService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IGeneralService>();
- LOG_DEBUG(Service_NIFM, "called");
}
};
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 18091c9bb..0dabcd23b 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -6,7 +6,9 @@
#include <ctime>
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -138,57 +140,61 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- finished_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IEnsureNetworkClockAvailabilityService:FinishEvent");
+ finished_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot,
+ "IEnsureNetworkClockAvailabilityService:FinishEvent");
}
private:
- Kernel::SharedPtr<Kernel::Event> finished_event;
+ Kernel::EventPair finished_event;
void StartTask(Kernel::HLERequestContext& ctx) {
// No need to connect to the internet, just finish the task straight away.
- finished_event->Signal();
+ LOG_DEBUG(Service_NIM, "called");
+ finished_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_NIM, "called");
}
void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(finished_event);
- LOG_DEBUG(Service_NIM, "called");
+ rb.PushCopyObjects(finished_event.readable);
}
void GetResult(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIM, "called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_NIM, "called");
}
void Cancel(Kernel::HLERequestContext& ctx) {
- finished_event->Clear();
+ LOG_DEBUG(Service_NIM, "called");
+ finished_event.writable->Clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_NIM, "called");
}
void IsProcessing(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIM, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<u32>(0); // We instantly process the request
- LOG_DEBUG(Service_NIM, "called");
}
void GetServerTime(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIM, "called");
+
const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count()};
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.PushRaw<s64>(server_time);
- LOG_DEBUG(Service_NIM, "called");
}
};
@@ -208,23 +214,26 @@ public:
private:
void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIM, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
- LOG_DEBUG(Service_NIM, "called");
}
// TODO(ogniK): Do we need these?
void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_NIM, "(STUBBED) called");
}
void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIM, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_WARNING(Service_NIM, "(STUBBED) called");
}
};
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 07c1381fe..2663f56b1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,6 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
{305, nullptr, "TerminateSystemApplet"},
{306, nullptr, "LaunchOverlayApplet"},
{307, nullptr, "TerminateOverlayApplet"},
- {400, nullptr, "GetApplicationControlData"},
+ {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
{401, nullptr, "InvalidateAllApplicationControlCache"},
{402, nullptr, "RequestDownloadApplicationControlData"},
{403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
RegisterHandlers(functions);
}
+
+ void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto flag = rp.PopRaw<u64>();
+ LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
+
+ const auto title_id = rp.PopRaw<u64>();
+
+ const auto size = ctx.GetWriteBufferSize();
+
+ const FileSys::PatchManager pm{title_id};
+ const auto control = pm.GetControlMetadata();
+
+ std::vector<u8> out;
+
+ if (control.first != nullptr) {
+ if (size < 0x4000) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
+ size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000);
+ const auto bytes = control.first->GetRawBytes();
+ std::memcpy(out.data(), bytes.data(), bytes.size());
+ } else {
+ LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ out.resize(std::min<u64>(0x4000, size));
+ }
+
+ if (control.second != nullptr) {
+ if (size < 0x4000 + control.second->GetSize()) {
+ LOG_ERROR(Service_NS,
+ "output buffer is too small! (actual={:016X}, expected_min={:016X})",
+ size, 0x4000 + control.second->GetSize());
+ IPC::ResponseBuilder rb{ctx, 2};
+ // TODO(DarkLordZach): Find a better error code for this.
+ rb.Push(ResultCode(-1));
+ return;
+ }
+
+ out.resize(0x4000 + control.second->GetSize());
+ control.second->Read(out.data() + 0x4000, control.second->GetSize());
+ } else {
+ LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
+ title_id);
+ }
+
+ ctx.WriteBuffer(out);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(static_cast<u32>(out.size()));
+ }
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
@@ -371,11 +433,11 @@ public:
private:
template <typename T>
void PushInterface(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NS, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<T>();
-
- LOG_DEBUG(Service_NS, "called");
}
};
@@ -464,11 +526,11 @@ public:
private:
void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NS, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemUpdateControl>();
-
- LOG_DEBUG(Service_NS, "called");
}
};
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 44accecb7..ad176f89d 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
const u32 shared_font_type{rp.Pop<u32>()};
// Games don't call this so all fonts should be loaded
LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
-
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(LoadState::Done));
@@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
-
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
@@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
-
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
@@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
// Map backing memory for the font data
+ LOG_DEBUG(Service_NS, "called");
Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
SHARED_FONT_MEM_SIZE,
Kernel::MemoryState::Shared);
@@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
"PL_U:shared_font_mem");
- LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(impl->shared_font_mem);
@@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
+
IPC::ResponseBuilder rb{ctx, 4};
std::vector<u32> font_codes;
std::vector<u32> font_offsets;
@@ -351,6 +353,14 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
font_sizes.push_back(region.size);
}
+ // Resize buffers if game requests smaller size output.
+ font_codes.resize(
+ std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32)));
+ font_offsets.resize(
+ std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32)));
+ font_sizes.resize(
+ std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32)));
+
ctx.WriteBuffer(font_codes, 0);
ctx.WriteBuffer(font_offsets, 1);
ctx.WriteBuffer(font_sizes, 2);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index c41ef7058..466db7ccd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
IoctlInitalizeEx params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
+
return 0;
}
@@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
IoctlBindChannel params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
+
channel = params.fd;
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 7a88ae029..d57a54ee8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,8 @@
#include <cstring>
#include "common/assert.h"
#include "common/logging/log.h"
+#include "core/core_timing.h"
+#include "core/core_timing_util.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
namespace Service::Nvidia::Devices {
@@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
return ZBCQueryTable(input, output);
case IoctlCommand::IocFlushL2:
return FlushL2(input, output);
+ case IoctlCommand::IocGetGpuTime:
+ return GetGpuTime(input, output);
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
return 0;
@@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
+
IoctlActiveSlotMask params{};
if (input.size() > 0) {
std::memcpy(&params, input.data(), input.size());
@@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
+
IoctlZcullGetCtxSize params{};
if (input.size() > 0) {
std::memcpy(&params, input.data(), input.size());
@@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
+
IoctlNvgpuGpuZcullGetInfoArgs params{};
if (input.size() > 0) {
@@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
IoctlZbcSetTable params{};
std::memcpy(&params, input.data(), input.size());
// TODO(ogniK): What does this even actually do?
@@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
IoctlZbcQueryTable params{};
std::memcpy(&params, input.data(), input.size());
// TODO : To implement properly
@@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>
u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
IoctlFlushL2 params{};
std::memcpy(&params, input.data(), input.size());
// TODO : To implement properly
@@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp
return 0;
}
+u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
+ LOG_DEBUG(Service_NVDRV, "called");
+
+ IoctlGetGpuTime params{};
+ std::memcpy(&params, input.data(), input.size());
+ params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
+ std::memcpy(output.data(), &params, output.size());
+ return 0;
+}
+
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 3bbf028ad..240435eea 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -156,6 +156,11 @@ private:
};
static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
+ struct IoctlGetGpuTime {
+ u64_le gpu_time;
+ };
+ static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
+
u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
@@ -164,6 +169,7 @@ private:
u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
+ u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 874d5e1c3..0a650f36c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -8,7 +8,6 @@
#include "core/core.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
#include "core/memory.h"
-#include "video_core/command_processor.h"
#include "video_core/gpu.h"
#include "video_core/memory_manager.h"
@@ -61,12 +60,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+
nvmap_fd = params.nvmap_fd;
return 0;
}
u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
+
IoctlClientData params{};
std::memcpy(&params, input.data(), input.size());
user_data = params.data;
@@ -75,6 +76,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out
u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called");
+
IoctlClientData params{};
std::memcpy(&params, input.data(), input.size());
params.data = user_data;
@@ -86,6 +88,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output)
std::memcpy(&zcull_params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
zcull_params.mode);
+
std::memcpy(output.data(), &zcull_params, output.size());
return 0;
}
@@ -95,6 +98,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
params.size, params.mem);
+
std::memcpy(output.data(), &params, output.size());
return 0;
}
@@ -102,6 +106,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
std::memcpy(&channel_priority, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
+
return 0;
}
@@ -113,6 +118,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
"unk1={:X}, unk2={:X}, unk3={:X}",
params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
params.unk3);
+
params.fence_out.id = 0;
params.fence_out.value = 0;
std::memcpy(output.data(), &params, output.size());
@@ -124,11 +130,22 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
params.flags);
+
params.obj_id = 0x0;
std::memcpy(output.data(), &params, output.size());
return 0;
}
+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();
+}
+
u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
@@ -142,11 +159,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
params.num_entries * sizeof(Tegra::CommandListHeader),
"Incorrect input size");
- std::vector<Tegra::CommandListHeader> entries(params.num_entries);
+ Tegra::CommandList entries(params.num_entries);
std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(Tegra::CommandListHeader));
- Core::System::GetInstance().GPU().ProcessCommandLists(entries);
+ PushGPUEntries(std::move(entries));
params.fence_out.id = 0;
params.fence_out.value = 0;
@@ -163,11 +180,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.address, params.num_entries, params.flags);
- std::vector<Tegra::CommandListHeader> entries(params.num_entries);
+ Tegra::CommandList entries(params.num_entries);
Memory::ReadBlock(params.address, entries.data(),
params.num_entries * sizeof(Tegra::CommandListHeader));
- Core::System::GetInstance().GPU().ProcessCommandLists(entries);
+ PushGPUEntries(std::move(entries));
params.fence_out.id = 0;
params.fence_out.value = 0;
@@ -179,6 +196,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
+
params.value = 0; // Seems to be hard coded at 0
std::memcpy(output.data(), &params, output.size());
return 0;
@@ -188,6 +206,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
IoctlChannelSetTimeout params{};
std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
+
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 46dbbc37c..f5e8ea7c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+
nvmap_fd = params.nvmap_fd;
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index c67f934f6..3e0951ab0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+
nvmap_fd = params.nvmap_fd;
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 727b9fee4..d544f0f31 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
+
nvmap_fd = params.nvmap_fd;
return 0;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 43651d8a6..1ec796fc6 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
if (!params.size) {
+ LOG_ERROR(Service_NVDRV, "Size is 0");
return static_cast<u32>(NvErrCodes::InvalidValue);
}
// Create a new nvmap object and obtain a handle to it.
@@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
if (!params.handle) {
+ LOG_ERROR(Service_NVDRV, "Handle is 0");
return static_cast<u32>(NvErrCodes::InvalidValue);
}
if ((params.align - 1) & params.align) {
+ LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
@@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
auto object = GetObject(params.handle);
if (!object) {
+ LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
if (object->status == Object::Status::Allocated) {
+ LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
}
@@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
LOG_WARNING(Service_NVDRV, "called");
if (!params.handle) {
+ LOG_ERROR(Service_NVDRV, "Handle is zero");
return static_cast<u32>(NvErrCodes::InvalidValue);
}
auto object = GetObject(params.handle);
if (!object) {
+ LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
}
@@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
auto itr = std::find_if(handles.begin(), handles.end(),
[&](const auto& entry) { return entry.second->id == params.id; });
if (itr == handles.end()) {
+ LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
auto& object = itr->second;
if (object->status != Object::Status::Allocated) {
+ LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
@@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
auto object = GetObject(params.handle);
if (!object) {
+ LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
if (object->status != Object::Status::Allocated) {
+ LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::OperationNotPermitted);
}
@@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
auto itr = handles.find(params.handle);
if (itr == handles.end()) {
+ LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
if (!itr->second->refcount) {
+ LOG_ERROR(
+ Service_NVDRV,
+ "There is no references to this object. The object is already freed. handle={:08X}",
+ params.handle);
return static_cast<u32>(NvErrCodes::InvalidValue);
}
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index ac3859353..3b9ab4b14 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -6,7 +6,9 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -55,6 +57,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
@@ -68,15 +71,15 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(query_event);
+ rb.PushCopyObjects(query_event.readable);
rb.Push<u32>(0);
}
void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
pid = rp.Pop<u64>();
-
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
@@ -84,6 +87,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NVDRV, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
+ // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
+ // retail hardware.
+ LOG_DEBUG(Service_NVDRV, "called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -97,10 +117,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{3, &NVDRV::Initialize, "Initialize"},
{4, &NVDRV::QueryEvent, "QueryEvent"},
{5, nullptr, "MapSharedMem"},
- {6, nullptr, "GetStatus"},
+ {6, &NVDRV::GetStatus, "GetStatus"},
{7, nullptr, "ForceSetClientPID"},
{8, &NVDRV::SetClientPID, "SetClientPID"},
- {9, nullptr, "DumpGraphicsMemoryInfo"},
+ {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
{11, &NVDRV::Ioctl, "Ioctl2"},
{12, nullptr, "Ioctl3"},
@@ -109,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event");
+ query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "NVDRV::query_event");
}
NVDRV::~NVDRV() = default;
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index d340893c2..fe311b069 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,10 +5,13 @@
#pragma once
#include <memory>
-#include "core/hle/kernel/event.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
+namespace Kernel {
+class WritableEvent;
+}
+
namespace Service::Nvidia {
class NVDRV final : public ServiceFramework<NVDRV> {
@@ -24,12 +27,14 @@ private:
void QueryEvent(Kernel::HLERequestContext& ctx);
void SetClientPID(Kernel::HLERequestContext& ctx);
void FinishInitialize(Kernel::HLERequestContext& ctx);
+ void GetStatus(Kernel::HLERequestContext& ctx);
+ void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
std::shared_ptr<Module> nvdrv;
u64 pid{};
- Kernel::SharedPtr<Kernel::Event> query_event;
+ Kernel::EventPair query_event;
};
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index fd98d541d..fc07d9bb8 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -7,31 +7,34 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
namespace Service::NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_wait_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
+ buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "BufferQueue NativeHandle");
}
BufferQueue::~BufferQueue() = default;
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
+ LOG_WARNING(Service, "Adding graphics buffer {}", slot);
+
Buffer buffer{};
buffer.slot = slot;
buffer.igbp_buffer = igbp_buffer;
buffer.status = Buffer::Status::Free;
- LOG_WARNING(Service, "Adding graphics buffer {}", slot);
-
queue.emplace_back(buffer);
- buffer_wait_event->Signal();
+ buffer_wait_event.writable->Signal();
}
-boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
+std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
// Only consider free buffers. Buffers become free once again after they've been Acquired
// and Released by the compositor, see the NVFlinger::Compose method.
@@ -44,7 +47,7 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
});
if (itr == queue.end()) {
- return boost::none;
+ return {};
}
itr->status = Buffer::Status::Dequeued;
@@ -70,12 +73,12 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
itr->crop_rect = crop_rect;
}
-boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() {
+std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
return buffer.status == Buffer::Status::Queued;
});
if (itr == queue.end())
- return boost::none;
+ return {};
itr->status = Buffer::Status::Acquired;
return *itr;
}
@@ -87,11 +90,12 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
ASSERT(itr->status == Buffer::Status::Acquired);
itr->status = Buffer::Status::Free;
- buffer_wait_event->Signal();
+ buffer_wait_event.writable->Signal();
}
u32 BufferQueue::Query(QueryType type) {
LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type));
+
switch (type) {
case QueryType::NativeWindowFormat:
// TODO(Subv): Use an enum for this
@@ -103,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
+Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
+ return buffer_wait_event.writable;
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
+ return buffer_wait_event.readable;
+}
+
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 50b767732..b171f256c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -4,12 +4,14 @@
#pragma once
+#include <optional>
#include <vector>
-#include <boost/optional.hpp>
+
#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/writable_event.h"
namespace CoreTiming {
struct EventType;
@@ -57,9 +59,9 @@ public:
/// Rotate source image 90 degrees clockwise
Rotate90 = 0x04,
/// Rotate source image 180 degrees
- Roate180 = 0x03,
+ Rotate180 = 0x03,
/// Rotate source image 270 degrees clockwise
- Roate270 = 0x07,
+ Rotate270 = 0x07,
};
struct Buffer {
@@ -73,11 +75,11 @@ public:
};
void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
- boost::optional<u32> DequeueBuffer(u32 width, u32 height);
+ std::optional<u32> DequeueBuffer(u32 width, u32 height);
const IGBPBuffer& RequestBuffer(u32 slot) const;
void QueueBuffer(u32 slot, BufferTransformFlags transform,
const MathUtil::Rectangle<int>& crop_rect);
- boost::optional<const Buffer&> AcquireBuffer();
+ std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
void ReleaseBuffer(u32 slot);
u32 Query(QueryType type);
@@ -85,16 +87,16 @@ public:
return id;
}
- Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const {
- return buffer_wait_event;
- }
+ Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
+
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
private:
u32 id;
u64 layer_id;
std::vector<Buffer> queue;
- Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
+ Kernel::EventPair buffer_wait_event;
};
} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index d47b6f659..05af2d593 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <boost/optional.hpp>
+#include <optional>
#include "common/alignment.h"
#include "common/assert.h"
@@ -13,6 +13,9 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
return layer.buffer_queue->GetId();
}
-Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) {
- const auto& display = GetDisplay(display_id);
- return display.vsync_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
+ return GetDisplay(display_id).vsync_event.readable;
}
std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
@@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
void NVFlinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing
- SCOPE_EXIT({ display.vsync_event->Signal(); });
+ SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
// Don't do anything for displays without layers.
if (display.layers.empty())
@@ -134,7 +136,7 @@ void NVFlinger::Compose() {
MicroProfileFlip();
- if (buffer == boost::none) {
+ if (!buffer) {
auto& system_instance = Core::System::GetInstance();
// There was no queued buffer to draw, render previous frame
@@ -143,7 +145,7 @@ void NVFlinger::Compose() {
continue;
}
- auto& igbp_buffer = buffer->igbp_buffer;
+ 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
@@ -152,10 +154,10 @@ void NVFlinger::Compose() {
ASSERT(nvdisp);
nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
- igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform,
- buffer->crop_rect);
+ igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
+ buffer->get().transform, buffer->get().crop_rect);
- buffer_queue->ReleaseBuffer(buffer->slot);
+ buffer_queue->ReleaseBuffer(buffer->get().slot);
}
}
@@ -164,7 +166,8 @@ 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::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event");
+ vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
+ fmt::format("Display VSync Event {}", id));
}
Display::~Display() = default;
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3dc69e69b..9abba555b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -10,12 +10,17 @@
#include <vector>
#include "common/common_types.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/object.h"
namespace CoreTiming {
struct EventType;
}
+namespace Kernel {
+class ReadableEvent;
+class WritableEvent;
+} // namespace Kernel
+
namespace Service::Nvidia {
class Module;
}
@@ -40,7 +45,7 @@ struct Display {
std::string name;
std::vector<Layer> layers;
- Kernel::SharedPtr<Kernel::Event> vsync_event;
+ Kernel::EventPair vsync_event;
};
class NVFlinger final {
@@ -61,7 +66,7 @@ public:
u32 GetBufferQueueId(u64 display_id, u64 layer_id);
/// Gets the vsync event for the specified display.
- Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id);
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
/// Obtains a buffer queue identified by the id.
std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index 4fd185f69..6081f41e1 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -114,29 +114,33 @@ public:
private:
void Initialize(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(RESULT_SUCCESS);
}
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
};
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCTL, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IParentalControlService>();
- LOG_DEBUG(Service_PCTL, "called");
}
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCTL, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IParentalControlService>();
- LOG_DEBUG(Service_PCTL, "called");
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 6ec35ca60..53e7da9c3 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -20,11 +20,11 @@ public:
private:
void GetBootMode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PM, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
-
- LOG_DEBUG(Service_PM, "called");
}
};
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index bbad870a2..0ba0a4076 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -61,11 +61,11 @@ public:
private:
void GetPmModule(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PSC, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IPmModule>();
-
- LOG_DEBUG(Service_PSC, "called");
}
};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a4cf45267..d25b80ab0 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -70,18 +70,14 @@
#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 {
/**
* Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
-static std::string MakeFunctionString(const char* name, const char* port_name,
- const u32* cmd_buff) {
+[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name,
+ const u32* cmd_buff) {
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
@@ -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/set/set.cpp b/src/core/hle/service/set/set.cpp
index 9e5af7839..1afc43f75 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
constexpr std::size_t pre4_0_0_max_entries = 0xF;
constexpr std::size_t post4_0_0_max_entries = 0x40;
+constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
+
LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
return available_language_codes.at(index);
}
@@ -49,38 +51,54 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- if (available_language_codes.size() > max_size)
+ if (available_language_codes.size() > max_size) {
rb.Push(static_cast<u32>(max_size));
- else
+ } else {
rb.Push(static_cast<u32>(available_language_codes.size()));
+ }
}
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
- if (available_language_codes.size() > pre4_0_0_max_entries)
+ LOG_DEBUG(Service_SET, "called");
+
+ if (available_language_codes.size() > pre4_0_0_max_entries) {
ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
- else
+ } else {
ctx.WriteBuffer(available_language_codes);
-
+ }
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
+}
- LOG_DEBUG(Service_SET, "called");
+void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto index = rp.Pop<u32>();
+
+ if (index >= available_language_codes.size()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_LANGUAGE);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushEnum(available_language_codes[index]);
}
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
- if (available_language_codes.size() > post4_0_0_max_entries)
+ LOG_DEBUG(Service_SET, "called");
+
+ if (available_language_codes.size() > post4_0_0_max_entries) {
ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
- else
+ } else {
ctx.WriteBuffer(available_language_codes);
-
+ }
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
-
- LOG_DEBUG(Service_SET, "called");
}
void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
- PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
-
LOG_DEBUG(Service_SET, "called");
+
+ PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
}
void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
@@ -90,18 +108,18 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
}
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index]));
-
- LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
+ rb.PushEnum(available_language_codes[Settings::values.language_index]);
}
SET::SET() : ServiceFramework("set") {
static const FunctionInfo functions[] = {
{0, &SET::GetLanguageCode, "GetLanguageCode"},
{1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
- {2, nullptr, "MakeLanguageCode"},
+ {2, &SET::MakeLanguageCode, "MakeLanguageCode"},
{3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
{4, nullptr, "GetRegionCode"},
{5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 266f13e46..31f9cb296 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -38,6 +38,7 @@ public:
private:
void GetLanguageCode(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
+ void MakeLanguageCode(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 41efca31c..c9b4da5b0 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -10,22 +10,22 @@
namespace Service::Set {
void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.PushEnum(color_set);
-
- LOG_DEBUG(Service_SET, "called");
}
void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "called");
+
IPC::RequestParser rp{ctx};
color_set = rp.PopEnum<ColorSet>();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
-
- LOG_DEBUG(Service_SET, "called");
}
SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 98f6e4111..74da4d5e6 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -14,25 +14,26 @@ namespace Service::SM {
void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
+ LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
ctx.Session()->ConvertToDomain();
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1); // Converted sessions start with 1 request handler
-
- LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
}
void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
// TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
// and that we probably want to actually make an entirely new Session, but we still need to
// verify this on hardware.
+ LOG_DEBUG(Service, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(RESULT_SUCCESS);
Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client};
rb.PushMoveObjects(session);
- LOG_DEBUG(Service, "called, session={}", session->GetObjectId());
+ LOG_DEBUG(Service, "session={}", session->GetObjectId());
}
void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
@@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
}
void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u16>(0x500);
-
- LOG_WARNING(Service, "(STUBBED) called");
}
Controller::Controller() : ServiceFramework("IpcController") {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 464e79d01..142929124 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -54,13 +54,22 @@ 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) {
+ CASCADE_CODE(ValidateServiceName(name));
+
+ const auto iter = registered_services.find(name);
+ if (iter == registered_services.end())
+ return ERR_SERVICE_NOT_REGISTERED;
+
+ registered_services.erase(iter);
+ return RESULT_SUCCESS;
}
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
@@ -72,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(
@@ -92,9 +101,10 @@ SM::~SM() = default;
* 0: ResultCode
*/
void SM::Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SM, "called");
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_SM, "called");
}
void SM::GetService(Kernel::HLERequestContext& ctx) {
@@ -127,13 +137,54 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
}
}
+void SM::RegisterService(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto name_buf = rp.PopRaw<std::array<char, 8>>();
+ const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
+
+ const std::string name(name_buf.begin(), end);
+
+ const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
+ const auto max_session_count = rp.PopRaw<u32>();
+
+ LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
+ max_session_count, is_light);
+
+ 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);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(handle.Code());
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+ rb.Push(handle.Code());
+ rb.PushMoveObjects(std::move(handle).Unwrap());
+}
+
+void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto name_buf = rp.PopRaw<std::array<char, 8>>();
+ const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
+
+ const std::string name(name_buf.begin(), end);
+ LOG_DEBUG(Service_SM, "called with name={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(service_manager->UnregisterService(name));
+}
+
SM::SM(std::shared_ptr<ServiceManager> service_manager)
: ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
static const FunctionInfo functions[] = {
{0x00000000, &SM::Initialize, "Initialize"},
{0x00000001, &SM::GetService, "GetService"},
- {0x00000002, nullptr, "RegisterService"},
- {0x00000003, nullptr, "UnregisterService"},
+ {0x00000002, &SM::RegisterService, "RegisterService"},
+ {0x00000003, &SM::UnregisterService, "UnregisterService"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 4f8145dda..bef25433e 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -35,6 +35,8 @@ public:
private:
void Initialize(Kernel::HLERequestContext& ctx);
void GetService(Kernel::HLERequestContext& ctx);
+ void RegisterService(Kernel::HLERequestContext& ctx);
+ void UnregisterService(Kernel::HLERequestContext& ctx);
std::shared_ptr<ServiceManager> service_manager;
};
@@ -48,6 +50,7 @@ public:
ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
+ ResultCode UnregisterService(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 44a6717d0..8db0c2f13 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -3,34 +3,41 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <chrono>
#include <cstdlib>
+#include <ctime>
+#include <functional>
#include <vector>
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/module.h"
#include "core/hle/service/spl/spl.h"
+#include "core/settings.h"
namespace Service::SPL {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
- : ServiceFramework(name), module(std::move(module)) {}
+ : ServiceFramework(name), module(std::move(module)),
+ rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SPL, "called");
+
IPC::RequestParser rp{ctx};
std::size_t size = ctx.GetWriteBufferSize();
+ std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
std::vector<u8> data(size);
- std::generate(data.begin(), data.end(), std::rand);
+ std::generate(data.begin(), data.end(), [&] { return static_cast<u8>(distribution(rng)); });
ctx.WriteBuffer(data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
- LOG_DEBUG(Service_SPL, "called");
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 48fda6099..afa1f0295 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -4,6 +4,7 @@
#pragma once
+#include <random>
#include "core/hle/service/service.h"
namespace Service::SPL {
@@ -19,6 +20,9 @@ public:
protected:
std::shared_ptr<Module> module;
+
+ private:
+ std::mt19937 rng;
};
};
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index bc4f7a437..af40a1815 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -69,6 +69,7 @@ public:
private:
void SetOption(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
+
IPC::RequestParser rp{ctx};
IPC::ResponseBuilder rb{ctx, 2};
@@ -114,6 +115,7 @@ private:
void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SSL, "called");
+
IPC::RequestParser rp{ctx};
ssl_version = rp.Pop<u32>();
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 18a5d71d5..b3a196f65 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,9 +21,10 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
- {400, nullptr, "GetClockSnapshot"},
+ {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
- {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
+ {500, &Time::CalculateStandardUserSystemClockDifferenceByUser,
+ "CalculateStandardUserSystemClockDifferenceByUser"},
{501, nullptr, "CalculateSpanBetween"},
};
RegisterHandlers(functions);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 28fd8debc..16564de24 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -15,6 +15,44 @@
namespace Service::Time {
+static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
+ CalendarAdditionalInfo& additional_info,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ const std::time_t time(posix_time);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ calendar_time = {};
+ additional_info = {};
+ return;
+ }
+ 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;
+
+ additional_info.day_of_week = tm->tm_wday;
+ additional_info.day_of_year = tm->tm_yday;
+ std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
+ additional_info.utc_offset = 0;
+}
+
+static u64 CalendarToPosix(const CalendarTime& calendar_time,
+ [[maybe_unused]] const TimeZoneRule& /*rule*/) {
+ std::tm time{};
+ time.tm_year = calendar_time.year - 1900;
+ time.tm_mon = calendar_time.month - 1;
+ time.tm_mday = calendar_time.day;
+
+ time.tm_hour = calendar_time.hour;
+ time.tm_min = calendar_time.minute;
+ time.tm_sec = calendar_time.second;
+
+ std::time_t epoch_time = std::mktime(&time);
+ return static_cast<u64>(epoch_time);
+}
+
class ISystemClock final : public ServiceFramework<ISystemClock> {
public:
ISystemClock() : ServiceFramework("ISystemClock") {
@@ -34,6 +72,7 @@ private:
std::chrono::system_clock::now().time_since_epoch())
.count()};
LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(time_since_epoch);
@@ -41,6 +80,7 @@ private:
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Time, "(STUBBED) called");
+
SystemClockContext system_clock_ontext{};
IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
rb.Push(RESULT_SUCCESS);
@@ -60,6 +100,7 @@ public:
private:
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
+
SteadyClockTimePoint steady_clock_time_point{
CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
@@ -80,8 +121,8 @@ public:
{5, nullptr, "GetTimeZoneRuleVersion"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
- {201, nullptr, "ToPosixTime"},
- {202, nullptr, "ToPosixTimeWithMyRule"},
+ {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
+ {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
};
RegisterHandlers(functions);
}
@@ -92,6 +133,7 @@ private:
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
rb.Push(RESULT_SUCCESS);
rb.PushRaw(location_name);
@@ -99,6 +141,7 @@ private:
void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Time, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0);
@@ -116,7 +159,6 @@ private:
void ToCalendarTime(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 posix_time = rp.Pop<u64>();
-
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
TimeZoneRule time_zone_rule{};
@@ -137,7 +179,6 @@ private:
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 posix_time = rp.Pop<u64>();
-
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
@@ -151,60 +192,139 @@ private:
rb.PushRaw(additional_info);
}
- void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
- CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) {
- std::time_t t(posix_time);
- std::tm* tm = std::localtime(&t);
- if (!tm) {
- return;
- }
- 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;
-
- additional_info.day_of_week = tm->tm_wday;
- additional_info.day_of_year = tm->tm_yday;
- std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
- additional_info.utc_offset = 0;
+ void ToPosixTime(Kernel::HLERequestContext& ctx) {
+ // TODO(ogniK): Figure out how to handle multiple times
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
+ }
+
+ void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Time, "(STUBBED) called");
+
+ IPC::RequestParser rp{ctx};
+ auto calendar_time = rp.PopRaw<CalendarTime>();
+ auto posix_time = CalendarToPosix(calendar_time, {});
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u32>(1); // Amount of times we're returning
+ ctx.WriteBuffer(&posix_time, sizeof(u64));
}
};
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
- LOG_DEBUG(Service_Time, "called");
}
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
- LOG_DEBUG(Service_Time, "called");
}
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>();
- LOG_DEBUG(Service_Time, "called");
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>();
- LOG_DEBUG(Service_Time, "called");
}
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>();
+}
+
+void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
+
+ IPC::RequestParser rp{ctx};
+ 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()};
+
+ const std::time_t time(time_since_epoch);
+ const std::tm* tm = std::localtime(&time);
+ if (tm == nullptr) {
+ LOG_ERROR(Service_Time, "tm is a nullptr");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
+ return;
+ }
+
+ 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;
+ clock_snapshot.network_calendar_time = calendar_time;
+
+ CalendarAdditionalInfo additional_info{};
+ PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
+
+ clock_snapshot.system_calendar_info = additional_info;
+ clock_snapshot.network_calendar_info = additional_info;
+
+ clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
+ clock_snapshot.location_name = LocationName{"UTC"};
+ clock_snapshot.clock_auto_adjustment_enabled = 1;
+ clock_snapshot.type = initial_type;
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
+}
+
+void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
+ Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ IPC::RequestParser rp{ctx};
+ const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
+ const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
+ const u64 difference =
+ snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushRaw<u64>(difference);
}
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 5659ecad3..f11affe95 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include "common/common_funcs.h"
#include "core/hle/service/service.h"
namespace Service::Time {
@@ -21,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");
@@ -29,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,
@@ -41,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");
@@ -53,6 +55,24 @@ struct SystemClockContext {
static_assert(sizeof(SystemClockContext) == 0x20,
"SystemClockContext structure has incorrect size");
+struct ClockSnapshot {
+ SystemClockContext user_clock_context;
+ SystemClockContext network_clock_context;
+ s64_le system_posix_time;
+ s64_le network_posix_time;
+ CalendarTime system_calendar_time;
+ CalendarTime network_calendar_time;
+ CalendarAdditionalInfo system_calendar_info;
+ CalendarAdditionalInfo network_calendar_info;
+ SteadyClockTimePoint steady_clock_timepoint;
+ LocationName location_name;
+ u8 clock_auto_adjustment_enabled;
+ u8 type;
+ u8 version;
+ INSERT_PADDING_BYTES(1);
+};
+static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
+
class Module final {
public:
class Interface : public ServiceFramework<Interface> {
@@ -65,6 +85,8 @@ public:
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
+ void GetClockSnapshot(Kernel::HLERequestContext& ctx);
+ void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> time;
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index c489da071..58a9845fc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -73,7 +73,7 @@ public:
{3, nullptr, "Populate"},
{4, nullptr, "PostBufferAsync"},
{5, nullptr, "GetXferReport"},
- {6, nullptr, "Unknown2"},
+ {6, nullptr, "PostBufferMultiAsync"},
{7, nullptr, "Unknown3"},
{8, nullptr, "Unknown4"},
};
@@ -132,11 +132,11 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "BindNoticeEvent"},
- {1, nullptr, "Unknown1"},
+ {1, nullptr, "UnbindNoticeEvent"},
{2, nullptr, "GetStatus"},
{3, nullptr, "GetNotice"},
- {4, nullptr, "Unknown2"},
- {5, nullptr, "Unknown3"},
+ {4, nullptr, "EnablePowerRequestNotice"},
+ {5, nullptr, "DisablePowerRequestNotice"},
{6, nullptr, "ReplyPowerRequest"},
};
// clang-format on
@@ -159,11 +159,11 @@ public:
private:
void GetPdSession(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_USB, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IPdSession>();
-
- LOG_DEBUG(Service_USB, "called");
}
};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 184537daa..a3b8cec72 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -6,9 +6,10 @@
#include <array>
#include <cstring>
#include <memory>
+#include <optional>
#include <type_traits>
#include <utility>
-#include <boost/optional.hpp>
+
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_funcs.h"
@@ -17,7 +18,9 @@
#include "common/swap.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.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"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -236,6 +239,22 @@ private:
Data data{};
};
+/// Represents a parcel containing one int '0' as its data
+/// Used by DetachBuffer and Disconnect
+class IGBPEmptyResponseParcel : public Parcel {
+protected:
+ void SerializeData() override {
+ Write(data);
+ }
+
+private:
+ struct Data {
+ u32_le unk_0;
+ };
+
+ Data data{};
+};
+
class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
public:
explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
@@ -484,16 +503,22 @@ 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>();
- auto buffer_queue = nv_flinger->GetBufferQueue(id);
+ 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, transaction={:X}", static_cast<u32>(transaction));
+ 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);
if (transaction == TransactionId::Connect) {
IGBPConnectRequestParcel request{ctx.ReadBuffer()};
- IGBPConnectResponseParcel response{1280, 720};
+ IGBPConnectResponseParcel response{
+ static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
+ Settings::values.resolution_factor),
+ static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
+ Settings::values.resolution_factor)};
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::SetPreallocatedBuffer) {
IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
@@ -506,9 +531,9 @@ private:
IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
const u32 width{request.data.width};
const u32 height{request.data.height};
- boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
- if (slot != boost::none) {
+ if (slot) {
// Buffer is available
IGBPDequeueBufferResponseParcel response{*slot};
ctx.WriteBuffer(response.Serialize());
@@ -520,13 +545,15 @@ private:
Kernel::ThreadWakeupReason reason) {
// Repeat TransactParcel DequeueBuffer when a buffer is available
auto buffer_queue = nv_flinger->GetBufferQueue(id);
- boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
+
IGBPDequeueBufferResponseParcel response{*slot};
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
},
- buffer_queue->GetBufferWaitEvent());
+ buffer_queue->GetWritableBufferWaitEvent());
}
} else if (transaction == TransactionId::RequestBuffer) {
IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
@@ -553,6 +580,12 @@ private:
ctx.WriteBuffer(response.Serialize());
} else if (transaction == TransactionId::CancelBuffer) {
LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
+ } else if (transaction == TransactionId::Disconnect ||
+ transaction == TransactionId::DetachBuffer) {
+ const auto buffer = ctx.ReadBuffer();
+
+ IGBPEmptyResponseParcel response{};
+ ctx.WriteBuffer(response.Serialize());
} else {
ASSERT_MSG(false, "Unimplemented");
}
@@ -563,26 +596,27 @@ 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);
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
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>();
- auto buffer_queue = nv_flinger->GetBufferQueue(id);
+ LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
- // TODO(Subv): Find out what this actually is.
+ const auto buffer_queue = nv_flinger->GetBufferQueue(id);
- LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
+ // TODO(Subv): Find out what this actually is.
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
@@ -645,10 +679,12 @@ 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);
@@ -656,30 +692,36 @@ private:
void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u64 layer_id = rp.Pop<u64>();
- bool visibility = rp.Pop<bool>();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ const u64 layer_id = rp.Pop<u64>();
+ const bool visibility = rp.Pop<bool>();
+
LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
visibility);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
}
void GetDisplayMode(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_VI, "(STUBBED) called");
+
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
+ static_cast<u32>(Settings::values.resolution_factor));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
+ static_cast<u32>(Settings::values.resolution_factor));
} else {
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
- rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
+ static_cast<u32>(Settings::values.resolution_factor));
+ rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
+ static_cast<u32>(Settings::values.resolution_factor));
}
- rb.PushRaw<float>(60.0f);
+ rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
rb.Push<u32>(0);
-
- LOG_DEBUG(Service_VI, "called");
}
};
@@ -761,23 +803,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>();
+
+ LOG_WARNING(Service_VI,
+ "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
+ unknown, display, aruid);
- u64 layer_id = nv_flinger->CreateLayer(display);
+ const u64 layer_id = nv_flinger->CreateLayer(display);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -785,10 +831,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);
@@ -796,12 +844,14 @@ private:
void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u64 layer_id = rp.Pop<u64>();
- bool visibility = rp.Pop<bool>();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
+ 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);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
}
std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
@@ -847,11 +897,25 @@ private:
void OpenDisplay(Kernel::HLERequestContext& ctx) {
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>>();
- std::string name(name_buf.begin(), end);
+ OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()});
+ }
+
+ void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_VI, "called");
+
+ 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");
@@ -861,64 +925,85 @@ 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);
+ }
+
+ // 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) {
- 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, 6};
rb.Push(RESULT_SUCCESS);
if (Settings::values.use_docked_mode) {
- rb.Push(static_cast<u64>(DisplayResolution::DockedWidth));
- rb.Push(static_cast<u64>(DisplayResolution::DockedHeight));
+ 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));
- rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
+ 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 u32 scaling_mode = rp.Pop<u32>();
+ const u64 unknown = rp.Pop<u64>();
+
+ LOG_WARNING(Service_VI, "(STUBBED) called. scaling_mode=0x{:08X}, unknown=0x{:016X}",
+ scaling_mode, unknown);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void ListDisplays(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_VI, "(STUBBED) called");
+
IPC::RequestParser rp{ctx};
DisplayInfo display_info;
+ display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
+ display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(1);
- LOG_WARNING(Service_VI, "(STUBBED) called");
}
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};
@@ -927,17 +1012,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};
@@ -947,21 +1032,22 @@ 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);
@@ -1030,9 +1116,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"},