summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp2
-rw-r--r--src/core/file_sys/archive_sdmc.cpp2
-rw-r--r--src/core/file_sys/archive_sdmcwriteonly.cpp2
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.cpp2
-rw-r--r--src/core/frontend/emu_window.cpp52
-rw-r--r--src/core/frontend/emu_window.h54
-rw-r--r--src/core/frontend/input.h110
-rw-r--r--src/core/frontend/key_map.cpp152
-rw-r--r--src/core/frontend/key_map.h93
-rw-r--r--src/core/hle/function_wrappers.h4
-rw-r--r--src/core/hle/ipc.h7
-rw-r--r--src/core/hle/ipc_helpers.h170
-rw-r--r--src/core/hle/service/apt/apt.cpp444
-rw-r--r--src/core/hle/service/cfg/cfg.cpp31
-rw-r--r--src/core/hle/service/hid/hid.cpp56
-rw-r--r--src/core/hle/service/hid/hid.h37
-rw-r--r--src/core/hle/service/ptm/ptm.cpp14
-rw-r--r--src/core/hle/service/ptm/ptm.h2
-rw-r--r--src/core/hle/service/soc_u.cpp71
-rw-r--r--src/core/hle/service/y2r_u.cpp8
-rw-r--r--src/core/hle/shared_page.cpp7
-rw-r--r--src/core/hle/shared_page.h10
-rw-r--r--src/core/hle/svc.cpp24
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/loader/ncch.cpp9
-rw-r--r--src/core/settings.cpp3
-rw-r--r--src/core/settings.h90
28 files changed, 726 insertions, 735 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ffd67f074..61a0b1cc3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -34,7 +34,6 @@ set(SRCS
frontend/camera/factory.cpp
frontend/camera/interface.cpp
frontend/emu_window.cpp
- frontend/key_map.cpp
frontend/motion_emu.cpp
gdbstub/gdbstub.cpp
hle/config_mem.cpp
@@ -218,7 +217,7 @@ set(HEADERS
frontend/camera/factory.h
frontend/camera/interface.h
frontend/emu_window.h
- frontend/key_map.h
+ frontend/input.h
frontend/motion_emu.h
gdbstub/gdbstub.h
hle/config_mem.h
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index dd2fb167f..f454e7840 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -173,7 +173,7 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location,
bool shared)
: shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) {
- LOG_INFO(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
+ LOG_DEBUG(Service_FS, "Directory %s set as base for ExtSaveData.", mount_point.c_str());
}
bool ArchiveFactory_ExtSaveData::Initialize() {
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 72ff05c65..679909d06 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -306,7 +306,7 @@ u64 SDMCArchive::GetFreeBytes() const {
ArchiveFactory_SDMC::ArchiveFactory_SDMC(const std::string& sdmc_directory)
: sdmc_directory(sdmc_directory) {
- LOG_INFO(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str());
+ LOG_DEBUG(Service_FS, "Directory %s set as SDMC.", sdmc_directory.c_str());
}
bool ArchiveFactory_SDMC::Initialize() {
diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp
index 2aafc9b1d..244aef48a 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.cpp
+++ b/src/core/file_sys/archive_sdmcwriteonly.cpp
@@ -32,7 +32,7 @@ ResultVal<std::unique_ptr<DirectoryBackend>> SDMCWriteOnlyArchive::OpenDirectory
ArchiveFactory_SDMCWriteOnly::ArchiveFactory_SDMCWriteOnly(const std::string& mount_point)
: sdmc_directory(mount_point) {
- LOG_INFO(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str());
+ LOG_DEBUG(Service_FS, "Directory %s set as SDMCWriteOnly.", sdmc_directory.c_str());
}
bool ArchiveFactory_SDMCWriteOnly::Initialize() {
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp
index e01357891..f31a68038 100644
--- a/src/core/file_sys/archive_source_sd_savedata.cpp
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -39,7 +39,7 @@ std::string GetSaveDataMetadataPath(const std::string& mount_location, u64 progr
ArchiveSource_SDSaveData::ArchiveSource_SDSaveData(const std::string& sdmc_directory)
: mount_point(GetSaveDataContainerPath(sdmc_directory)) {
- LOG_INFO(Service_FS, "Directory %s set as SaveData.", mount_point.c_str());
+ LOG_DEBUG(Service_FS, "Directory %s set as SaveData.", mount_point.c_str());
}
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveSource_SDSaveData::Open(u64 program_id) {
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index a155b657d..5fdb3a7e8 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -7,33 +7,9 @@
#include "common/assert.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
-#include "core/frontend/key_map.h"
+#include "core/settings.h"
#include "video_core/video_core.h"
-void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
- pad_state.hex |= pad.hex;
-}
-
-void EmuWindow::ButtonReleased(Service::HID::PadState pad) {
- pad_state.hex &= ~pad.hex;
-}
-
-void EmuWindow::CirclePadUpdated(float x, float y) {
- constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
-
- // Make sure the coordinates are in the unit circle,
- // otherwise normalize it.
- float r = x * x + y * y;
- if (r > 1) {
- r = std::sqrt(r);
- x /= r;
- y /= r;
- }
-
- circle_pad_x = static_cast<s16>(x * MAX_CIRCLEPAD_POS);
- circle_pad_y = static_cast<s16>(y * MAX_CIRCLEPAD_POS);
-}
-
/**
* Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout
* @param layout FramebufferLayout object describing the framebuffer size and screen positions
@@ -113,17 +89,21 @@ void EmuWindow::GyroscopeChanged(float x, float y, float z) {
void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
Layout::FramebufferLayout layout;
- switch (Settings::values.layout_option) {
- case Settings::LayoutOption::SingleScreen:
- layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
- break;
- case Settings::LayoutOption::LargeScreen:
- layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
- break;
- case Settings::LayoutOption::Default:
- default:
- layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
- break;
+ if (Settings::values.custom_layout == true) {
+ layout = Layout::CustomFrameLayout(width, height);
+ } else {
+ switch (Settings::values.layout_option) {
+ case Settings::LayoutOption::SingleScreen:
+ layout = Layout::SingleFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ case Settings::LayoutOption::LargeScreen:
+ layout = Layout::LargeFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ case Settings::LayoutOption::Default:
+ default:
+ layout = Layout::DefaultFrameLayout(width, height, Settings::values.swap_screen);
+ break;
+ }
}
NotifyFramebufferLayoutChanged(layout);
}
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 1ba64c92b..36f2667fa 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -10,7 +10,6 @@
#include "common/common_types.h"
#include "common/framebuffer_layout.h"
#include "common/math_util.h"
-#include "core/hle/service/hid/hid.h"
/**
* Abstraction class used to provide an interface between emulation code and the frontend
@@ -52,30 +51,6 @@ public:
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
virtual void DoneCurrent() = 0;
- virtual void ReloadSetKeymaps() = 0;
-
- /**
- * Signals a button press action to the HID module.
- * @param pad_state indicates which button to press
- * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
- */
- void ButtonPressed(Service::HID::PadState pad_state);
-
- /**
- * Signals a button release action to the HID module.
- * @param pad_state indicates which button to press
- * @note only handles real buttons (A/B/X/Y/...), excluding analog inputs like the circle pad.
- */
- void ButtonReleased(Service::HID::PadState pad_state);
-
- /**
- * Signals a circle pad change action to the HID module.
- * @param x new x-coordinate of the circle pad, in the range [-1.0, 1.0]
- * @param y new y-coordinate of the circle pad, in the range [-1.0, 1.0]
- * @note the coordinates will be normalized if the radius is larger than 1
- */
- void CirclePadUpdated(float x, float y);
-
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
* @param framebuffer_x Framebuffer x-coordinate that was pressed
@@ -115,27 +90,6 @@ public:
void GyroscopeChanged(float x, float y, float z);
/**
- * Gets the current pad state (which buttons are pressed).
- * @note This should be called by the core emu thread to get a state set by the window thread.
- * @note This doesn't include analog input like circle pad direction
- * @todo Fix this function to be thread-safe.
- * @return PadState object indicating the current pad state
- */
- Service::HID::PadState GetPadState() const {
- return pad_state;
- }
-
- /**
- * Gets the current circle pad state.
- * @note This should be called by the core emu thread to get a state set by the window thread.
- * @todo Fix this function to be thread-safe.
- * @return std::tuple of (x, y), where `x` and `y` are the circle pad coordinates
- */
- std::tuple<s16, s16> GetCirclePadState() const {
- return std::make_tuple(circle_pad_x, circle_pad_y);
- }
-
- /**
* Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed).
* @note This should be called by the core emu thread to get a state set by the window thread.
* @todo Fix this function to be thread-safe.
@@ -230,11 +184,8 @@ protected:
// TODO: Find a better place to set this.
config.min_client_area_size = std::make_pair(400u, 480u);
active_config = config;
- pad_state.hex = 0;
touch_x = 0;
touch_y = 0;
- circle_pad_x = 0;
- circle_pad_y = 0;
touch_pressed = false;
accel_x = 0;
accel_y = -512;
@@ -304,9 +255,6 @@ private:
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
- s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
- s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
-
std::mutex accel_mutex;
s16 accel_x; ///< Accelerometer X-axis value in native 3DS units
s16 accel_y; ///< Accelerometer Y-axis value in native 3DS units
@@ -321,6 +269,4 @@ private:
* Clip the provided coordinates to be inside the touchscreen area.
*/
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
-
- Service::HID::PadState pad_state;
};
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
new file mode 100644
index 000000000..0a5713dc0
--- /dev/null
+++ b/src/core/frontend/input.h
@@ -0,0 +1,110 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <utility>
+#include "common/logging/log.h"
+#include "common/param_package.h"
+
+namespace Input {
+
+/// An abstract class template for an input device (a button, an analog input, etc.).
+template <typename StatusType>
+class InputDevice {
+public:
+ virtual ~InputDevice() = default;
+ virtual StatusType GetStatus() const {
+ return {};
+ }
+};
+
+/// An abstract class template for a factory that can create input devices.
+template <typename InputDeviceType>
+class Factory {
+public:
+ virtual ~Factory() = default;
+ virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
+};
+
+namespace Impl {
+
+template <typename InputDeviceType>
+using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
+
+template <typename InputDeviceType>
+struct FactoryList {
+ static FactoryListType<InputDeviceType> list;
+};
+
+template <typename InputDeviceType>
+FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
+
+} // namespace Impl
+
+/**
+ * Registers an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory. Will be used to match the "engine" parameter when creating
+ * a device
+ * @param factory the factory object to register
+ */
+template <typename InputDeviceType>
+void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
+ auto pair = std::make_pair(name, std::move(factory));
+ if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
+ LOG_ERROR(Input, "Factory %s already registered", name.c_str());
+ }
+}
+
+/**
+ * Unregisters an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory to unregister
+ */
+template <typename InputDeviceType>
+void UnregisterFactory(const std::string& name) {
+ if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
+ LOG_ERROR(Input, "Factory %s not registered", name.c_str());
+ }
+}
+
+/**
+ * Create an input device from given paramters.
+ * @tparam InputDeviceType the type of input devices to create
+ * @param params a serialized ParamPackage string contains all parameters for creating the device
+ */
+template <typename InputDeviceType>
+std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
+ const Common::ParamPackage package(params);
+ const std::string engine = package.Get("engine", "null");
+ const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
+ const auto pair = factory_list.find(engine);
+ if (pair == factory_list.end()) {
+ if (engine != "null") {
+ LOG_ERROR(Input, "Unknown engine name: %s", engine.c_str());
+ }
+ return std::make_unique<InputDeviceType>();
+ }
+ return pair->second->Create(package);
+}
+
+/**
+ * A button device is an input device that returns bool as status.
+ * true for pressed; false for released.
+ */
+using ButtonDevice = InputDevice<bool>;
+
+/**
+ * An analog device is an input device that returns a tuple of x and y coordinates as status. The
+ * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up
+ * direction
+ */
+using AnalogDevice = InputDevice<std::tuple<float, float>>;
+
+} // namespace Input
diff --git a/src/core/frontend/key_map.cpp b/src/core/frontend/key_map.cpp
deleted file mode 100644
index 15f0e079c..000000000
--- a/src/core/frontend/key_map.cpp
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <map>
-#include "core/frontend/emu_window.h"
-#include "core/frontend/key_map.h"
-
-namespace KeyMap {
-
-// TODO (wwylele): currently we treat c-stick as four direction buttons
-// and map it directly to EmuWindow::ButtonPressed.
-// It should go the analog input way like circle pad does.
-const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
- Service::HID::PAD_A,
- Service::HID::PAD_B,
- Service::HID::PAD_X,
- Service::HID::PAD_Y,
- Service::HID::PAD_L,
- Service::HID::PAD_R,
- Service::HID::PAD_ZL,
- Service::HID::PAD_ZR,
- Service::HID::PAD_START,
- Service::HID::PAD_SELECT,
- Service::HID::PAD_NONE,
- Service::HID::PAD_UP,
- Service::HID::PAD_DOWN,
- Service::HID::PAD_LEFT,
- Service::HID::PAD_RIGHT,
- Service::HID::PAD_C_UP,
- Service::HID::PAD_C_DOWN,
- Service::HID::PAD_C_LEFT,
- Service::HID::PAD_C_RIGHT,
-
- IndirectTarget::CirclePadUp,
- IndirectTarget::CirclePadDown,
- IndirectTarget::CirclePadLeft,
- IndirectTarget::CirclePadRight,
- IndirectTarget::CirclePadModifier,
-}};
-
-static std::map<HostDeviceKey, KeyTarget> key_map;
-static int next_device_id = 0;
-
-static bool circle_pad_up = false;
-static bool circle_pad_down = false;
-static bool circle_pad_left = false;
-static bool circle_pad_right = false;
-static bool circle_pad_modifier = false;
-
-static void UpdateCirclePad(EmuWindow& emu_window) {
- constexpr float SQRT_HALF = 0.707106781f;
- int x = 0, y = 0;
-
- if (circle_pad_right)
- ++x;
- if (circle_pad_left)
- --x;
- if (circle_pad_up)
- ++y;
- if (circle_pad_down)
- --y;
-
- float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0f;
- emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0f : SQRT_HALF),
- y * modifier * (x == 0 ? 1.0f : SQRT_HALF));
-}
-
-int NewDeviceId() {
- return next_device_id++;
-}
-
-void SetKeyMapping(HostDeviceKey key, KeyTarget target) {
- key_map[key] = target;
-}
-
-void ClearKeyMapping(int device_id) {
- auto iter = key_map.begin();
- while (iter != key_map.end()) {
- if (iter->first.device_id == device_id)
- key_map.erase(iter++);
- else
- ++iter;
- }
-}
-
-void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
- auto target = key_map.find(key);
- if (target == key_map.end())
- return;
-
- if (target->second.direct) {
- emu_window.ButtonPressed({{target->second.target.direct_target_hex}});
- } else {
- switch (target->second.target.indirect_target) {
- case IndirectTarget::CirclePadUp:
- circle_pad_up = true;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadDown:
- circle_pad_down = true;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadLeft:
- circle_pad_left = true;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadRight:
- circle_pad_right = true;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadModifier:
- circle_pad_modifier = true;
- UpdateCirclePad(emu_window);
- break;
- }
- }
-}
-
-void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) {
- auto target = key_map.find(key);
- if (target == key_map.end())
- return;
-
- if (target->second.direct) {
- emu_window.ButtonReleased({{target->second.target.direct_target_hex}});
- } else {
- switch (target->second.target.indirect_target) {
- case IndirectTarget::CirclePadUp:
- circle_pad_up = false;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadDown:
- circle_pad_down = false;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadLeft:
- circle_pad_left = false;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadRight:
- circle_pad_right = false;
- UpdateCirclePad(emu_window);
- break;
- case IndirectTarget::CirclePadModifier:
- circle_pad_modifier = false;
- UpdateCirclePad(emu_window);
- break;
- }
- }
-}
-}
diff --git a/src/core/frontend/key_map.h b/src/core/frontend/key_map.h
deleted file mode 100644
index 040794578..000000000
--- a/src/core/frontend/key_map.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <array>
-#include <tuple>
-#include "core/hle/service/hid/hid.h"
-
-class EmuWindow;
-
-namespace KeyMap {
-
-/**
- * Represents key mapping targets that are not real 3DS buttons.
- * They will be handled by KeyMap and translated to 3DS input.
- */
-enum class IndirectTarget {
- CirclePadUp,
- CirclePadDown,
- CirclePadLeft,
- CirclePadRight,
- CirclePadModifier,
-};
-
-/**
- * Represents a key mapping target. It can be a PadState that represents real 3DS buttons,
- * or an IndirectTarget.
- */
-struct KeyTarget {
- bool direct;
- union {
- u32 direct_target_hex;
- IndirectTarget indirect_target;
- } target;
-
- KeyTarget() : direct(true) {
- target.direct_target_hex = 0;
- }
-
- KeyTarget(Service::HID::PadState pad) : direct(true) {
- target.direct_target_hex = pad.hex;
- }
-
- KeyTarget(IndirectTarget i) : direct(false) {
- target.indirect_target = i;
- }
-};
-
-/**
- * Represents a key for a specific host device.
- */
-struct HostDeviceKey {
- int key_code;
- int device_id; ///< Uniquely identifies a host device
-
- bool operator<(const HostDeviceKey& other) const {
- return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id);
- }
-
- bool operator==(const HostDeviceKey& other) const {
- return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id);
- }
-};
-
-extern const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets;
-
-/**
- * Generates a new device id, which uniquely identifies a host device within KeyMap.
- */
-int NewDeviceId();
-
-/**
- * Maps a device-specific key to a target (a PadState or an IndirectTarget).
- */
-void SetKeyMapping(HostDeviceKey key, KeyTarget target);
-
-/**
- * Clears all key mappings belonging to one device.
- */
-void ClearKeyMapping(int device_id);
-
-/**
- * Maps a key press action and call the corresponding function in EmuWindow
- */
-void PressKey(EmuWindow& emu_window, HostDeviceKey key);
-
-/**
- * Maps a key release action and call the corresponding function in EmuWindow
- */
-void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
-}
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 7875971ce..f6eb900f0 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -256,9 +256,9 @@ void Wrap() {
func(((s64)PARAM(1) << 32) | PARAM(0));
}
-template <void func(const char*)>
+template <void func(const char*, int len)>
void Wrap() {
- func((char*)Memory::GetPointer(PARAM(0)));
+ func((char*)Memory::GetPointer(PARAM(0)), PARAM(1));
}
template <void func(u8)>
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index cd9a5863d..3a5d481a5 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -10,7 +10,8 @@
namespace Kernel {
-static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
+/// Offset into command buffer of header
+static const int kCommandHeaderOffset = 0x80;
/**
* Returns a pointer to the command buffer in the current thread's TLS
@@ -26,8 +27,8 @@ inline u32* GetCommandBuffer(const int offset = 0) {
offset);
}
-static const int kStaticBuffersOffset =
- 0x100; ///< Offset into static buffers, relative to command buffer header
+/// Offset into static buffers, relative to command buffer header
+static const int kStaticBuffersOffset = 0x100;
/**
* Returns a pointer to the static buffers area in the current thread's TLS
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 323158bb5..06c4c5a85 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -27,6 +27,24 @@ public:
DEBUG_ASSERT_MSG(index == TotalSize(), "Operations do not match the header (cmd 0x%x)",
header.raw);
}
+
+ void Skip(unsigned size_in_words, bool set_to_null) {
+ if (set_to_null)
+ memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
+ index += size_in_words;
+ }
+
+ /**
+ * @brief Retrieves the address of a static buffer, used when a buffer is needed for output
+ * @param buffer_id The index of the static buffer
+ * @param data_size If non-null, will store the size of the buffer
+ */
+ VAddr PeekStaticBuffer(u8 buffer_id, size_t* data_size = nullptr) const {
+ u32* static_buffer = cmdbuf + Kernel::kStaticBuffersOffset / sizeof(u32) + buffer_id * 2;
+ if (data_size)
+ *data_size = StaticBufferDescInfo{static_buffer[0]}.size;
+ return static_buffer[1];
+ }
};
class RequestBuilder : public RequestHelperBase {
@@ -50,14 +68,8 @@ public:
template <typename T>
void Push(T value);
- void Push(u32 value) {
- cmdbuf[index++] = value;
- }
template <typename First, typename... Other>
- void Push(const First& first_value, const Other&... other_values) {
- Push(first_value);
- Push(other_values...);
- }
+ void Push(const First& first_value, const Other&... other_values);
/**
* @brief Copies the content of the given trivially copyable class to the buffer as a normal
@@ -65,59 +77,96 @@ public:
* @note: The input class must be correctly packed/padded to fit hardware layout.
*/
template <typename T>
- void PushRaw(const T& value) {
- static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
- std::memcpy(cmdbuf + index, &value, sizeof(T));
- index += (sizeof(T) + 3) / 4; // round up to word length
- }
+ void PushRaw(const T& value);
// TODO : ensure that translate params are added after all regular params
template <typename... H>
- void PushCopyHandles(H... handles) {
- Push(CopyHandleDesc(sizeof...(H)));
- Push(static_cast<Kernel::Handle>(handles)...);
- }
+ void PushCopyHandles(H... handles);
template <typename... H>
- void PushMoveHandles(H... handles) {
- Push(MoveHandleDesc(sizeof...(H)));
- Push(static_cast<Kernel::Handle>(handles)...);
- }
+ void PushMoveHandles(H... handles);
- void PushCurrentPIDHandle() {
- Push(CallingPidDesc());
- Push(u32(0));
- }
+ void PushCurrentPIDHandle();
- void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) {
- Push(StaticBufferDesc(size, buffer_id));
- Push(buffer_vaddr);
- }
+ void PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id);
- void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms) {
- Push(MappedBufferDesc(size, perms));
- Push(buffer_vaddr);
- }
+ void PushMappedBuffer(VAddr buffer_vaddr, u32 size, MappedBufferPermissions perms);
};
/// Push ///
template <>
-inline void RequestBuilder::Push<u32>(u32 value) {
- Push(value);
+inline void RequestBuilder::Push(u32 value) {
+ cmdbuf[index++] = value;
+}
+
+template <typename T>
+void RequestBuilder::PushRaw(const T& value) {
+ static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
+ std::memcpy(cmdbuf + index, &value, sizeof(T));
+ index += (sizeof(T) + 3) / 4; // round up to word length
}
template <>
-inline void RequestBuilder::Push<u64>(u64 value) {
+inline void RequestBuilder::Push(u8 value) {
+ PushRaw(value);
+}
+
+template <>
+inline void RequestBuilder::Push(u16 value) {
+ PushRaw(value);
+}
+
+template <>
+inline void RequestBuilder::Push(u64 value) {
Push(static_cast<u32>(value));
Push(static_cast<u32>(value >> 32));
}
template <>
-inline void RequestBuilder::Push<ResultCode>(ResultCode value) {
+inline void RequestBuilder::Push(bool value) {
+ Push(static_cast<u8>(value));
+}
+
+template <>
+inline void RequestBuilder::Push(ResultCode value) {
Push(value.raw);
}
+template <typename First, typename... Other>
+void RequestBuilder::Push(const First& first_value, const Other&... other_values) {
+ Push(first_value);
+ Push(other_values...);
+}
+
+template <typename... H>
+inline void RequestBuilder::PushCopyHandles(H... handles) {
+ Push(CopyHandleDesc(sizeof...(H)));
+ Push(static_cast<Kernel::Handle>(handles)...);
+}
+
+template <typename... H>
+inline void RequestBuilder::PushMoveHandles(H... handles) {
+ Push(MoveHandleDesc(sizeof...(H)));
+ Push(static_cast<Kernel::Handle>(handles)...);
+}
+
+inline void RequestBuilder::PushCurrentPIDHandle() {
+ Push(CallingPidDesc());
+ Push(u32(0));
+}
+
+inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, u32 size, u8 buffer_id) {
+ Push(StaticBufferDesc(size, buffer_id));
+ Push(buffer_vaddr);
+}
+
+inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, u32 size,
+ MappedBufferPermissions perms) {
+ Push(MappedBufferDesc(size, perms));
+ Push(buffer_vaddr);
+}
+
class RequestParser : public RequestHelperBase {
public:
RequestParser(u32* command_buffer, Header command_header)
@@ -185,24 +234,60 @@ public:
*/
template <typename T>
void PopRaw(T& value);
+
+ /**
+ * @brief Reads the next normal parameters as a struct, by copying it into a new value
+ * @note: The output class must be correctly packed/padded to fit hardware layout.
+ */
+ template <typename T>
+ T PopRaw();
};
/// Pop ///
template <>
-inline u32 RequestParser::Pop<u32>() {
+inline u32 RequestParser::Pop() {
return cmdbuf[index++];
}
+template <typename T>
+void RequestParser::PopRaw(T& value) {
+ static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
+ std::memcpy(&value, cmdbuf + index, sizeof(T));
+ index += (sizeof(T) + 3) / 4; // round up to word length
+}
+
+template <typename T>
+T RequestParser::PopRaw() {
+ T value;
+ PopRaw(value);
+ return value;
+}
+
+template <>
+inline u8 RequestParser::Pop() {
+ return PopRaw<u8>();
+}
+
template <>
-inline u64 RequestParser::Pop<u64>() {
+inline u16 RequestParser::Pop() {
+ return PopRaw<u16>();
+}
+
+template <>
+inline u64 RequestParser::Pop() {
const u64 lsw = Pop<u32>();
const u64 msw = Pop<u32>();
return msw << 32 | lsw;
}
template <>
-inline ResultCode RequestParser::Pop<ResultCode>() {
+inline bool RequestParser::Pop() {
+ return Pop<u8>() != 0;
+}
+
+template <>
+inline ResultCode RequestParser::Pop() {
return ResultCode{Pop<u32>()};
}
@@ -265,11 +350,4 @@ inline VAddr RequestParser::PopMappedBuffer(size_t* data_size,
return Pop<VAddr>();
}
-template <typename T>
-void RequestParser::PopRaw(T& value) {
- static_assert(std::is_trivially_copyable<T>(), "Raw types should be trivially copyable");
- std::memcpy(&value, cmdbuf + index, sizeof(T));
- index += (sizeof(T) + 3) / 4; // round up to word length
-}
-
} // namespace IPC
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index e57b19c2d..366d1eacf 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -49,13 +49,13 @@ void SendParameter(const MessageParameter& parameter) {
}
void Initialize(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- u32 flags = cmd_buff[2];
-
- cmd_buff[2] = IPC::CopyHandleDesc(2);
- cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
- cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080
+ u32 app_id = rp.Pop<u32>();
+ u32 flags = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 3);
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).MoveFrom(),
+ Kernel::g_handle_table.Create(parameter_event).MoveFrom());
// TODO(bunnei): Check if these events are cleared every time Initialize is called.
notification_event->Clear();
@@ -64,18 +64,16 @@ void Initialize(Service::Interface* self) {
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
lock->Release();
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-
LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
}
void GetSharedFont(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
if (!shared_font_mem) {
LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
- cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
- cmd_buff[1] = -1; // TODO: Find the right error code
+ rb.Push<u32>(-1); // TODO: Find the right error code
+ rb.Skip(1 + 2, true);
return;
}
@@ -87,103 +85,110 @@ void GetSharedFont(Service::Interface* self) {
BCFNT::RelocateSharedFont(shared_font_mem, target_address);
shared_font_relocated = true;
}
- cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ rb.Push(RESULT_SUCCESS); // No error
// Since the SharedMemory interface doesn't provide the address at which the memory was
// allocated, the real APT service calculates this address by scanning the entire address space
// (using svcQueryMemory) and searches for an allocation of the same size as the Shared Font.
- cmd_buff[2] = target_address;
- cmd_buff[3] = IPC::CopyHandleDesc();
- cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
+ rb.Push(target_address);
+ rb.PushCopyHandles(Kernel::g_handle_table.Create(shared_font_mem).MoveFrom());
}
void NotifyToWait(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x43, 1, 0); // 0x430040
+ u32 app_id = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
}
void GetLockHandle(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x10040
+
// Bits [0:2] are the applet type (System, Library, etc)
// Bit 5 tells the application that there's a pending APT parameter,
// this will cause the app to wait until parameter_event is signaled.
- u32 applet_attributes = cmd_buff[1];
-
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
-
- cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
- cmd_buff[3] = 0; // Least significant bit = power button state
- cmd_buff[4] = IPC::CopyHandleDesc();
- cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom();
-
- LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5],
+ u32 applet_attributes = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(3, 2);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable.
+ rb.Push<u32>(0); // Least significant bit = power button state
+ Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).MoveFrom();
+ rb.PushCopyHandles(handle_copy);
+
+ LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", handle_copy,
applet_attributes);
}
void Enable(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 attributes = cmd_buff[1];
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- parameter_event->Signal(); // Let the application know that it has been started
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040
+ u32 attributes = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ parameter_event->Signal(); // Let the application know that it has been started
LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
}
void GetAppletManInfo(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 unk = cmd_buff[1];
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0;
- cmd_buff[3] = 0;
- cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
- cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x5, 1, 0); // 0x50040
+ u32 unk = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push<u32>(0);
+ rb.Push<u32>(0);
+ rb.Push(static_cast<u32>(AppletId::HomeMenu)); // Home menu AppID
+ rb.Push(static_cast<u32>(AppletId::Application)); // TODO(purpasmart96): Do this correctly
LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
}
void IsRegistered(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040
+ u32 app_id = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS); // No error
// TODO(Subv): An application is considered "registered" if it has already called APT::Enable
// handle this properly once we implement multiprocess support.
- cmd_buff[2] = 0; // Set to not registered by default
+ bool is_registered = false; // Set to not registered by default
if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) {
- cmd_buff[2] = HLE::Applets::IsLibraryAppletRunning() ? 1 : 0;
+ is_registered = HLE::Applets::IsLibraryAppletRunning();
} else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) {
- cmd_buff[2] = 1; // Set to registered
+ is_registered = true; // Set to registered
}
+ rb.Push(is_registered);
+
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
}
void InquireNotification(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 1, 0); // 0xB0040
+ u32 app_id = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(static_cast<u32>(SignalType::None)); // Signal type
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
}
void SendParameter(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 src_app_id = cmd_buff[1];
- u32 dst_app_id = cmd_buff[2];
- u32 signal_type = cmd_buff[3];
- u32 buffer_size = cmd_buff[4];
- u32 value = cmd_buff[5];
- u32 handle = cmd_buff[6];
- u32 size = cmd_buff[7];
- u32 buffer = cmd_buff[8];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xC, 4, 4); // 0xC0104
+ u32 src_app_id = rp.Pop<u32>();
+ u32 dst_app_id = rp.Pop<u32>();
+ u32 signal_type = rp.Pop<u32>();
+ u32 buffer_size = rp.Pop<u32>();
+ Kernel::Handle handle = rp.PopHandle();
+ size_t size;
+ VAddr buffer = rp.PopStaticBuffer(&size);
std::shared_ptr<HLE::Applets::Applet> dest_applet =
HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+
if (dest_applet == nullptr) {
LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
- cmd_buff[1] = -1; // TODO(Subv): Find the right error code
+ rb.Push<u32>(-1); // TODO(Subv): Find the right error code
return;
}
@@ -195,88 +200,104 @@ void SendParameter(Service::Interface* self) {
param.buffer.resize(buffer_size);
Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size());
- cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
+ rb.Push(dest_applet->ReceiveParameter(param));
- LOG_WARNING(
- Service_APT,
- "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
- "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
- src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
+ LOG_WARNING(Service_APT,
+ "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
+ "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X",
+ src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer);
}
void ReceiveParameter(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- u32 buffer_size = cmd_buff[2];
- VAddr buffer = cmd_buff[0x104 >> 2];
-
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = next_parameter.sender_id;
- cmd_buff[3] = next_parameter.signal; // Signal type
- cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
- cmd_buff[5] = 0x10;
- cmd_buff[6] = 0;
- if (next_parameter.object != nullptr)
- cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
- cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
- cmd_buff[8] = buffer;
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 2, 0); // 0xD0080
+ u32 app_id = rp.Pop<u32>();
+ u32 buffer_size = rp.Pop<u32>();
+
+ size_t static_buff_size;
+ VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size);
+ if (buffer_size > static_buff_size)
+ LOG_WARNING(
+ Service_APT,
+ "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)",
+ buffer_size, static_buff_size);
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(next_parameter.sender_id);
+ rb.Push(next_parameter.signal); // Signal type
+ ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !");
+ rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
+
+ rb.PushMoveHandles((next_parameter.object != nullptr)
+ ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom()
+ : 0);
+ rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0);
Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
- LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+ LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
}
void GlanceParameter(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id = cmd_buff[1];
- u32 buffer_size = cmd_buff[2];
- VAddr buffer = cmd_buff[0x104 >> 2];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xE, 2, 0); // 0xE0080
+ u32 app_id = rp.Pop<u32>();
+ u32 buffer_size = rp.Pop<u32>();
+
+ size_t static_buff_size;
+ VAddr buffer = rp.PeekStaticBuffer(0, &static_buff_size);
+ if (buffer_size > static_buff_size)
+ LOG_WARNING(
+ Service_APT,
+ "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)",
+ buffer_size, static_buff_size);
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = next_parameter.sender_id;
- cmd_buff[3] = next_parameter.signal; // Signal type
- cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
- cmd_buff[5] = 0x10;
- cmd_buff[6] = 0;
- if (next_parameter.object != nullptr)
- cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
- cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
- cmd_buff[8] = buffer;
+ IPC::RequestBuilder rb = rp.MakeBuilder(4, 4);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(next_parameter.sender_id);
+ rb.Push(next_parameter.signal); // Signal type
+ ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !");
+ rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size
- Memory::WriteBlock(buffer, next_parameter.buffer.data(),
- std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
+ rb.PushCopyHandles((next_parameter.object != nullptr)
+ ? Kernel::g_handle_table.Create(next_parameter.object).MoveFrom()
+ : 0);
+ rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0);
- LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+ Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size());
+
+ LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size);
}
void CancelParameter(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 flag1 = cmd_buff[1];
- u32 unk = cmd_buff[2];
- u32 flag2 = cmd_buff[3];
- u32 app_id = cmd_buff[4];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 1; // Set to Success
+ u32 check_sender = rp.Pop<u32>();
+ u32 sender_appid = rp.Pop<u32>();
+ u32 check_receiver = rp.Pop<u32>();
+ u32 receiver_appid = rp.Pop<u32>();
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(true); // Set to Success
- LOG_WARNING(Service_APT,
- "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1,
- unk, flag2, app_id);
+ LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, "
+ "check_receiver=0x%08X, receiver_appid=0x%08X",
+ check_sender, sender_appid, check_receiver, receiver_appid);
}
void PrepareToStartApplication(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 title_info1 = cmd_buff[1];
- u32 title_info2 = cmd_buff[2];
- u32 title_info3 = cmd_buff[3];
- u32 title_info4 = cmd_buff[4];
- u32 flags = cmd_buff[5];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x15, 5, 0); // 0x00150140
+ u32 title_info1 = rp.Pop<u32>();
+ u32 title_info2 = rp.Pop<u32>();
+ u32 title_info3 = rp.Pop<u32>();
+ u32 title_info4 = rp.Pop<u32>();
+ u32 flags = rp.Pop<u32>();
if (flags & 0x00000100) {
unknown_ns_state_field = 1;
}
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT,
"(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
@@ -285,172 +306,188 @@ void PrepareToStartApplication(Service::Interface* self) {
}
void StartApplication(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 buffer1_size = cmd_buff[1];
- u32 buffer2_size = cmd_buff[2];
- u32 flag = cmd_buff[3];
- u32 size1 = cmd_buff[4];
- u32 buffer1_ptr = cmd_buff[5];
- u32 size2 = cmd_buff[6];
- u32 buffer2_ptr = cmd_buff[7];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 3, 4); // 0x001B00C4
+ u32 buffer1_size = rp.Pop<u32>();
+ u32 buffer2_size = rp.Pop<u32>();
+ u32 flag = rp.Pop<u32>();
+ size_t size1;
+ VAddr buffer1_ptr = rp.PopStaticBuffer(&size1);
+ size_t size2;
+ VAddr buffer2_ptr = rp.PopStaticBuffer(&size2);
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT,
"(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
- "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
+ "size1=0x%08zX, buffer1_ptr=0x%08X, size2=0x%08zX, buffer2_ptr=0x%08X",
buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
}
void AppletUtility(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4B, 3, 2); // 0x004B00C2
// These are from 3dbrew - I'm not really sure what they're used for.
- u32 command = cmd_buff[1];
- u32 buffer1_size = cmd_buff[2];
- u32 buffer2_size = cmd_buff[3];
- u32 buffer1_addr = cmd_buff[5];
- u32 buffer2_addr = cmd_buff[65];
+ u32 utility_command = rp.Pop<u32>();
+ u32 input_size = rp.Pop<u32>();
+ u32 output_size = rp.Pop<u32>();
+ VAddr input_addr = rp.PopStaticBuffer();
+
+ VAddr output_addr = rp.PeekStaticBuffer(0);
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT,
- "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
- "buffer1_addr=0x%08X, buffer2_addr=0x%08X",
- command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr);
+ "(STUBBED) called command=0x%08X, input_size=0x%08X, output_size=0x%08X, "
+ "input_addr=0x%08X, output_addr=0x%08X",
+ utility_command, input_size, output_size, input_addr, output_addr);
}
void SetAppCpuTimeLimit(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 value = cmd_buff[1];
- cpu_percent = cmd_buff[2];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x4F, 2, 0); // 0x4F0080
+ u32 value = rp.Pop<u32>();
+ cpu_percent = rp.Pop<u32>();
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
}
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value);
}
void GetAppCpuTimeLimit(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 value = cmd_buff[1];
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x50, 1, 0); // 0x500040
+ u32 value = rp.Pop<u32>();
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
}
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = cpu_percent;
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(cpu_percent);
LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
}
void PrepareToStartLibraryApplet(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x18, 1, 0); // 0x180040
+ AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>());
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
auto applet = HLE::Applets::Applet::Get(applet_id);
if (applet) {
LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
- cmd_buff[1] = RESULT_SUCCESS.raw;
+ rb.Push(RESULT_SUCCESS);
} else {
- cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
+ rb.Push(HLE::Applets::Applet::Create(applet_id));
}
LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
}
void PreloadLibraryApplet(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x16, 1, 0); // 0x160040
+ AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>());
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
auto applet = HLE::Applets::Applet::Get(applet_id);
if (applet) {
LOG_WARNING(Service_APT, "applet has already been started id=%08X", applet_id);
- cmd_buff[1] = RESULT_SUCCESS.raw;
+ rb.Push(RESULT_SUCCESS);
} else {
- cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
+ rb.Push(HLE::Applets::Applet::Create(applet_id));
}
LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
}
void StartLibraryApplet(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1E, 2, 4); // 0x1E0084
+ AppletId applet_id = static_cast<AppletId>(rp.Pop<u32>());
std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
if (applet == nullptr) {
LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
- cmd_buff[1] = -1; // TODO(Subv): Find the right error code
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0, false);
+ rb.Push<u32>(-1); // TODO(Subv): Find the right error code
return;
}
- size_t buffer_size = cmd_buff[2];
- VAddr buffer_addr = cmd_buff[6];
+ size_t buffer_size = rp.Pop<u32>();
+ Kernel::Handle handle = rp.PopHandle();
+ VAddr buffer_addr = rp.PopStaticBuffer();
AppletStartupParameter parameter;
- parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
+ parameter.object = Kernel::g_handle_table.GetGeneric(handle);
parameter.buffer.resize(buffer_size);
Memory::ReadBlock(buffer_addr, parameter.buffer.data(), parameter.buffer.size());
- cmd_buff[1] = applet->Start(parameter).raw;
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(applet->Start(parameter));
}
void CancelLibraryApplet(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 exiting = cmd_buff[1] & 0xFF;
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3B, 1, 0); // 0x003B0040
+ bool exiting = rp.Pop<bool>();
- cmd_buff[1] = 1; // TODO: Find the return code meaning
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push<u32>(1); // TODO: Find the return code meaning
- LOG_WARNING(Service_APT, "(STUBBED) called exiting=%u", exiting);
+ LOG_WARNING(Service_APT, "(STUBBED) called exiting=%d", exiting);
}
void SetScreenCapPostPermission(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x55, 1, 0); // 0x00550040
- screen_capture_post_permission = static_cast<ScreencapPostPermission>(cmd_buff[1] & 0xF);
+ screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF);
- cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
- cmd_buff[1] = RESULT_SUCCESS.raw;
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(RESULT_SUCCESS); // No error
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
screen_capture_post_permission);
}
void GetScreenCapPostPermission(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x56, 0, 0); // 0x00560000
- cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+ rb.Push(RESULT_SUCCESS); // No error
+ rb.Push(static_cast<u32>(screen_capture_post_permission));
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
screen_capture_post_permission);
}
void GetAppletInfo(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- auto app_id = static_cast<AppletId>(cmd_buff[1]);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x6, 1, 0); // 0x60040
+ auto app_id = static_cast<AppletId>(rp.Pop<u32>());
if (auto applet = HLE::Applets::Applet::Get(app_id)) {
// TODO(Subv): Get the title id for the current applet and write it in the response[2-3]
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[4] = static_cast<u32>(Service::FS::MediaType::NAND);
- cmd_buff[5] = 1; // Registered
- cmd_buff[6] = 1; // Loaded
- cmd_buff[7] = 0; // Applet Attributes
+ IPC::RequestBuilder rb = rp.MakeBuilder(7, 0);
+ rb.Push(RESULT_SUCCESS);
+ u64 title_id = 0;
+ rb.Push(title_id);
+ rb.Push(static_cast<u32>(Service::FS::MediaType::NAND));
+ rb.Push(true); // Registered
+ rb.Push(true); // Loaded
+ rb.Push<u32>(0); // Applet Attributes
} else {
- cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
- ErrorSummary::NotFound, ErrorLevel::Status)
- .raw;
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
+ ErrorLevel::Status));
}
LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id);
}
void GetStartupArgument(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 parameter_size = cmd_buff[1];
- StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x51, 2, 0); // 0x00510080
+ u32 parameter_size = rp.Pop<u32>();
+ StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(rp.Pop<u8>());
if (parameter_size >= 0x300) {
LOG_ERROR(
@@ -460,7 +497,14 @@ void GetStartupArgument(Service::Interface* self) {
return;
}
- u32 addr = cmd_buff[65];
+ size_t static_buff_size;
+ VAddr addr = rp.PeekStaticBuffer(0, &static_buff_size);
+ if (parameter_size > static_buff_size)
+ LOG_WARNING(
+ Service_APT,
+ "parameter_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)",
+ parameter_size, static_buff_size);
+
if (addr && parameter_size) {
Memory::ZeroBlock(addr, parameter_size);
}
@@ -468,8 +512,10 @@ void GetStartupArgument(Service::Interface* self) {
LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x",
startup_argument_type, parameter_size);
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0);
+ rb.PushStaticBuffer(addr, parameter_size, 0);
}
void Wrap(Service::Interface* self) {
@@ -554,7 +600,7 @@ void Unwrap(Service::Interface* self) {
// Decrypts the ciphertext using AES-CCM
auto pdata = HW::AES::DecryptVerifyCCM(cipher, nonce, HW::AES::KeySlotID::APTWrap);
- IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+ IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
if (!pdata.empty()) {
// Splits the plaintext and put the nonce in between
Memory::WriteBlock(output, pdata.data(), nonce_offset);
@@ -574,25 +620,25 @@ void Unwrap(Service::Interface* self) {
}
void CheckNew3DSApp(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x101, 0, 0); // 0x01010000
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (unknown_ns_state_field) {
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0);
} else {
- PTM::CheckNew3DS(self);
+ PTM::CheckNew3DS(rb);
}
- cmd_buff[0] = IPC::MakeHeader(0x101, 2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
}
void CheckNew3DS(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x102, 0, 0); // 0x01020000
+ IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
- PTM::CheckNew3DS(self);
+ PTM::CheckNew3DS(rb);
- cmd_buff[0] = IPC::MakeHeader(0x102, 2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
}
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 6f13cde27..4ddb1bc90 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -3,6 +3,8 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <array>
+#include <cryptopp/sha.h>
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -176,14 +178,29 @@ void SecureInfoGetRegion(Service::Interface* self) {
}
void GenHashConsoleUnique(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 app_id_salt = cmd_buff[1];
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0x33646D6F ^ (app_id_salt & 0xFFFFF); // 3dmoo hash
- cmd_buff[3] = 0x6F534841 ^ (app_id_salt & 0xFFFFF);
+ IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0);
+ const u32 app_id_salt = rp.Pop<u32>() & 0x000FFFFF;
+
+ IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
+
+ std::array<u8, 12> buffer;
+ const ResultCode result = GetConfigInfoBlock(ConsoleUniqueID2BlockID, 8, 2, buffer.data());
+ rb.Push(result);
+ if (result.IsSuccess()) {
+ std::memcpy(&buffer[8], &app_id_salt, sizeof(u32));
+ std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash;
+ CryptoPP::SHA256().CalculateDigest(hash.data(), buffer.data(), sizeof(buffer));
+ u32 low, high;
+ memcpy(&low, &hash[hash.size() - 8], sizeof(u32));
+ memcpy(&high, &hash[hash.size() - 4], sizeof(u32));
+ rb.Push(low);
+ rb.Push(high);
+ } else {
+ rb.Push<u32>(0);
+ rb.Push<u32>(0);
+ }
- LOG_WARNING(Service_CFG, "(STUBBED) called app_id_salt=0x%X", app_id_salt);
+ LOG_DEBUG(Service_CFG, "called app_id_salt=0x%X", app_id_salt);
}
void GetRegionCanadaUSA(Service::Interface* self) {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fb3acb507..b19e831fe 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,10 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <atomic>
#include <cmath>
+#include <memory>
#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
+#include "core/frontend/input.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/hid.h"
@@ -44,6 +48,11 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234;
constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104;
constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101;
+static std::atomic<bool> is_device_reload_pending;
+static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
+ buttons;
+static std::unique_ptr<Input::AnalogDevice> circle_pad;
+
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
// 30 degree and 60 degree are angular thresholds for directions
constexpr float TAN30 = 0.577350269f;
@@ -74,14 +83,48 @@ static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
return state;
}
+static void LoadInputDevices() {
+ 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>);
+ circle_pad = Input::CreateDevice<Input::AnalogDevice>(
+ Settings::values.analogs[Settings::NativeAnalog::CirclePad]);
+}
+
+static void UnloadInputDevices() {
+ for (auto& button : buttons) {
+ button.reset();
+ }
+ circle_pad.reset();
+}
+
static void UpdatePadCallback(u64 userdata, int cycles_late) {
SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
- PadState state = VideoCore::g_emu_window->GetPadState();
+ if (is_device_reload_pending.exchange(false))
+ LoadInputDevices();
+
+ PadState state;
+ using namespace Settings::NativeButton;
+ state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
+ state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
+ state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
+ state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
+ state.right.Assign(buttons[Right - BUTTON_HID_BEGIN]->GetStatus());
+ state.left.Assign(buttons[Left - BUTTON_HID_BEGIN]->GetStatus());
+ state.up.Assign(buttons[Up - BUTTON_HID_BEGIN]->GetStatus());
+ state.down.Assign(buttons[Down - BUTTON_HID_BEGIN]->GetStatus());
+ state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
+ state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
+ state.start.Assign(buttons[Start - BUTTON_HID_BEGIN]->GetStatus());
+ state.select.Assign(buttons[Select - BUTTON_HID_BEGIN]->GetStatus());
// Get current circle pad position and update circle pad direction
- s16 circle_pad_x, circle_pad_y;
- std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState();
+ float circle_pad_x_f, circle_pad_y_f;
+ std::tie(circle_pad_x_f, circle_pad_y_f) = circle_pad->GetStatus();
+ constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position
+ s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS);
+ s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS);
state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex;
mem->pad.current_state.hex = state.hex;
@@ -313,6 +356,8 @@ void Init() {
AddService(new HID_U_Interface);
AddService(new HID_SPVR_Interface);
+ is_device_reload_pending.store(true);
+
using Kernel::MemoryPermission;
shared_mem =
SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
@@ -350,6 +395,11 @@ void Shutdown() {
event_accelerometer = nullptr;
event_gyroscope = nullptr;
event_debug_pad = nullptr;
+ UnloadInputDevices();
+}
+
+void ReloadInputDevices() {
+ is_device_reload_pending.store(true);
}
} // namespace HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index c7f4ee138..b505cdcd5 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -39,13 +39,6 @@ struct PadState {
BitField<10, 1, u32> x;
BitField<11, 1, u32> y;
- BitField<14, 1, u32> zl;
- BitField<15, 1, u32> zr;
-
- BitField<24, 1, u32> c_right;
- BitField<25, 1, u32> c_left;
- BitField<26, 1, u32> c_up;
- BitField<27, 1, u32> c_down;
BitField<28, 1, u32> circle_right;
BitField<29, 1, u32> circle_left;
BitField<30, 1, u32> circle_up;
@@ -183,33 +176,6 @@ ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
#undef ASSERT_REG_POSITION
#endif // !defined(_MSC_VER)
-// Pre-defined PadStates for single button presses
-const PadState PAD_NONE = {{0}};
-const PadState PAD_A = {{1u << 0}};
-const PadState PAD_B = {{1u << 1}};
-const PadState PAD_SELECT = {{1u << 2}};
-const PadState PAD_START = {{1u << 3}};
-const PadState PAD_RIGHT = {{1u << 4}};
-const PadState PAD_LEFT = {{1u << 5}};
-const PadState PAD_UP = {{1u << 6}};
-const PadState PAD_DOWN = {{1u << 7}};
-const PadState PAD_R = {{1u << 8}};
-const PadState PAD_L = {{1u << 9}};
-const PadState PAD_X = {{1u << 10}};
-const PadState PAD_Y = {{1u << 11}};
-
-const PadState PAD_ZL = {{1u << 14}};
-const PadState PAD_ZR = {{1u << 15}};
-
-const PadState PAD_C_RIGHT = {{1u << 24}};
-const PadState PAD_C_LEFT = {{1u << 25}};
-const PadState PAD_C_UP = {{1u << 26}};
-const PadState PAD_C_DOWN = {{1u << 27}};
-const PadState PAD_CIRCLE_RIGHT = {{1u << 28}};
-const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
-const PadState PAD_CIRCLE_UP = {{1u << 30}};
-const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
-
/**
* HID::GetIPCHandles service function
* Inputs:
@@ -297,5 +263,8 @@ void Init();
/// Shutdown HID service
void Shutdown();
+
+/// Reload input devices. Used when input configuration changed
+void ReloadInputDevices();
}
}
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 8ff808fd9..e373ed47a 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -92,8 +92,7 @@ void GetSoftwareClosedFlag(Service::Interface* self) {
LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-void CheckNew3DS(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
+void CheckNew3DS(IPC::RequestBuilder& rb) {
const bool is_new_3ds = Settings::values.is_new_3ds;
if (is_new_3ds) {
@@ -101,12 +100,17 @@ void CheckNew3DS(Service::Interface* self) {
"settings. Citra does not fully support New 3DS emulation yet!");
}
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = is_new_3ds ? 1 : 0;
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(is_new_3ds);
LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x%08x", static_cast<u32>(is_new_3ds));
}
+void CheckNew3DS(Service::Interface* self) {
+ IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0x40A, 0, 0); // 0x040A0000
+ CheckNew3DS(rb);
+}
+
void Init() {
AddService(new PTM_Gets);
AddService(new PTM_Play);
@@ -134,9 +138,9 @@ void Init() {
ASSERT_MSG(archive_result.Succeeded(), "Could not open the PTM SharedExtSaveData archive!");
FileSys::Path gamecoin_path("/gamecoin.dat");
+ Service::FS::CreateFileInArchive(*archive_result, gamecoin_path, sizeof(GameCoin));
FileSys::Mode open_mode = {};
open_mode.write_flag.Assign(1);
- open_mode.create_flag.Assign(1);
// Open the file and write the default gamecoin information
auto gamecoin_result =
Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode);
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index a1a628012..683fb445b 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -5,6 +5,7 @@
#pragma once
#include "common/common_types.h"
+#include "core/hle/ipc_helpers.h"
namespace Service {
@@ -97,6 +98,7 @@ void GetSoftwareClosedFlag(Interface* self);
* 2: u8 output: 0 = Old3DS, 1 = New3DS.
*/
void CheckNew3DS(Interface* self);
+void CheckNew3DS(IPC::RequestBuilder& rb);
/// Initialize the PTM service
void Init();
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index dcc5c3c90..530614e6f 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -362,18 +362,18 @@ static void Socket(Interface* self) {
return;
}
- u32 socket_handle = static_cast<u32>(::socket(domain, type, protocol));
+ u32 ret = static_cast<u32>(::socket(domain, type, protocol));
- if ((s32)socket_handle != SOCKET_ERROR_VALUE)
- open_sockets[socket_handle] = {socket_handle, true};
+ if ((s32)ret != SOCKET_ERROR_VALUE)
+ open_sockets[ret] = {ret, true};
int result = 0;
- if ((s32)socket_handle == SOCKET_ERROR_VALUE)
- result = TranslateError(GET_ERRNO);
+ if ((s32)ret == SOCKET_ERROR_VALUE)
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[0] = IPC::MakeHeader(2, 2, 0);
cmd_buffer[1] = result;
- cmd_buffer[2] = socket_handle;
+ cmd_buffer[2] = ret;
}
static void Bind(Interface* self) {
@@ -393,15 +393,15 @@ static void Bind(Interface* self) {
sockaddr sock_addr = CTRSockAddr::ToPlatform(ctr_sock_addr);
- int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
+ int ret = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
int result = 0;
- if (res != 0)
- result = TranslateError(GET_ERRNO);
+ if (ret != 0)
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[0] = IPC::MakeHeader(5, 2, 0);
cmd_buffer[1] = result;
- cmd_buffer[2] = res;
+ cmd_buffer[2] = ret;
}
static void Fcntl(Interface* self) {
@@ -426,8 +426,7 @@ static void Fcntl(Interface* self) {
#else
int ret = ::fcntl(socket_handle, F_GETFL, 0);
if (ret == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
- posix_ret = -1;
+ posix_ret = TranslateError(GET_ERRNO);
return;
}
posix_ret = 0;
@@ -439,8 +438,7 @@ static void Fcntl(Interface* self) {
unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0;
int ret = ioctlsocket(socket_handle, FIONBIO, &tmp);
if (ret == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
- posix_ret = -1;
+ posix_ret = TranslateError(GET_ERRNO);
return;
}
auto iter = open_sockets.find(socket_handle);
@@ -449,8 +447,7 @@ static void Fcntl(Interface* self) {
#else
int flags = ::fcntl(socket_handle, F_GETFL, 0);
if (flags == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
- posix_ret = -1;
+ posix_ret = TranslateError(GET_ERRNO);
return;
}
@@ -460,15 +457,13 @@ static void Fcntl(Interface* self) {
int ret = ::fcntl(socket_handle, F_SETFL, flags);
if (ret == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
- posix_ret = -1;
+ posix_ret = TranslateError(GET_ERRNO);
return;
}
#endif
} else {
LOG_ERROR(Service_SOC, "Unsupported command (%d) in fcntl call", ctr_cmd);
- result = TranslateError(EINVAL); // TODO: Find the correct error
- posix_ret = -1;
+ posix_ret = TranslateError(EINVAL); // TODO: Find the correct error
return;
}
}
@@ -481,7 +476,7 @@ static void Listen(Interface* self) {
int ret = ::listen(socket_handle, backlog);
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[0] = IPC::MakeHeader(3, 2, 0);
cmd_buffer[1] = result;
@@ -504,7 +499,7 @@ static void Accept(Interface* self) {
int result = 0;
if ((s32)ret == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
} else {
CTRSockAddr ctr_addr = CTRSockAddr::FromPlatform(addr);
Memory::WriteBlock(cmd_buffer[0x104 >> 2], &ctr_addr, sizeof(ctr_addr));
@@ -545,7 +540,7 @@ static void Close(Interface* self) {
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[2] = ret;
cmd_buffer[1] = result;
@@ -589,7 +584,7 @@ static void SendTo(Interface* self) {
int result = 0;
if (ret == SOCKET_ERROR_VALUE)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[2] = ret;
cmd_buffer[1] = result;
@@ -638,7 +633,7 @@ static void RecvFrom(Interface* self) {
int result = 0;
int total_received = ret;
if (ret == SOCKET_ERROR_VALUE) {
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
total_received = 0;
} else {
// Write only the data we received to avoid overwriting parts of the buffer with zeros
@@ -673,7 +668,7 @@ static void Poll(Interface* self) {
std::vector<pollfd> platform_pollfd(nfds);
std::transform(ctr_fds.begin(), ctr_fds.end(), platform_pollfd.begin(), CTRPollFD::ToPlatform);
- const int ret = ::poll(platform_pollfd.data(), nfds, timeout);
+ int ret = ::poll(platform_pollfd.data(), nfds, timeout);
// Now update the output pollfd structure
std::transform(platform_pollfd.begin(), platform_pollfd.end(), ctr_fds.begin(),
@@ -683,7 +678,7 @@ static void Poll(Interface* self) {
int result = 0;
if (ret == SOCKET_ERROR_VALUE)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[1] = result;
cmd_buffer[2] = ret;
@@ -710,7 +705,7 @@ static void GetSockName(Interface* self) {
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[2] = ret;
cmd_buffer[1] = result;
@@ -724,7 +719,7 @@ static void Shutdown(Interface* self) {
int ret = ::shutdown(socket_handle, how);
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[2] = ret;
cmd_buffer[1] = result;
}
@@ -750,7 +745,7 @@ static void GetPeerName(Interface* self) {
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[2] = ret;
cmd_buffer[1] = result;
@@ -777,7 +772,7 @@ static void Connect(Interface* self) {
int ret = ::connect(socket_handle, &input_addr, sizeof(input_addr));
int result = 0;
if (ret != 0)
- result = TranslateError(GET_ERRNO);
+ ret = TranslateError(GET_ERRNO);
cmd_buffer[0] = IPC::MakeHeader(6, 2, 0);
cmd_buffer[1] = result;
@@ -815,7 +810,7 @@ static void GetSockOpt(Interface* self) {
int optname = TranslateSockOpt(cmd_buffer[3]);
socklen_t optlen = (socklen_t)cmd_buffer[4];
- int ret = -1;
+ int ret = 0;
int err = 0;
if (optname < 0) {
@@ -830,9 +825,8 @@ static void GetSockOpt(Interface* self) {
// >> 2 = convert to u32 offset instead of byte offset (cmd_buffer = u32*)
char* optval = reinterpret_cast<char*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
- ret = ::getsockopt(socket_handle, level, optname, optval, &optlen);
- err = 0;
- if (ret == SOCKET_ERROR_VALUE) {
+ err = ::getsockopt(socket_handle, level, optname, optval, &optlen);
+ if (err == SOCKET_ERROR_VALUE) {
err = TranslateError(GET_ERRNO);
}
}
@@ -849,7 +843,7 @@ static void SetSockOpt(Interface* self) {
u32 level = cmd_buffer[2];
int optname = TranslateSockOpt(cmd_buffer[3]);
- int ret = -1;
+ int ret = 0;
int err = 0;
if (optname < 0) {
@@ -862,9 +856,8 @@ static void SetSockOpt(Interface* self) {
socklen_t optlen = static_cast<socklen_t>(cmd_buffer[4]);
const char* optval = reinterpret_cast<const char*>(Memory::GetPointer(cmd_buffer[8]));
- ret = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen));
- err = 0;
- if (ret == SOCKET_ERROR_VALUE) {
+ err = static_cast<u32>(::setsockopt(socket_handle, level, optname, optval, optlen));
+ if (err == SOCKET_ERROR_VALUE) {
err = TranslateError(GET_ERRNO);
}
}
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 907d9c8fa..c0837d49d 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -189,11 +189,9 @@ static void SetSpacialDithering(Interface* self) {
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
static void GetSpacialDithering(Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = spacial_dithering_enabled;
+ IPC::RequestBuilder rb(Kernel::GetCommandBuffer(), 0xA, 2, 0);
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(spacial_dithering_enabled != 0);
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index d0d92487d..5978ccdd4 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -6,6 +6,7 @@
#include <cstring>
#include <ctime>
#include "core/core_timing.h"
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/shared_page.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -73,6 +74,12 @@ void Init() {
// Some games wait until this value becomes 0x1, before asking running_hw
shared_page.unknown_value = 0x1;
+ // Set to a completely full battery
+ shared_page.battery_state.charge_level.Assign(
+ static_cast<u8>(Service::PTM::ChargeLevels::CompletelyFull));
+ shared_page.battery_state.is_adapter_connected.Assign(1);
+ shared_page.battery_state.is_charging.Assign(1);
+
update_time_event =
CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback);
CoreTiming::ScheduleEvent(0, update_time_event);
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index 106e47efc..864695ae1 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -10,6 +10,7 @@
* write access, according to 3dbrew; this is not emulated)
*/
+#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
@@ -29,6 +30,13 @@ struct DateTime {
};
static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
+union BatteryState {
+ u8 raw;
+ BitField<0, 1, u8> is_adapter_connected;
+ BitField<1, 1, u8> is_charging;
+ BitField<2, 3, u8> charge_level;
+};
+
struct SharedPageDef {
// Most of these names are taken from the 3dbrew page linked above.
u32_le date_time_counter; // 0
@@ -44,7 +52,7 @@ struct SharedPageDef {
INSERT_PADDING_BYTES(0x80 - 0x68); // 68
float_le sliderstate_3d; // 80
u8 ledstate_3d; // 84
- INSERT_PADDING_BYTES(1); // 85
+ BatteryState battery_state; // 85
u8 unknown_value; // 86
INSERT_PADDING_BYTES(0xA0 - 0x87); // 87
u64_le menu_title_id; // A0
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 1baa80671..2db823c61 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -467,8 +467,8 @@ static void Break(u8 break_reason) {
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
-static void OutputDebugString(const char* string) {
- LOG_DEBUG(Debug_Emulated, "%s", string);
+static void OutputDebugString(const char* string, int len) {
+ LOG_DEBUG(Debug_Emulated, "%.*s", len, string);
}
/// Get resource limit
@@ -556,11 +556,21 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 ent
break;
}
- if (processor_id == THREADPROCESSORID_1 || processor_id == THREADPROCESSORID_ALL ||
- (processor_id == THREADPROCESSORID_DEFAULT &&
- Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1)) {
- LOG_WARNING(Kernel_SVC,
- "Newly created thread is allowed to be run in the SysCore, unimplemented.");
+ if (processor_id == THREADPROCESSORID_ALL) {
+ LOG_INFO(Kernel_SVC,
+ "Newly created thread is allowed to be run in any Core, unimplemented.");
+ }
+
+ if (processor_id == THREADPROCESSORID_DEFAULT &&
+ Kernel::g_current_process->ideal_processor == THREADPROCESSORID_1) {
+ LOG_WARNING(
+ Kernel_SVC,
+ "Newly created thread is allowed to be run in the SysCore (Core1), unimplemented.");
+ }
+
+ if (processor_id == THREADPROCESSORID_1) {
+ LOG_ERROR(Kernel_SVC,
+ "Newly created thread must run in the SysCore (Core1), unimplemented.");
}
CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority,
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 147bf8591..be719d74c 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -139,7 +139,7 @@ std::unique_ptr<AppLoader> GetLoader(const std::string& filename) {
type = filename_type;
}
- LOG_INFO(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type));
+ LOG_DEBUG(Loader, "Loading file %s as %s...", filename.c_str(), GetFileTypeString(type));
return GetFileLoader(std::move(file), type, filename_filename, filename);
}
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 98b8259d9..1a4e3efa8 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <cinttypes>
#include <cstring>
#include <memory>
#include "common/logging/log.h"
@@ -253,7 +254,7 @@ ResultStatus AppLoader_NCCH::LoadExeFS() {
// Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
- LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
+ LOG_DEBUG(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
ncch_offset = 0x4000;
file.Seek(ncch_offset, SEEK_SET);
file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
@@ -277,8 +278,8 @@ ResultStatus AppLoader_NCCH::LoadExeFS() {
priority = exheader_header.arm11_system_local_caps.priority;
resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category;
- LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
- LOG_INFO(Loader, "Program ID: %016llX", ncch_header.program_id);
+ LOG_DEBUG(Loader, "Name: %s", exheader_header.codeset_info.name);
+ LOG_DEBUG(Loader, "Program ID: %016" PRIX64, ncch_header.program_id);
LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
LOG_DEBUG(Loader, "Code size: 0x%08X", code_size);
@@ -336,6 +337,8 @@ ResultStatus AppLoader_NCCH::Load() {
if (result != ResultStatus::Success)
return result;
+ LOG_INFO(Loader, "Program ID: %016" PRIX64, ncch_header.program_id);
+
is_loaded = true; // Set state to loaded
result = LoadExec(); // Load the executable into memory for booting
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 3a32b70aa..a598f9f2f 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -4,6 +4,7 @@
#include "audio_core/audio_core.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/service/hid/hid.h"
#include "settings.h"
#include "video_core/video_core.h"
@@ -29,6 +30,8 @@ void Apply() {
AudioCore::SelectSink(values.sink_id);
AudioCore::EnableStretching(values.enable_audio_stretching);
+
+ Service::HID::ReloadInputDevices();
}
} // namespace
diff --git a/src/core/settings.h b/src/core/settings.h
index b6c75531f..03c64c94c 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -15,67 +15,70 @@ enum class LayoutOption {
Default,
SingleScreen,
LargeScreen,
- Custom,
};
-namespace NativeInput {
-
+namespace NativeButton {
enum Values {
- // directly mapped keys
A,
B,
X,
Y,
+ Up,
+ Down,
+ Left,
+ Right,
L,
R,
+ Start,
+ Select,
+
ZL,
ZR,
- START,
- SELECT,
- HOME,
- DUP,
- DDOWN,
- DLEFT,
- DRIGHT,
- CUP,
- CDOWN,
- CLEFT,
- CRIGHT,
-
- // indirectly mapped keys
- CIRCLE_UP,
- CIRCLE_DOWN,
- CIRCLE_LEFT,
- CIRCLE_RIGHT,
- CIRCLE_MODIFIER,
-
- NUM_INPUTS
+
+ Home,
+
+ NumButtons,
};
-static const std::array<const char*, NUM_INPUTS> Mapping = {{
- // directly mapped keys
- "pad_a", "pad_b", "pad_x", "pad_y", "pad_l", "pad_r", "pad_zl", "pad_zr", "pad_start",
- "pad_select", "pad_home", "pad_dup", "pad_ddown", "pad_dleft", "pad_dright", "pad_cup",
- "pad_cdown", "pad_cleft", "pad_cright",
+constexpr int BUTTON_HID_BEGIN = A;
+constexpr int BUTTON_IR_BEGIN = ZL;
+constexpr int BUTTON_NS_BEGIN = Home;
+
+constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN;
+constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN;
+constexpr int BUTTON_NS_END = NumButtons;
+
+constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
+constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN;
+constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
- // indirectly mapped keys
- "pad_circle_up", "pad_circle_down", "pad_circle_left", "pad_circle_right",
- "pad_circle_modifier",
+static const std::array<const char*, NumButtons> mapping = {{
+ "button_a", "button_b", "button_x", "button_y", "button_up", "button_down", "button_left",
+ "button_right", "button_l", "button_r", "button_start", "button_select", "button_zl",
+ "button_zr", "button_home",
}};
-static const std::array<Values, NUM_INPUTS> All = {{
- A, B, X, Y, L, R, ZL, ZR,
- START, SELECT, HOME, DUP, DDOWN, DLEFT, DRIGHT, CUP,
- CDOWN, CLEFT, CRIGHT, CIRCLE_UP, CIRCLE_DOWN, CIRCLE_LEFT, CIRCLE_RIGHT, CIRCLE_MODIFIER,
+} // namespace NativeButton
+
+namespace NativeAnalog {
+enum Values {
+ CirclePad,
+ CStick,
+
+ NumAnalogs,
+};
+
+static const std::array<const char*, NumAnalogs> mapping = {{
+ "circle_pad", "c_stick",
}};
-}
+} // namespace NumAnalog
struct Values {
// CheckNew3DS
bool is_new_3ds;
// Controls
- std::array<int, NativeInput::NUM_INPUTS> input_mappings;
- float pad_circle_modifier_scale;
+ std::array<std::string, NativeButton::NumButtons> buttons;
+ std::array<std::string, NativeAnalog::NumAnalogs> analogs;
// Core
bool use_cpu_jit;
@@ -95,6 +98,15 @@ struct Values {
LayoutOption layout_option;
bool swap_screen;
+ bool custom_layout;
+ u16 custom_top_left;
+ u16 custom_top_top;
+ u16 custom_top_right;
+ u16 custom_top_bottom;
+ u16 custom_bottom_left;
+ u16 custom_bottom_top;
+ u16 custom_bottom_right;
+ u16 custom_bottom_bottom;
float bg_red;
float bg_green;