Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a64a77df3 | |||
| 6810929f6a | |||
| 9404633bfd | |||
| c10e720ba9 | |||
| 5016de3626 | |||
| d5fb9fd12c | |||
| c79b3af610 | |||
| b6106604c4 | |||
| 12b6162852 | |||
| 8f192b494a | |||
| 372897aac4 | |||
| a2f23746c2 | |||
| 215b13f2a2 | |||
| 35ed9425d7 | |||
| 74cc8721c7 | |||
| 8ef1db78b0 | |||
| 18c8f10ff2 | |||
| 96d881f087 | |||
| 0e950baf41 | |||
| 8113f55f4b | |||
| ddbefc71cb | |||
| 85143e8376 | |||
| 504abbd6e0 | |||
| 4cccbe7989 | |||
| 5eb5c96750 | |||
| 5da55cbac9 | |||
| 81cc4df1f9 | |||
| 25f3d358b1 | |||
| a3c8bb251d | |||
| 327533be1f | |||
| 61ea2115c7 | |||
| fb3ef957bb | |||
| 78f72b3bf5 | |||
| 818721d12d | |||
| f740d8b9be | |||
| 442aad9b27 | |||
| 8e0f97ac96 | |||
| 345d691328 |
Vendored
+1
@@ -11,3 +11,4 @@ type = QT
|
||||
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
|
||||
source_file = ../../src/android/app/src/main/res/values/strings.xml
|
||||
type = ANDROID
|
||||
lang_map = ja_JP:ja, ko_KR:ko, pt_BR:pt-rBR, pt_PT:pt-rPT, ru_RU:ru, vi_VN:vi, zh_CN:zh-rCN, zh_TW:zh-rTW
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common {
|
||||
@@ -29,6 +30,8 @@ namespace Common {
|
||||
|
||||
template <std::size_t Size, bool le = false>
|
||||
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
|
||||
|
||||
std::array<u8, Size> out{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
|
||||
+40
-40
@@ -186,68 +186,68 @@ static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
|
||||
static_assert(std::is_trivially_destructible_v<VirtualAddress>);
|
||||
static_assert(std::is_trivially_destructible_v<ProcessAddress>);
|
||||
|
||||
static_assert(Null<uint64_t> == 0);
|
||||
static_assert(Null<uint64_t> == 0U);
|
||||
static_assert(Null<PhysicalAddress> == Null<uint64_t>);
|
||||
static_assert(Null<VirtualAddress> == Null<uint64_t>);
|
||||
static_assert(Null<ProcessAddress> == Null<uint64_t>);
|
||||
|
||||
// Constructor/assignment validations.
|
||||
static_assert([] {
|
||||
const PhysicalAddress a(5);
|
||||
const PhysicalAddress a(5U);
|
||||
PhysicalAddress b(a);
|
||||
return b;
|
||||
}() == PhysicalAddress(5));
|
||||
}() == PhysicalAddress(5U));
|
||||
static_assert([] {
|
||||
const PhysicalAddress a(5);
|
||||
PhysicalAddress b(10);
|
||||
const PhysicalAddress a(5U);
|
||||
PhysicalAddress b(10U);
|
||||
b = a;
|
||||
return b;
|
||||
}() == PhysicalAddress(5));
|
||||
}() == PhysicalAddress(5U));
|
||||
|
||||
// Arithmetic validations.
|
||||
static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15));
|
||||
static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5));
|
||||
static_assert(PhysicalAddress(10U) + 5U == PhysicalAddress(15U));
|
||||
static_assert(PhysicalAddress(10U) - 5U == PhysicalAddress(5U));
|
||||
static_assert([] {
|
||||
PhysicalAddress v(10);
|
||||
v += 5;
|
||||
PhysicalAddress v(10U);
|
||||
v += 5U;
|
||||
return v;
|
||||
}() == PhysicalAddress(15));
|
||||
}() == PhysicalAddress(15U));
|
||||
static_assert([] {
|
||||
PhysicalAddress v(10);
|
||||
v -= 5;
|
||||
PhysicalAddress v(10U);
|
||||
v -= 5U;
|
||||
return v;
|
||||
}() == PhysicalAddress(5));
|
||||
static_assert(PhysicalAddress(10)++ == PhysicalAddress(10));
|
||||
static_assert(++PhysicalAddress(10) == PhysicalAddress(11));
|
||||
static_assert(PhysicalAddress(10)-- == PhysicalAddress(10));
|
||||
static_assert(--PhysicalAddress(10) == PhysicalAddress(9));
|
||||
}() == PhysicalAddress(5U));
|
||||
static_assert(PhysicalAddress(10U)++ == PhysicalAddress(10U));
|
||||
static_assert(++PhysicalAddress(10U) == PhysicalAddress(11U));
|
||||
static_assert(PhysicalAddress(10U)-- == PhysicalAddress(10U));
|
||||
static_assert(--PhysicalAddress(10U) == PhysicalAddress(9U));
|
||||
|
||||
// Logical validations.
|
||||
static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111);
|
||||
static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110);
|
||||
static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010);
|
||||
static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010);
|
||||
static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000);
|
||||
static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101);
|
||||
static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111);
|
||||
static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111);
|
||||
static_assert((PhysicalAddress(0b11111111U) >> 1) == 0b01111111U);
|
||||
static_assert((PhysicalAddress(0b10101010U) >> 1) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) << 1) == 0b111111110U);
|
||||
static_assert((PhysicalAddress(0b01010101U) << 1) == 0b10101010U);
|
||||
static_assert((PhysicalAddress(0b11111111U) & 0b01010101U) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) & 0b10101010U) == 0b10101010U);
|
||||
static_assert((PhysicalAddress(0b01010101U) & 0b10101010U) == 0b00000000U);
|
||||
static_assert((PhysicalAddress(0b00000000U) | 0b01010101U) == 0b01010101U);
|
||||
static_assert((PhysicalAddress(0b11111111U) | 0b01010101U) == 0b11111111U);
|
||||
static_assert((PhysicalAddress(0b10101010U) | 0b01010101U) == 0b11111111U);
|
||||
|
||||
// Comparisons.
|
||||
static_assert(PhysicalAddress(0) == PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(0) != PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(0) < PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(0) <= PhysicalAddress(1));
|
||||
static_assert(PhysicalAddress(1) > PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(1) >= PhysicalAddress(0));
|
||||
static_assert(PhysicalAddress(0U) == PhysicalAddress(0U));
|
||||
static_assert(PhysicalAddress(0U) != PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(0U) < PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(0U) <= PhysicalAddress(1U));
|
||||
static_assert(PhysicalAddress(1U) > PhysicalAddress(0U));
|
||||
static_assert(PhysicalAddress(1U) >= PhysicalAddress(0U));
|
||||
|
||||
static_assert(!(PhysicalAddress(0) == PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0) != PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(1) < PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0)));
|
||||
static_assert(!(PhysicalAddress(0) > PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1)));
|
||||
static_assert(!(PhysicalAddress(0U) == PhysicalAddress(1U)));
|
||||
static_assert(!(PhysicalAddress(0U) != PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(1U) < PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(1U) <= PhysicalAddress(0U)));
|
||||
static_assert(!(PhysicalAddress(0U) > PhysicalAddress(1U)));
|
||||
static_assert(!(PhysicalAddress(0U) >= PhysicalAddress(1U)));
|
||||
|
||||
} // namespace Common
|
||||
|
||||
|
||||
@@ -548,8 +548,6 @@ add_library(core STATIC
|
||||
hle/service/es/es.h
|
||||
hle/service/eupld/eupld.cpp
|
||||
hle/service/eupld/eupld.h
|
||||
hle/service/event.cpp
|
||||
hle/service/event.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
@@ -676,8 +674,6 @@ add_library(core STATIC
|
||||
hle/service/mm/mm_u.h
|
||||
hle/service/mnpp/mnpp_app.cpp
|
||||
hle/service/mnpp/mnpp_app.h
|
||||
hle/service/mutex.cpp
|
||||
hle/service/mutex.h
|
||||
hle/service/ncm/ncm.cpp
|
||||
hle/service/ncm/ncm.h
|
||||
hle/service/nfc/common/amiibo_crypto.cpp
|
||||
@@ -790,6 +786,15 @@ add_library(core STATIC
|
||||
hle/service/nvnflinger/window.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
hle/service/olsc/olsc.h
|
||||
hle/service/os/event.cpp
|
||||
hle/service/os/event.h
|
||||
hle/service/os/multi_wait_holder.cpp
|
||||
hle/service/os/multi_wait_holder.h
|
||||
hle/service/os/multi_wait_utils.h
|
||||
hle/service/os/multi_wait.cpp
|
||||
hle/service/os/multi_wait.h
|
||||
hle/service/os/mutex.cpp
|
||||
hle/service/os/mutex.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
hle/service/pcie/pcie.h
|
||||
hle/service/pctl/pctl.cpp
|
||||
|
||||
@@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
return ValueToHex(context.pstate);
|
||||
} else if (id >= D0_REGISTER && id < Q0_REGISTER) {
|
||||
return ValueToHex(fprs[id - D0_REGISTER][0]);
|
||||
return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]);
|
||||
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
|
||||
return ValueToHex(fprs[id - Q0_REGISTER]);
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
@@ -406,7 +406,7 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
|
||||
} else if (id == CPSR_REGISTER) {
|
||||
context.pstate = HexToValue<u32>(value);
|
||||
} else if (id >= D0_REGISTER && id < Q0_REGISTER) {
|
||||
fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0};
|
||||
fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value);
|
||||
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
|
||||
fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
|
||||
} else if (id == FPSCR_REGISTER) {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
#include "core/hle/service/caps/caps_types.h"
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/os/event.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/os/event.h"
|
||||
|
||||
union Result;
|
||||
|
||||
|
||||
@@ -115,6 +115,11 @@ struct ArgumentTraits {
|
||||
static constexpr ArgumentType Type = ArgumentType::InData;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
consteval bool ConstIfReference() {
|
||||
return ((!std::is_reference_v<Ts> || std::is_const_v<std::remove_reference_t<Ts>>) && ... && true);
|
||||
}
|
||||
|
||||
struct RequestLayout {
|
||||
u32 copy_handle_count;
|
||||
u32 move_handle_count;
|
||||
@@ -435,6 +440,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
|
||||
}
|
||||
const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
|
||||
|
||||
static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
|
||||
using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
|
||||
|
||||
OutTemporaryBuffers buffers{};
|
||||
|
||||
@@ -4,10 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <span>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@@ -22,8 +21,10 @@ class Out {
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
/* implicit */ Out(const Out& t) : raw(t.raw) {}
|
||||
/* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ Out(Type* t) : raw(t) {}
|
||||
Out& operator=(const Out&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -37,6 +38,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -113,8 +118,10 @@ class OutCopyHandle {
|
||||
public:
|
||||
using Type = T*;
|
||||
|
||||
/* implicit */ OutCopyHandle(const OutCopyHandle& t) : raw(t.raw) {}
|
||||
/* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ OutCopyHandle(Type* t) : raw(t) {}
|
||||
OutCopyHandle& operator=(const OutCopyHandle&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -128,6 +135,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -137,8 +148,10 @@ class OutMoveHandle {
|
||||
public:
|
||||
using Type = T*;
|
||||
|
||||
/* implicit */ OutMoveHandle(const OutMoveHandle& t) : raw(t.raw) {}
|
||||
/* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
|
||||
/* implicit */ OutMoveHandle(Type* t) : raw(t) {}
|
||||
OutMoveHandle& operator=(const OutMoveHandle&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -152,6 +165,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
@@ -248,8 +265,10 @@ public:
|
||||
static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
|
||||
using Type = T;
|
||||
|
||||
/* implicit */ OutLargeData(const OutLargeData& t) : raw(t.raw) {}
|
||||
/* implicit */ OutLargeData(Type* t) : raw(t) {}
|
||||
/* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
|
||||
OutLargeData& operator=(const OutLargeData&) = delete;
|
||||
|
||||
Type* Get() const {
|
||||
return raw;
|
||||
@@ -263,6 +282,10 @@ public:
|
||||
return raw;
|
||||
}
|
||||
|
||||
operator Type*() const {
|
||||
return raw;
|
||||
}
|
||||
|
||||
private:
|
||||
Type* raw;
|
||||
};
|
||||
|
||||
@@ -115,6 +115,11 @@ private:
|
||||
if (type->GetName() == "save") {
|
||||
for (const auto& save_id : type->GetSubdirectories()) {
|
||||
for (const auto& user_id : save_id->GetSubdirectories()) {
|
||||
// Skip non user id subdirectories
|
||||
if (user_id->GetName().size() != 0x20) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -160,6 +165,10 @@ private:
|
||||
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
|
||||
// Temporary Storage
|
||||
for (const auto& user_id : type->GetSubdirectories()) {
|
||||
// Skip non user id subdirectories
|
||||
if (user_id->GetName().size() != 0x20) {
|
||||
continue;
|
||||
}
|
||||
for (const auto& title_id : user_id->GetSubdirectories()) {
|
||||
if (!title_id->GetFiles().empty() ||
|
||||
!title_id->GetSubdirectories().empty()) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "core/hle/service/glue/time/file_timestamp_worker.h"
|
||||
#include "core/hle/service/glue/time/standard_steady_clock_resource.h"
|
||||
#include "core/hle/service/glue/time/worker.h"
|
||||
#include "core/hle/service/os/multi_wait_utils.h"
|
||||
#include "core/hle/service/psc/time/common.h"
|
||||
#include "core/hle/service/psc/time/service_manager.h"
|
||||
#include "core/hle/service/psc/time/static.h"
|
||||
@@ -143,82 +144,46 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
Common::SetCurrentThreadName("TimeWorker");
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Low);
|
||||
|
||||
enum class EventType {
|
||||
Exit = 0,
|
||||
IpmModuleService_GetEvent = 1,
|
||||
PowerStateChange = 2,
|
||||
SignalAlarms = 3,
|
||||
UpdateLocalSystemClock = 4,
|
||||
UpdateNetworkSystemClock = 5,
|
||||
UpdateEphemeralSystemClock = 6,
|
||||
UpdateSteadyClock = 7,
|
||||
UpdateFileTimestamp = 8,
|
||||
AutoCorrect = 9,
|
||||
Max = 10,
|
||||
};
|
||||
|
||||
s32 num_objs{};
|
||||
std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{};
|
||||
std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{};
|
||||
|
||||
const auto AddWaiter{
|
||||
[&](Kernel::KSynchronizationObject* synchronization_object, EventType type) {
|
||||
// Open a new reference to the object.
|
||||
synchronization_object->Open();
|
||||
|
||||
// Insert into the list.
|
||||
wait_indices[num_objs] = type;
|
||||
wait_objs[num_objs++] = synchronization_object;
|
||||
}};
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
SCOPE_EXIT({
|
||||
for (s32 i = 0; i < num_objs; i++) {
|
||||
wait_objs[i]->Close();
|
||||
}
|
||||
});
|
||||
enum class EventType : s32 {
|
||||
Exit = 0,
|
||||
PowerStateChange = 1,
|
||||
SignalAlarms = 2,
|
||||
UpdateLocalSystemClock = 3,
|
||||
UpdateNetworkSystemClock = 4,
|
||||
UpdateEphemeralSystemClock = 5,
|
||||
UpdateSteadyClock = 6,
|
||||
UpdateFileTimestamp = 7,
|
||||
AutoCorrect = 8,
|
||||
};
|
||||
|
||||
s32 index{};
|
||||
|
||||
num_objs = {};
|
||||
wait_objs = {};
|
||||
if (m_pm_state_change_handler.m_priority != 0) {
|
||||
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
|
||||
// TODO
|
||||
// AddWaiter(gIPmModuleService::GetEvent(), 1);
|
||||
AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange);
|
||||
// TODO: gIPmModuleService::GetEvent() 1
|
||||
index = WaitAny(m_system.Kernel(),
|
||||
&m_event->GetReadableEvent(), // 0
|
||||
&m_alarm_worker.GetEvent() // 1
|
||||
);
|
||||
} else {
|
||||
AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
|
||||
// TODO
|
||||
// AddWaiter(gIPmModuleService::GetEvent(), 1);
|
||||
AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange);
|
||||
AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms);
|
||||
AddWaiter(m_local_clock_event, EventType::UpdateLocalSystemClock);
|
||||
AddWaiter(m_network_clock_event, EventType::UpdateNetworkSystemClock);
|
||||
AddWaiter(m_ephemeral_clock_event, EventType::UpdateEphemeralSystemClock);
|
||||
AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock);
|
||||
AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp);
|
||||
AddWaiter(m_standard_user_auto_correct_clock_event, EventType::AutoCorrect);
|
||||
// TODO: gIPmModuleService::GetEvent() 1
|
||||
index = WaitAny(m_system.Kernel(),
|
||||
&m_event->GetReadableEvent(), // 0
|
||||
&m_alarm_worker.GetEvent(), // 1
|
||||
&m_alarm_worker.GetTimerEvent().GetReadableEvent(), // 2
|
||||
m_local_clock_event, // 3
|
||||
m_network_clock_event, // 4
|
||||
m_ephemeral_clock_event, // 5
|
||||
&m_timer_steady_clock->GetReadableEvent(), // 6
|
||||
&m_timer_file_system->GetReadableEvent(), // 7
|
||||
m_standard_user_auto_correct_clock_event // 8
|
||||
);
|
||||
}
|
||||
|
||||
s32 out_index{-1};
|
||||
Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
|
||||
num_objs, -1);
|
||||
ASSERT(out_index >= 0 && out_index < num_objs);
|
||||
|
||||
if (stop_token.stop_requested()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (wait_indices[out_index]) {
|
||||
switch (static_cast<EventType>(index)) {
|
||||
case EventType::Exit:
|
||||
return;
|
||||
|
||||
case EventType::IpmModuleService_GetEvent:
|
||||
// TODO
|
||||
// IPmModuleService::GetEvent()
|
||||
// clear the event
|
||||
// Handle power state change event
|
||||
break;
|
||||
|
||||
case EventType::PowerStateChange:
|
||||
m_alarm_worker.GetEvent().Clear();
|
||||
if (m_pm_state_change_handler.m_priority <= 1) {
|
||||
@@ -235,19 +200,19 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
m_local_clock_event->Clear();
|
||||
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
auto res = m_local_clock->GetSystemClockContext(&context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
R_ASSERT(m_local_clock->GetSystemClockContext(&context));
|
||||
|
||||
m_set_sys->SetUserSystemClockContext(context);
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case EventType::UpdateNetworkSystemClock: {
|
||||
m_network_clock_event->Clear();
|
||||
|
||||
Service::PSC::Time::SystemClockContext context{};
|
||||
auto res = m_network_clock->GetSystemClockContext(&context);
|
||||
ASSERT(res == ResultSuccess);
|
||||
R_ASSERT(m_network_clock->GetSystemClockContext(&context));
|
||||
|
||||
m_set_sys->SetNetworkSystemClockContext(context);
|
||||
|
||||
s64 time{};
|
||||
@@ -267,7 +232,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
}
|
||||
|
||||
m_file_timestamp_worker.SetFilesystemPosixTime();
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case EventType::UpdateEphemeralSystemClock: {
|
||||
m_ephemeral_clock_event->Clear();
|
||||
@@ -295,7 +261,8 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
if (!g_ig_report_ephemeral_clock_context_set) {
|
||||
g_ig_report_ephemeral_clock_context_set = true;
|
||||
}
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
case EventType::UpdateSteadyClock:
|
||||
m_timer_steady_clock->Clear();
|
||||
@@ -314,21 +281,20 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
|
||||
m_standard_user_auto_correct_clock_event->Clear();
|
||||
|
||||
bool automatic_correction{};
|
||||
auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
&automatic_correction);
|
||||
ASSERT(res == ResultSuccess);
|
||||
R_ASSERT(m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
||||
&automatic_correction));
|
||||
|
||||
Service::PSC::Time::SteadyClockTimePoint time_point{};
|
||||
res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point);
|
||||
ASSERT(res == ResultSuccess);
|
||||
R_ASSERT(
|
||||
m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point));
|
||||
|
||||
m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
|
||||
m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/hid/hid_debug_server.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
@@ -11,7 +12,6 @@
|
||||
|
||||
#include "hid_core/resources/touch_screen/gesture.h"
|
||||
#include "hid_core/resources/touch_screen/touch_screen.h"
|
||||
#include "hid_core/resources/touch_screen/touch_types.h"
|
||||
|
||||
namespace Service::HID {
|
||||
|
||||
@@ -24,14 +24,14 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{0, nullptr, "DeactivateDebugPad"},
|
||||
{1, nullptr, "SetDebugPadAutoPilotState"},
|
||||
{2, nullptr, "UnsetDebugPadAutoPilotState"},
|
||||
{10, &IHidDebugServer::DeactivateTouchScreen, "DeactivateTouchScreen"},
|
||||
{11, &IHidDebugServer::SetTouchScreenAutoPilotState, "SetTouchScreenAutoPilotState"},
|
||||
{12, &IHidDebugServer::UnsetTouchScreenAutoPilotState, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, &IHidDebugServer::GetTouchScreenConfiguration, "GetTouchScreenConfiguration"},
|
||||
{14, &IHidDebugServer::ProcessTouchScreenAutoTune, "ProcessTouchScreenAutoTune"},
|
||||
{15, &IHidDebugServer::ForceStopTouchScreenManagement, "ForceStopTouchScreenManagement"},
|
||||
{16, &IHidDebugServer::ForceRestartTouchScreenManagement, "ForceRestartTouchScreenManagement"},
|
||||
{17, &IHidDebugServer::IsTouchScreenManaged, "IsTouchScreenManaged"},
|
||||
{10, C<&IHidDebugServer::DeactivateTouchScreen>, "DeactivateTouchScreen"},
|
||||
{11, C<&IHidDebugServer::SetTouchScreenAutoPilotState>, "SetTouchScreenAutoPilotState"},
|
||||
{12, C<&IHidDebugServer::UnsetTouchScreenAutoPilotState>, "UnsetTouchScreenAutoPilotState"},
|
||||
{13, C<&IHidDebugServer::GetTouchScreenConfiguration>, "GetTouchScreenConfiguration"},
|
||||
{14, C<&IHidDebugServer::ProcessTouchScreenAutoTune>, "ProcessTouchScreenAutoTune"},
|
||||
{15, C<&IHidDebugServer::ForceStopTouchScreenManagement>, "ForceStopTouchScreenManagement"},
|
||||
{16, C<&IHidDebugServer::ForceRestartTouchScreenManagement>, "ForceRestartTouchScreenManagement"},
|
||||
{17, C<&IHidDebugServer::IsTouchScreenManaged>, "IsTouchScreenManaged"},
|
||||
{20, nullptr, "DeactivateMouse"},
|
||||
{21, nullptr, "SetMouseAutoPilotState"},
|
||||
{22, nullptr, "UnsetMouseAutoPilotState"},
|
||||
@@ -47,7 +47,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{60, nullptr, "ClearNpadSystemCommonPolicy"},
|
||||
{61, nullptr, "DeactivateNpad"},
|
||||
{62, nullptr, "ForceDisconnectNpad"},
|
||||
{91, &IHidDebugServer::DeactivateGesture, "DeactivateGesture"},
|
||||
{91, C<&IHidDebugServer::DeactivateGesture>, "DeactivateGesture"},
|
||||
{110, nullptr, "DeactivateHomeButton"},
|
||||
{111, nullptr, "SetHomeButtonAutoPilotState"},
|
||||
{112, nullptr, "UnsetHomeButtonAutoPilotState"},
|
||||
@@ -160,169 +160,122 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
}
|
||||
|
||||
IHidDebugServer::~IHidDebugServer() = default;
|
||||
void IHidDebugServer::DeactivateTouchScreen(HLERequestContext& ctx) {
|
||||
|
||||
Result IHidDebugServer::DeactivateTouchScreen() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetTouchScreen()->Deactivate();
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->Deactivate());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::SetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::SetTouchScreenAutoPilotState(
|
||||
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer) {
|
||||
AutoPilotState auto_pilot{};
|
||||
auto_pilot.count = ctx.GetReadBufferNumElements<TouchState>();
|
||||
const auto buffer = ctx.ReadBuffer();
|
||||
|
||||
auto_pilot.count = std::min(auto_pilot.count, static_cast<u64>(auto_pilot.state.size()));
|
||||
memcpy(auto_pilot.state.data(), buffer.data(), auto_pilot.count * sizeof(TouchState));
|
||||
auto_pilot.count =
|
||||
static_cast<u64>(std::min(auto_pilot_buffer.size(), auto_pilot.state.size()));
|
||||
memcpy(auto_pilot.state.data(), auto_pilot_buffer.data(),
|
||||
auto_pilot.count * sizeof(TouchState));
|
||||
|
||||
LOG_INFO(Service_HID, "called, auto_pilot_count={}", auto_pilot.count);
|
||||
|
||||
const Result result =
|
||||
GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->SetTouchScreenAutoPilotState(auto_pilot));
|
||||
}
|
||||
|
||||
void IHidDebugServer::UnsetTouchScreenAutoPilotState(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::UnsetTouchScreenAutoPilotState() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->UnsetTouchScreenAutoPilotState());
|
||||
}
|
||||
|
||||
void IHidDebugServer::GetTouchScreenConfiguration(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
Result IHidDebugServer::GetTouchScreenConfiguration(
|
||||
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", aruid.pid);
|
||||
|
||||
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
R_TRY(GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
|
||||
*out_touchscreen_config, aruid.pid));
|
||||
|
||||
Core::HID::TouchScreenConfigurationForNx touchscreen_config{};
|
||||
const Result result = GetResourceManager()->GetTouchScreen()->GetTouchScreenConfiguration(
|
||||
touchscreen_config, applet_resource_user_id);
|
||||
|
||||
if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
||||
touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
|
||||
touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
||||
if (out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Heat2 &&
|
||||
out_touchscreen_config->mode != Core::HID::TouchScreenModeForNx::Finger) {
|
||||
out_touchscreen_config->mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(result);
|
||||
rb.PushRaw(touchscreen_config);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::ProcessTouchScreenAutoTune(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::ProcessTouchScreenAutoTune() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_RETURN(GetResourceManager()->GetTouchScreen()->ProcessTouchScreenAutoTune());
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceStopTouchScreenManagement(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::ForceStopTouchScreenManagement() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
return;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result result = ResultSuccess;
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
auto gesture = GetResourceManager()->GetGesture();
|
||||
|
||||
if (firmware_settings->IsTouchI2cManaged()) {
|
||||
result = touch_screen->IsActive(is_touch_active);
|
||||
if (result.IsSuccess()) {
|
||||
result = gesture->IsActive(is_gesture_active);
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
R_TRY(touch_screen->IsActive(is_touch_active));
|
||||
R_TRY(gesture->IsActive(is_gesture_active));
|
||||
|
||||
if (is_touch_active) {
|
||||
R_TRY(touch_screen->Deactivate());
|
||||
}
|
||||
if (result.IsSuccess() && is_touch_active) {
|
||||
result = touch_screen->Deactivate();
|
||||
}
|
||||
if (result.IsSuccess() && is_gesture_active) {
|
||||
result = gesture->Deactivate();
|
||||
if (is_gesture_active) {
|
||||
R_TRY(gesture->Deactivate());
|
||||
}
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::ForceRestartTouchScreenManagement(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
u32 basic_gesture_id;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IHidDebugServer::ForceRestartTouchScreenManagement(u32 basic_gesture_id,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
|
||||
parameters.basic_gesture_id, parameters.applet_resource_user_id);
|
||||
basic_gesture_id, aruid.pid);
|
||||
|
||||
Result result = ResultSuccess;
|
||||
auto touch_screen = GetResourceManager()->GetTouchScreen();
|
||||
auto gesture = GetResourceManager()->GetGesture();
|
||||
|
||||
if (firmware_settings->IsDeviceManaged() && firmware_settings->IsTouchI2cManaged()) {
|
||||
result = gesture->Activate();
|
||||
if (result.IsSuccess()) {
|
||||
result =
|
||||
gesture->Activate(parameters.applet_resource_user_id, parameters.basic_gesture_id);
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->Activate();
|
||||
}
|
||||
if (result.IsSuccess()) {
|
||||
result = touch_screen->Activate(parameters.applet_resource_user_id);
|
||||
}
|
||||
R_TRY(gesture->Activate());
|
||||
R_TRY(gesture->Activate(aruid.pid, basic_gesture_id));
|
||||
R_TRY(touch_screen->Activate());
|
||||
R_TRY(touch_screen->Activate(aruid.pid));
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::IsTouchScreenManaged(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::IsTouchScreenManaged(Out<bool> out_is_managed) {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
bool is_touch_active{};
|
||||
bool is_gesture_active{};
|
||||
R_TRY(GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active));
|
||||
R_TRY(GetResourceManager()->GetGesture()->IsActive(is_gesture_active));
|
||||
|
||||
Result result = GetResourceManager()->GetTouchScreen()->IsActive(is_touch_active);
|
||||
if (result.IsSuccess()) {
|
||||
result = GetResourceManager()->GetGesture()->IsActive(is_gesture_active);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(result);
|
||||
rb.Push(is_touch_active | is_gesture_active);
|
||||
*out_is_managed = is_touch_active || is_gesture_active;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IHidDebugServer::DeactivateGesture(HLERequestContext& ctx) {
|
||||
Result IHidDebugServer::DeactivateGesture() {
|
||||
LOG_INFO(Service_HID, "called");
|
||||
|
||||
Result result = ResultSuccess;
|
||||
|
||||
if (!firmware_settings->IsDeviceManaged()) {
|
||||
result = GetResourceManager()->GetGesture()->Deactivate();
|
||||
R_RETURN(GetResourceManager()->GetGesture()->Deactivate());
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/resources/touch_screen/touch_types.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -20,15 +22,19 @@ public:
|
||||
~IHidDebugServer() override;
|
||||
|
||||
private:
|
||||
void DeactivateTouchScreen(HLERequestContext& ctx);
|
||||
void SetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void UnsetTouchScreenAutoPilotState(HLERequestContext& ctx);
|
||||
void GetTouchScreenConfiguration(HLERequestContext& ctx);
|
||||
void ProcessTouchScreenAutoTune(HLERequestContext& ctx);
|
||||
void ForceStopTouchScreenManagement(HLERequestContext& ctx);
|
||||
void ForceRestartTouchScreenManagement(HLERequestContext& ctx);
|
||||
void IsTouchScreenManaged(HLERequestContext& ctx);
|
||||
void DeactivateGesture(HLERequestContext& ctx);
|
||||
Result DeactivateTouchScreen();
|
||||
Result SetTouchScreenAutoPilotState(
|
||||
InArray<TouchState, BufferAttr_HipcMapAlias> auto_pilot_buffer);
|
||||
Result UnsetTouchScreenAutoPilotState();
|
||||
Result GetTouchScreenConfiguration(
|
||||
Out<Core::HID::TouchScreenConfigurationForNx> out_touchscreen_config,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result ProcessTouchScreenAutoTune();
|
||||
Result ForceStopTouchScreenManagement();
|
||||
Result ForceRestartTouchScreenManagement(u32 basic_gesture_id,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result IsTouchScreenManaged(Out<bool> out_is_managed);
|
||||
Result DeactivateGesture();
|
||||
|
||||
std::shared_ptr<ResourceManager> GetResourceManager();
|
||||
|
||||
|
||||
+189
-385
@@ -9,6 +9,7 @@
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/hid/irs.h"
|
||||
#include "core/hle/service/ipc_helpers.h"
|
||||
#include "core/memory.h"
|
||||
@@ -28,24 +29,24 @@ namespace Service::IRS {
|
||||
IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
|
||||
{303, &IRS::DeactivateIrsensor, "DeactivateIrsensor"},
|
||||
{304, &IRS::GetIrsensorSharedMemoryHandle, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, &IRS::StopImageProcessor, "StopImageProcessor"},
|
||||
{306, &IRS::RunMomentProcessor, "RunMomentProcessor"},
|
||||
{307, &IRS::RunClusteringProcessor, "RunClusteringProcessor"},
|
||||
{308, &IRS::RunImageTransferProcessor, "RunImageTransferProcessor"},
|
||||
{309, &IRS::GetImageTransferProcessorState, "GetImageTransferProcessorState"},
|
||||
{310, &IRS::RunTeraPluginProcessor, "RunTeraPluginProcessor"},
|
||||
{311, &IRS::GetNpadIrCameraHandle, "GetNpadIrCameraHandle"},
|
||||
{312, &IRS::RunPointingProcessor, "RunPointingProcessor"},
|
||||
{313, &IRS::SuspendImageProcessor, "SuspendImageProcessor"},
|
||||
{314, &IRS::CheckFirmwareVersion, "CheckFirmwareVersion"},
|
||||
{315, &IRS::SetFunctionLevel, "SetFunctionLevel"},
|
||||
{316, &IRS::RunImageTransferExProcessor, "RunImageTransferExProcessor"},
|
||||
{317, &IRS::RunIrLedProcessor, "RunIrLedProcessor"},
|
||||
{318, &IRS::StopImageProcessorAsync, "StopImageProcessorAsync"},
|
||||
{319, &IRS::ActivateIrsensorWithFunctionLevel, "ActivateIrsensorWithFunctionLevel"},
|
||||
{302, C<&IRS::ActivateIrsensor>, "ActivateIrsensor"},
|
||||
{303, C<&IRS::DeactivateIrsensor>, "DeactivateIrsensor"},
|
||||
{304, C<&IRS::GetIrsensorSharedMemoryHandle>, "GetIrsensorSharedMemoryHandle"},
|
||||
{305, C<&IRS::StopImageProcessor>, "StopImageProcessor"},
|
||||
{306, C<&IRS::RunMomentProcessor>, "RunMomentProcessor"},
|
||||
{307, C<&IRS::RunClusteringProcessor>, "RunClusteringProcessor"},
|
||||
{308, C<&IRS::RunImageTransferProcessor>, "RunImageTransferProcessor"},
|
||||
{309, C<&IRS::GetImageTransferProcessorState>, "GetImageTransferProcessorState"},
|
||||
{310, C<&IRS::RunTeraPluginProcessor>, "RunTeraPluginProcessor"},
|
||||
{311, C<&IRS::GetNpadIrCameraHandle>, "GetNpadIrCameraHandle"},
|
||||
{312, C<&IRS::RunPointingProcessor>, "RunPointingProcessor"},
|
||||
{313, C<&IRS::SuspendImageProcessor>, "SuspendImageProcessor"},
|
||||
{314, C<&IRS::CheckFirmwareVersion>, "CheckFirmwareVersion"},
|
||||
{315, C<&IRS::SetFunctionLevel>, "SetFunctionLevel"},
|
||||
{316, C<&IRS::RunImageTransferExProcessor>, "RunImageTransferExProcessor"},
|
||||
{317, C<&IRS::RunIrLedProcessor>, "RunIrLedProcessor"},
|
||||
{318, C<&IRS::StopImageProcessorAsync>, "StopImageProcessorAsync"},
|
||||
{319, C<&IRS::ActivateIrsensorWithFunctionLevel>, "ActivateIrsensorWithFunctionLevel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -57,489 +58,292 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
|
||||
}
|
||||
IRS::~IRS() = default;
|
||||
|
||||
void IRS::ActivateIrsensor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
Result IRS::ActivateIrsensor(ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::DeactivateIrsensor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}",
|
||||
applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
Result IRS::DeactivateIrsensor(ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
Result IRS::GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", aruid.pid);
|
||||
|
||||
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
|
||||
*out_shared_memory = &system.Kernel().GetIrsSharedMem();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Stop Image processor
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Stop Image processor
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunMomentProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
Core::IrSensor::PackedMomentProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::RunMomentProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedMomentProcessorConfig& processor_config) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<MomentProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<MomentProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<MomentProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunClusteringProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
Core::IrSensor::PackedClusteringProcessorConfig processor_config;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::RunClusteringProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ClusteringProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ClusteringProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ClusteringProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
Core::IrSensor::PackedImageTransferProcessorConfig processor_config;
|
||||
u32 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
|
||||
Result IRS::RunImageTransferProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
|
||||
if (t_mem.IsNull()) {
|
||||
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultUnknown);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
|
||||
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, t_mem->GetSize(), parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, t_mem->GetSize(),
|
||||
aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::GetImageTransferProcessorState(
|
||||
Out<Core::IrSensor::ImageTransferProcessorState> out_state,
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data) {
|
||||
LOG_DEBUG(Service_IRS, "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsError()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
const auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
|
||||
if (device.mode != Core::IrSensor::IrSensorMode::ImageTransferProcessor) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(InvalidProcessorState);
|
||||
return;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
R_UNLESS(device.mode == Core::IrSensor::IrSensorMode::ImageTransferProcessor,
|
||||
InvalidProcessorState);
|
||||
|
||||
std::vector<u8> data{};
|
||||
const auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
const auto& state = image_transfer_processor.GetState(data);
|
||||
*out_state = GetProcessor<ImageTransferProcessor>(camera_handle).GetState(out_buffer_data);
|
||||
|
||||
ctx.WriteBuffer(data);
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(state);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
|
||||
Result IRS::RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.processor_config.mode, parameters.processor_config.required_mcu_version.major,
|
||||
parameters.processor_config.required_mcu_version.minor, parameters.applet_resource_user_id);
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<TeraPluginProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
const auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessor<TeraPluginProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
Result IRS::GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
|
||||
Core::HID::NpadIdType npad_id) {
|
||||
R_UNLESS(HID::IsNpadIdValid(npad_id), HID::ResultInvalidNpadId);
|
||||
|
||||
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
|
||||
npad_id != Core::HID::NpadIdType::Handheld) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(Service::HID::ResultInvalidNpadId);
|
||||
return;
|
||||
}
|
||||
|
||||
Core::IrSensor::IrCameraHandle camera_handle{
|
||||
*out_camera_handle = {
|
||||
.npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)),
|
||||
.npad_type = Core::HID::NpadStyleIndex::None,
|
||||
};
|
||||
|
||||
LOG_INFO(Service_IRS, "called, npad_id={}, camera_npad_id={}, camera_npad_type={}", npad_id,
|
||||
camera_handle.npad_id, camera_handle.npad_type);
|
||||
out_camera_handle->npad_id, out_camera_handle->npad_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(camera_handle);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunPointingProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
Result IRS::RunPointingProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle,
|
||||
const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<PointingProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::SuspendImageProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Suspend image processor
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Suspend image processor
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::CheckFirmwareVersion(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
Result IRS::CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedMcuVersion mcu_version,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid, mcu_version.major,
|
||||
mcu_version.minor);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Check firmware version
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Check firmware version
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::SetFunctionLevel(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
Result IRS::SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(
|
||||
Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, function_level={}, applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level,
|
||||
applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, function_level.function_level, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Set Function level
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Set Function level
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
Core::IrSensor::PackedImageTransferProcessorExConfig processor_config;
|
||||
u64 transfer_memory_size;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
|
||||
Result IRS::RunImageTransferExProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem) {
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
const auto t_mem_handle{ctx.GetCopyHandle(0)};
|
||||
|
||||
auto t_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(t_mem_handle);
|
||||
ASSERT_MSG(t_mem->GetSize() == transfer_memory_size, "t_mem has incorrect size");
|
||||
|
||||
LOG_INFO(Service_IRS,
|
||||
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
|
||||
"applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.transfer_memory_size, parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, transfer_memory_size, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(parameters.camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(parameters.camera_handle, device);
|
||||
auto& image_transfer_processor =
|
||||
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
|
||||
image_transfer_processor.SetConfig(parameters.processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessorWithCoreContext<ImageTransferProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<ImageTransferProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::RunIrLedProcessor(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
|
||||
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
|
||||
const auto applet_resource_user_id{rp.Pop<u64>()};
|
||||
|
||||
Result IRS::RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedIrLedProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
|
||||
"applet_resource_user_id={}",
|
||||
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
|
||||
processor_config.required_mcu_version.major,
|
||||
processor_config.required_mcu_version.minor, applet_resource_user_id);
|
||||
processor_config.required_mcu_version.minor, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(camera_handle);
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
if (result.IsSuccess()) {
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
}
|
||||
auto& device = GetIrCameraSharedMemoryDeviceEntry(camera_handle);
|
||||
MakeProcessor<IrLedProcessor>(camera_handle, device);
|
||||
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
|
||||
image_transfer_processor.SetConfig(processor_config);
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::IR);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::StopImageProcessorAsync(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::IrCameraHandle camera_handle;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS,
|
||||
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
|
||||
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
|
||||
parameters.applet_resource_user_id);
|
||||
camera_handle.npad_type, camera_handle.npad_id, aruid.pid);
|
||||
|
||||
auto result = IsIrCameraHandleValid(parameters.camera_handle);
|
||||
if (result.IsSuccess()) {
|
||||
// TODO: Stop image processor async
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
result = ResultSuccess;
|
||||
}
|
||||
R_TRY(IsIrCameraHandleValid(camera_handle));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
// TODO: Stop image processor async
|
||||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
|
||||
Common::Input::PollingMode::Active);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
struct Parameters {
|
||||
Core::IrSensor::PackedFunctionLevel function_level;
|
||||
INSERT_PADDING_WORDS_NOINIT(1);
|
||||
u64 applet_resource_user_id;
|
||||
};
|
||||
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
|
||||
|
||||
const auto parameters{rp.PopRaw<Parameters>()};
|
||||
|
||||
Result IRS::ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid) {
|
||||
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
|
||||
parameters.function_level.function_level, parameters.applet_resource_user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
function_level.function_level, aruid.pid);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "hid_core/hid_types.h"
|
||||
#include "hid_core/irsensor/irs_types.h"
|
||||
@@ -35,26 +36,73 @@ private:
|
||||
};
|
||||
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
|
||||
|
||||
void ActivateIrsensor(HLERequestContext& ctx);
|
||||
void DeactivateIrsensor(HLERequestContext& ctx);
|
||||
void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx);
|
||||
void StopImageProcessor(HLERequestContext& ctx);
|
||||
void RunMomentProcessor(HLERequestContext& ctx);
|
||||
void RunClusteringProcessor(HLERequestContext& ctx);
|
||||
void RunImageTransferProcessor(HLERequestContext& ctx);
|
||||
void GetImageTransferProcessorState(HLERequestContext& ctx);
|
||||
void RunTeraPluginProcessor(HLERequestContext& ctx);
|
||||
void GetNpadIrCameraHandle(HLERequestContext& ctx);
|
||||
void RunPointingProcessor(HLERequestContext& ctx);
|
||||
void SuspendImageProcessor(HLERequestContext& ctx);
|
||||
void CheckFirmwareVersion(HLERequestContext& ctx);
|
||||
void SetFunctionLevel(HLERequestContext& ctx);
|
||||
void RunImageTransferExProcessor(HLERequestContext& ctx);
|
||||
void RunIrLedProcessor(HLERequestContext& ctx);
|
||||
void StopImageProcessorAsync(HLERequestContext& ctx);
|
||||
void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx);
|
||||
Result ActivateIrsensor(ClientAppletResourceUserId aruid);
|
||||
|
||||
Result DeactivateIrsensor(ClientAppletResourceUserId aruid);
|
||||
|
||||
Result GetIrsensorSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory,
|
||||
ClientAppletResourceUserId aruid);
|
||||
Result StopImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result RunMomentProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedMomentProcessorConfig& processor_config);
|
||||
|
||||
Result RunClusteringProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedClusteringProcessorConfig& processor_config);
|
||||
|
||||
Result RunImageTransferProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
|
||||
|
||||
Result GetImageTransferProcessorState(
|
||||
Out<Core::IrSensor::ImageTransferProcessorState> out_state,
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_buffer_data);
|
||||
|
||||
Result RunTeraPluginProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedTeraPluginProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result GetNpadIrCameraHandle(Out<Core::IrSensor::IrCameraHandle> out_camera_handle,
|
||||
Core::HID::NpadIdType npad_id);
|
||||
|
||||
Result RunPointingProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle,
|
||||
const Core::IrSensor::PackedPointingProcessorConfig& processor_config,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result SuspendImageProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result CheckFirmwareVersion(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedMcuVersion mcu_version,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result SetFunctionLevel(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result RunImageTransferExProcessor(
|
||||
Core::IrSensor::IrCameraHandle camera_handle, ClientAppletResourceUserId aruid,
|
||||
const Core::IrSensor::PackedImageTransferProcessorExConfig& processor_config,
|
||||
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> t_mem);
|
||||
|
||||
Result RunIrLedProcessor(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
Core::IrSensor::PackedIrLedProcessorConfig processor_config,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result StopImageProcessorAsync(Core::IrSensor::IrCameraHandle camera_handle,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result ActivateIrsensorWithFunctionLevel(Core::IrSensor::PackedFunctionLevel function_level,
|
||||
ClientAppletResourceUserId aruid);
|
||||
|
||||
Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
|
||||
|
||||
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
|
||||
const Core::IrSensor::IrCameraHandle& camera_handle);
|
||||
|
||||
|
||||
@@ -123,6 +123,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
vm.va_range_end = params.va_range_end;
|
||||
}
|
||||
|
||||
const u64 max_big_page_bits = Common::Log2Ceil64(vm.va_range_end);
|
||||
|
||||
const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)};
|
||||
const auto end_pages{static_cast<u32>(vm.va_range_split >> VM::PAGE_SIZE_BITS)};
|
||||
vm.small_page_allocator = std::make_shared<VM::Allocator>(start_pages, end_pages);
|
||||
@@ -132,8 +134,8 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
|
||||
static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)};
|
||||
vm.big_page_allocator = std::make_unique<VM::Allocator>(start_big_pages, end_big_pages);
|
||||
|
||||
gmmu = std::make_shared<Tegra::MemoryManager>(system, 40, vm.big_page_size_bits,
|
||||
VM::PAGE_SIZE_BITS);
|
||||
gmmu = std::make_shared<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split,
|
||||
vm.big_page_size_bits, VM::PAGE_SIZE_BITS);
|
||||
system.GPU().InitAddressSpace(*gmmu);
|
||||
vm.initialised = true;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_item.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
|
||||
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
|
||||
#include "core/hle/service/nvnflinger/hardware_composer.h"
|
||||
#include "core/hle/service/nvnflinger/hwc_layer.h"
|
||||
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
|
||||
@@ -46,31 +45,9 @@ HardwareComposer::HardwareComposer() = default;
|
||||
HardwareComposer::~HardwareComposer() = default;
|
||||
|
||||
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp) {
|
||||
boost::container::small_vector<HwcLayer, 2> composition_stack;
|
||||
|
||||
m_frame_number += frame_advance;
|
||||
|
||||
// Release any necessary framebuffers.
|
||||
for (auto& [layer_id, framebuffer] : m_framebuffers) {
|
||||
if (framebuffer.release_frame_number > m_frame_number) {
|
||||
// Not yet ready to release this framebuffer.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!framebuffer.is_acquired) {
|
||||
// Already released.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
|
||||
// TODO: support release fence
|
||||
// This is needed to prevent screen tearing
|
||||
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
|
||||
framebuffer.is_acquired = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set default speed limit to 100%.
|
||||
*out_speed_scale = 1.0f;
|
||||
|
||||
@@ -142,7 +119,30 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||
MicroProfileFlip();
|
||||
|
||||
// Advance by at least one frame.
|
||||
return swap_interval.value_or(1);
|
||||
const u32 frame_advance = swap_interval.value_or(1);
|
||||
m_frame_number += frame_advance;
|
||||
|
||||
// Release any necessary framebuffers.
|
||||
for (auto& [layer_id, framebuffer] : m_framebuffers) {
|
||||
if (framebuffer.release_frame_number > m_frame_number) {
|
||||
// Not yet ready to release this framebuffer.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!framebuffer.is_acquired) {
|
||||
// Already released.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
|
||||
// TODO: support release fence
|
||||
// This is needed to prevent screen tearing
|
||||
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
|
||||
framebuffer.is_acquired = false;
|
||||
}
|
||||
}
|
||||
|
||||
return frame_advance;
|
||||
}
|
||||
|
||||
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
~HardwareComposer();
|
||||
|
||||
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance);
|
||||
Nvidia::Devices::nvdisp_disp0& nvdisp);
|
||||
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
|
||||
|
||||
private:
|
||||
|
||||
@@ -291,8 +291,7 @@ void Nvnflinger::Compose() {
|
||||
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
|
||||
ASSERT(nvdisp);
|
||||
|
||||
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp,
|
||||
swap_interval);
|
||||
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/service/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/os/event.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_hardware_timer.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/svc_common.h"
|
||||
#include "core/hle/service/os/multi_wait.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
MultiWait::MultiWait() = default;
|
||||
MultiWait::~MultiWait() = default;
|
||||
|
||||
MultiWaitHolder* MultiWait::WaitAny(Kernel::KernelCore& kernel) {
|
||||
return this->TimedWaitImpl(kernel, -1);
|
||||
}
|
||||
|
||||
MultiWaitHolder* MultiWait::TryWaitAny(Kernel::KernelCore& kernel) {
|
||||
return this->TimedWaitImpl(kernel, 0);
|
||||
}
|
||||
|
||||
MultiWaitHolder* MultiWait::TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns) {
|
||||
return this->TimedWaitImpl(kernel, kernel.HardwareTimer().GetTick() + timeout_ns);
|
||||
}
|
||||
|
||||
MultiWaitHolder* MultiWait::TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick) {
|
||||
std::array<MultiWaitHolder*, Kernel::Svc::ArgumentHandleCountMax> holders{};
|
||||
std::array<Kernel::KSynchronizationObject*, Kernel::Svc::ArgumentHandleCountMax> objects{};
|
||||
|
||||
s32 out_index = -1;
|
||||
s32 num_objects = 0;
|
||||
|
||||
for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it++) {
|
||||
ASSERT(num_objects < Kernel::Svc::ArgumentHandleCountMax);
|
||||
holders[num_objects] = std::addressof(*it);
|
||||
objects[num_objects] = it->GetNativeHandle();
|
||||
num_objects++;
|
||||
}
|
||||
|
||||
Kernel::KSynchronizationObject::Wait(kernel, std::addressof(out_index), objects.data(),
|
||||
num_objects, timeout_tick);
|
||||
|
||||
if (out_index == -1) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return holders[out_index];
|
||||
}
|
||||
}
|
||||
|
||||
void MultiWait::MoveAll(MultiWait* other) {
|
||||
while (!other->m_wait_list.empty()) {
|
||||
MultiWaitHolder& holder = other->m_wait_list.front();
|
||||
holder.UnlinkFromMultiWait();
|
||||
holder.LinkToMultiWait(this);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/os/multi_wait_holder.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
|
||||
class MultiWait final {
|
||||
public:
|
||||
explicit MultiWait();
|
||||
~MultiWait();
|
||||
|
||||
public:
|
||||
MultiWaitHolder* WaitAny(Kernel::KernelCore& kernel);
|
||||
MultiWaitHolder* TryWaitAny(Kernel::KernelCore& kernel);
|
||||
MultiWaitHolder* TimedWaitAny(Kernel::KernelCore& kernel, s64 timeout_ns);
|
||||
// TODO: SdkReplyAndReceive?
|
||||
|
||||
void MoveAll(MultiWait* other);
|
||||
|
||||
private:
|
||||
MultiWaitHolder* TimedWaitImpl(Kernel::KernelCore& kernel, s64 timeout_tick);
|
||||
|
||||
private:
|
||||
friend class MultiWaitHolder;
|
||||
using ListType = Common::IntrusiveListMemberTraits<&MultiWaitHolder::m_list_node>::ListType;
|
||||
ListType m_wait_list{};
|
||||
};
|
||||
|
||||
} // namespace Service
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/os/multi_wait.h"
|
||||
#include "core/hle/service/os/multi_wait_holder.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
void MultiWaitHolder::LinkToMultiWait(MultiWait* multi_wait) {
|
||||
if (m_multi_wait != nullptr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
m_multi_wait = multi_wait;
|
||||
m_multi_wait->m_wait_list.push_back(*this);
|
||||
}
|
||||
|
||||
void MultiWaitHolder::UnlinkFromMultiWait() {
|
||||
if (m_multi_wait) {
|
||||
m_multi_wait->m_wait_list.erase(m_multi_wait->m_wait_list.iterator_to(*this));
|
||||
m_multi_wait = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Service
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/intrusive_list.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KSynchronizationObject;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service {
|
||||
|
||||
class MultiWait;
|
||||
|
||||
class MultiWaitHolder {
|
||||
public:
|
||||
explicit MultiWaitHolder(Kernel::KSynchronizationObject* native_handle)
|
||||
: m_native_handle(native_handle) {}
|
||||
|
||||
void LinkToMultiWait(MultiWait* multi_wait);
|
||||
void UnlinkFromMultiWait();
|
||||
|
||||
void SetUserData(uintptr_t user_data) {
|
||||
m_user_data = user_data;
|
||||
}
|
||||
|
||||
uintptr_t GetUserData() const {
|
||||
return m_user_data;
|
||||
}
|
||||
|
||||
Kernel::KSynchronizationObject* GetNativeHandle() const {
|
||||
return m_native_handle;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class MultiWait;
|
||||
Common::IntrusiveListNode m_list_node{};
|
||||
MultiWait* m_multi_wait{};
|
||||
Kernel::KSynchronizationObject* m_native_handle{};
|
||||
uintptr_t m_user_data{};
|
||||
};
|
||||
|
||||
} // namespace Service
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/os/multi_wait.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class AutoMultiWaitHolder {
|
||||
private:
|
||||
MultiWaitHolder m_holder;
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) {
|
||||
m_holder.LinkToMultiWait(multi_wait);
|
||||
}
|
||||
|
||||
~AutoMultiWaitHolder() {
|
||||
m_holder.UnlinkFromMultiWait();
|
||||
}
|
||||
|
||||
std::pair<MultiWaitHolder*, int> ConvertResult(const std::pair<MultiWaitHolder*, int> result,
|
||||
int index) {
|
||||
if (result.first == std::addressof(m_holder)) {
|
||||
return std::make_pair(static_cast<MultiWaitHolder*>(nullptr), index);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using WaitAnyFunction = decltype(&MultiWait::WaitAny);
|
||||
|
||||
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
|
||||
MultiWait* multi_wait, WaitAnyFunction func,
|
||||
int) {
|
||||
return std::pair<MultiWaitHolder*, int>((multi_wait->*func)(kernel), -1);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
|
||||
MultiWait* multi_wait, WaitAnyFunction func,
|
||||
int index, T&& x, Args&&... args) {
|
||||
AutoMultiWaitHolder holder(multi_wait, std::forward<T>(x));
|
||||
return holder.ConvertResult(
|
||||
WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward<Args>(args)...), index);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
|
||||
MultiWait* multi_wait, WaitAnyFunction func,
|
||||
Args&&... args) {
|
||||
return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline std::pair<MultiWaitHolder*, int> WaitAnyImpl(Kernel::KernelCore& kernel,
|
||||
WaitAnyFunction func, Args&&... args) {
|
||||
MultiWait temp_multi_wait;
|
||||
return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
class NotBoolButInt {
|
||||
public:
|
||||
constexpr NotBoolButInt(int v) : m_value(v) {}
|
||||
constexpr operator int() const {
|
||||
return m_value;
|
||||
}
|
||||
explicit operator bool() const = delete;
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
||||
template <typename... Args>
|
||||
requires(sizeof...(Args) > 0)
|
||||
inline std::pair<MultiWaitHolder*, int> WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait,
|
||||
Args&&... args) {
|
||||
return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
requires(sizeof...(Args) > 0)
|
||||
inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) {
|
||||
return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward<Args>(args)...).second;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
requires(sizeof...(Args) > 0)
|
||||
inline std::pair<MultiWaitHolder*, int> TryWaitAny(Kernel::KernelCore& kernel,
|
||||
MultiWait* multi_wait, Args&&... args) {
|
||||
return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
requires(sizeof...(Args) > 0)
|
||||
inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) {
|
||||
return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward<Args>(args)...).second;
|
||||
}
|
||||
|
||||
} // namespace Service
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_synchronization_object.h"
|
||||
#include "core/hle/service/mutex.h"
|
||||
#include "core/hle/service/os/mutex.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@@ -20,50 +20,91 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
constexpr size_t MaximumWaitObjects = 0x40;
|
||||
|
||||
enum HandleType {
|
||||
enum class UserDataTag {
|
||||
Port,
|
||||
Session,
|
||||
DeferEvent,
|
||||
Event,
|
||||
};
|
||||
|
||||
ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} {
|
||||
class Port : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Port> {
|
||||
public:
|
||||
explicit Port(Kernel::KServerPort* server_port, SessionRequestHandlerFactory&& handler_factory)
|
||||
: MultiWaitHolder(server_port), m_handler_factory(std::move(handler_factory)) {
|
||||
this->SetUserData(static_cast<uintptr_t>(UserDataTag::Port));
|
||||
}
|
||||
|
||||
~Port() {
|
||||
this->GetNativeHandle()->Close();
|
||||
}
|
||||
|
||||
SessionRequestHandlerPtr CreateHandler() {
|
||||
return m_handler_factory();
|
||||
}
|
||||
|
||||
private:
|
||||
const SessionRequestHandlerFactory m_handler_factory;
|
||||
};
|
||||
|
||||
class Session : public MultiWaitHolder, public Common::IntrusiveListBaseNode<Session> {
|
||||
public:
|
||||
explicit Session(Kernel::KServerSession* server_session,
|
||||
std::shared_ptr<SessionRequestManager>&& manager)
|
||||
: MultiWaitHolder(server_session), m_manager(std::move(manager)) {
|
||||
this->SetUserData(static_cast<uintptr_t>(UserDataTag::Session));
|
||||
}
|
||||
|
||||
~Session() {
|
||||
this->GetNativeHandle()->Close();
|
||||
}
|
||||
|
||||
std::shared_ptr<SessionRequestManager>& GetManager() {
|
||||
return m_manager;
|
||||
}
|
||||
|
||||
std::shared_ptr<HLERequestContext>& GetContext() {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<SessionRequestManager> m_manager;
|
||||
std::shared_ptr<HLERequestContext> m_context;
|
||||
};
|
||||
|
||||
ServerManager::ServerManager(Core::System& system) : m_system{system}, m_selection_mutex{system} {
|
||||
// Initialize event.
|
||||
m_event = Kernel::KEvent::Create(system.Kernel());
|
||||
m_event->Initialize(nullptr);
|
||||
m_wakeup_event = Kernel::KEvent::Create(system.Kernel());
|
||||
m_wakeup_event->Initialize(nullptr);
|
||||
|
||||
// Register event.
|
||||
Kernel::KEvent::Register(system.Kernel(), m_event);
|
||||
Kernel::KEvent::Register(system.Kernel(), m_wakeup_event);
|
||||
|
||||
// Link to holder.
|
||||
m_wakeup_holder.emplace(std::addressof(m_wakeup_event->GetReadableEvent()));
|
||||
m_wakeup_holder->LinkToMultiWait(std::addressof(m_deferred_list));
|
||||
}
|
||||
|
||||
ServerManager::~ServerManager() {
|
||||
// Signal stop.
|
||||
m_stop_source.request_stop();
|
||||
m_event->Signal();
|
||||
m_wakeup_event->Signal();
|
||||
|
||||
// Wait for processing to stop.
|
||||
m_stopped.Wait();
|
||||
m_threads.clear();
|
||||
|
||||
// Clean up server ports.
|
||||
for (const auto& [port, handler] : m_ports) {
|
||||
port->Close();
|
||||
// Clean up ports.
|
||||
for (auto it = m_servers.begin(); it != m_servers.end(); it = m_servers.erase(it)) {
|
||||
delete std::addressof(*it);
|
||||
}
|
||||
|
||||
// Clean up sessions.
|
||||
for (const auto& [session, manager] : m_sessions) {
|
||||
session->Close();
|
||||
for (auto it = m_sessions.begin(); it != m_sessions.end(); it = m_sessions.erase(it)) {
|
||||
delete std::addressof(*it);
|
||||
}
|
||||
|
||||
for (const auto& request : m_deferrals) {
|
||||
request.session->Close();
|
||||
}
|
||||
|
||||
// Close event.
|
||||
m_event->GetReadableEvent().Close();
|
||||
m_event->Close();
|
||||
// Close wakeup event.
|
||||
m_wakeup_event->GetReadableEvent().Close();
|
||||
m_wakeup_event->Close();
|
||||
|
||||
if (m_deferral_event) {
|
||||
m_deferral_event->GetReadableEvent().Close();
|
||||
@@ -75,19 +116,19 @@ void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
|
||||
server_manager->m_system.RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
Result ServerManager::RegisterSession(Kernel::KServerSession* session,
|
||||
Result ServerManager::RegisterSession(Kernel::KServerSession* server_session,
|
||||
std::shared_ptr<SessionRequestManager> manager) {
|
||||
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
|
||||
|
||||
// We are taking ownership of the server session, so don't open it.
|
||||
auto* session = new Session(server_session, std::move(manager));
|
||||
|
||||
// Begin tracking the server session.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_sessions.emplace(session, std::move(manager));
|
||||
std::scoped_lock ll{m_deferred_list_mutex};
|
||||
m_sessions.push_back(*session);
|
||||
}
|
||||
|
||||
// Signal the wakeup event.
|
||||
m_event->Signal();
|
||||
// Register to wait on the session.
|
||||
this->LinkToDeferredList(session);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -95,21 +136,22 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session,
|
||||
Result ServerManager::RegisterNamedService(const std::string& service_name,
|
||||
SessionRequestHandlerFactory&& handler_factory,
|
||||
u32 max_sessions) {
|
||||
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
|
||||
|
||||
// Add the new server to sm: and get the moved server port.
|
||||
Kernel::KServerPort* server_port{};
|
||||
R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,
|
||||
max_sessions, handler_factory));
|
||||
|
||||
// We are taking ownership of the server port, so don't open it.
|
||||
auto* server = new Port(server_port, std::move(handler_factory));
|
||||
|
||||
// Begin tracking the server port.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_ports.emplace(server_port, std::move(handler_factory));
|
||||
std::scoped_lock ll{m_deferred_list_mutex};
|
||||
m_servers.push_back(*server);
|
||||
}
|
||||
|
||||
// Signal the wakeup event.
|
||||
m_event->Signal();
|
||||
// Register to wait on the server port.
|
||||
this->LinkToDeferredList(server);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -127,8 +169,6 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
|
||||
Result ServerManager::ManageNamedPort(const std::string& service_name,
|
||||
SessionRequestHandlerFactory&& handler_factory,
|
||||
u32 max_sessions) {
|
||||
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
|
||||
|
||||
// Create a new port.
|
||||
auto* port = Kernel::KPort::Create(m_system.Kernel());
|
||||
port->Initialize(max_sessions, false, 0);
|
||||
@@ -149,12 +189,18 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
|
||||
// Open a new reference to the server port.
|
||||
port->GetServerPort().Open();
|
||||
|
||||
// Begin tracking the server port.
|
||||
// Transfer ownership into a new port object.
|
||||
auto* server = new Port(std::addressof(port->GetServerPort()), std::move(handler_factory));
|
||||
|
||||
// Begin tracking the port.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
|
||||
std::scoped_lock ll{m_deferred_list_mutex};
|
||||
m_servers.push_back(*server);
|
||||
}
|
||||
|
||||
// Register to wait on the port.
|
||||
this->LinkToDeferredList(server);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -173,6 +219,11 @@ Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
|
||||
// Set the output.
|
||||
*out_event = m_deferral_event;
|
||||
|
||||
// Register to wait on the event.
|
||||
m_deferral_holder.emplace(std::addressof(m_deferral_event->GetReadableEvent()));
|
||||
m_deferral_holder->SetUserData(static_cast<uintptr_t>(UserDataTag::DeferEvent));
|
||||
this->LinkToDeferredList(std::addressof(*m_deferral_holder));
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -191,270 +242,185 @@ Result ServerManager::LoopProcess() {
|
||||
R_RETURN(this->LoopProcessImpl());
|
||||
}
|
||||
|
||||
void ServerManager::LinkToDeferredList(MultiWaitHolder* holder) {
|
||||
// Link.
|
||||
{
|
||||
std::scoped_lock lk{m_deferred_list_mutex};
|
||||
holder->LinkToMultiWait(std::addressof(m_deferred_list));
|
||||
}
|
||||
|
||||
// Signal the wakeup event.
|
||||
m_wakeup_event->Signal();
|
||||
}
|
||||
|
||||
void ServerManager::LinkDeferred() {
|
||||
std::scoped_lock lk{m_deferred_list_mutex};
|
||||
m_multi_wait.MoveAll(std::addressof(m_deferred_list));
|
||||
}
|
||||
|
||||
MultiWaitHolder* ServerManager::WaitSignaled() {
|
||||
// Ensure we are the only thread waiting for this server.
|
||||
std::scoped_lock lk{m_selection_mutex};
|
||||
|
||||
while (true) {
|
||||
this->LinkDeferred();
|
||||
|
||||
// If we're done, return before we start waiting.
|
||||
if (m_stop_source.stop_requested()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
|
||||
if (selected == std::addressof(*m_wakeup_holder)) {
|
||||
// Clear and restart if we were woken up.
|
||||
m_wakeup_event->Clear();
|
||||
} else {
|
||||
// Unlink and handle the event.
|
||||
selected->UnlinkFromMultiWait();
|
||||
return selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::Process(MultiWaitHolder* holder) {
|
||||
switch (static_cast<UserDataTag>(holder->GetUserData())) {
|
||||
case UserDataTag::Session:
|
||||
R_RETURN(this->OnSessionEvent(static_cast<Session*>(holder)));
|
||||
case UserDataTag::Port:
|
||||
R_RETURN(this->OnPortEvent(static_cast<Port*>(holder)));
|
||||
case UserDataTag::DeferEvent:
|
||||
R_RETURN(this->OnDeferralEvent());
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
bool ServerManager::WaitAndProcessImpl() {
|
||||
if (auto* signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) {
|
||||
R_ASSERT(this->Process(signaled_holder));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::LoopProcessImpl() {
|
||||
while (!m_stop_source.stop_requested()) {
|
||||
R_TRY(this->WaitAndProcessImpl());
|
||||
this->WaitAndProcessImpl();
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerManager::WaitAndProcessImpl() {
|
||||
Kernel::KScopedAutoObject<Kernel::KSynchronizationObject> wait_obj;
|
||||
HandleType wait_type{};
|
||||
|
||||
// Ensure we are the only thread waiting for this server.
|
||||
std::unique_lock sl{m_serve_mutex};
|
||||
|
||||
// If we're done, return before we start waiting.
|
||||
R_SUCCEED_IF(m_stop_source.stop_requested());
|
||||
|
||||
// Wait for a tracked object to become signaled.
|
||||
{
|
||||
s32 num_objs{};
|
||||
std::array<HandleType, MaximumWaitObjects> wait_types{};
|
||||
std::array<Kernel::KSynchronizationObject*, MaximumWaitObjects> wait_objs{};
|
||||
|
||||
const auto AddWaiter{
|
||||
[&](Kernel::KSynchronizationObject* synchronization_object, HandleType type) {
|
||||
// Open a new reference to the object.
|
||||
synchronization_object->Open();
|
||||
|
||||
// Insert into the list.
|
||||
wait_types[num_objs] = type;
|
||||
wait_objs[num_objs++] = synchronization_object;
|
||||
}};
|
||||
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
|
||||
// Add all of our ports.
|
||||
for (const auto& [port, handler] : m_ports) {
|
||||
AddWaiter(port, HandleType::Port);
|
||||
}
|
||||
|
||||
// Add all of our sessions.
|
||||
for (const auto& [session, manager] : m_sessions) {
|
||||
AddWaiter(session, HandleType::Session);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the deferral wakeup event.
|
||||
if (m_deferral_event != nullptr) {
|
||||
AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent);
|
||||
}
|
||||
|
||||
// Add the wakeup event.
|
||||
AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event);
|
||||
|
||||
// Clean up extra references on exit.
|
||||
SCOPE_EXIT({
|
||||
for (s32 i = 0; i < num_objs; i++) {
|
||||
wait_objs[i]->Close();
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for a signal.
|
||||
s32 out_index{-1};
|
||||
R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index,
|
||||
wait_objs.data(), num_objs, -1)) {
|
||||
R_CATCH(Kernel::ResultSessionClosed) {
|
||||
// On session closed, index is updated and we don't want to return an error.
|
||||
}
|
||||
}
|
||||
R_END_TRY_CATCH;
|
||||
ASSERT(out_index >= 0 && out_index < num_objs);
|
||||
|
||||
// Set the output index.
|
||||
wait_obj = wait_objs[out_index];
|
||||
wait_type = wait_types[out_index];
|
||||
}
|
||||
|
||||
// Process what we just received, temporarily removing the object so it is
|
||||
// not processed concurrently by another thread.
|
||||
{
|
||||
switch (wait_type) {
|
||||
case HandleType::Port: {
|
||||
// Port signaled.
|
||||
auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>();
|
||||
SessionRequestHandlerFactory handler_factory;
|
||||
|
||||
// Remove from tracking.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
ASSERT(m_ports.contains(port));
|
||||
m_ports.at(port).swap(handler_factory);
|
||||
m_ports.erase(port);
|
||||
}
|
||||
|
||||
// Allow other threads to serve.
|
||||
sl.unlock();
|
||||
|
||||
// Finish.
|
||||
R_RETURN(this->OnPortEvent(port, std::move(handler_factory)));
|
||||
}
|
||||
case HandleType::Session: {
|
||||
// Session signaled.
|
||||
auto* session = wait_obj->DynamicCast<Kernel::KServerSession*>();
|
||||
std::shared_ptr<SessionRequestManager> manager;
|
||||
|
||||
// Remove from tracking.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
ASSERT(m_sessions.contains(session));
|
||||
m_sessions.at(session).swap(manager);
|
||||
m_sessions.erase(session);
|
||||
}
|
||||
|
||||
// Allow other threads to serve.
|
||||
sl.unlock();
|
||||
|
||||
// Finish.
|
||||
R_RETURN(this->OnSessionEvent(session, std::move(manager)));
|
||||
}
|
||||
case HandleType::DeferEvent: {
|
||||
// Clear event.
|
||||
ASSERT(R_SUCCEEDED(m_deferral_event->Clear()));
|
||||
|
||||
// Drain the list of deferrals while we process.
|
||||
std::list<RequestState> deferrals;
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_deferrals.swap(deferrals);
|
||||
}
|
||||
|
||||
// Allow other threads to serve.
|
||||
sl.unlock();
|
||||
|
||||
// Finish.
|
||||
R_RETURN(this->OnDeferralEvent(std::move(deferrals)));
|
||||
}
|
||||
case HandleType::Event: {
|
||||
// Clear event and finish.
|
||||
R_RETURN(m_event->Clear());
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result ServerManager::OnPortEvent(Kernel::KServerPort* port,
|
||||
SessionRequestHandlerFactory&& handler_factory) {
|
||||
Result ServerManager::OnPortEvent(Port* server) {
|
||||
// Accept a new server session.
|
||||
Kernel::KServerSession* session = port->AcceptSession();
|
||||
ASSERT(session != nullptr);
|
||||
auto* server_port = static_cast<Kernel::KServerPort*>(server->GetNativeHandle());
|
||||
Kernel::KServerSession* server_session = server_port->AcceptSession();
|
||||
ASSERT(server_session != nullptr);
|
||||
|
||||
// Create the session manager and install the handler.
|
||||
auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this);
|
||||
manager->SetSessionHandler(handler_factory());
|
||||
manager->SetSessionHandler(server->CreateHandler());
|
||||
|
||||
// Track the server session.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_ports.emplace(port, std::move(handler_factory));
|
||||
m_sessions.emplace(session, std::move(manager));
|
||||
}
|
||||
// Create and register the new session.
|
||||
this->RegisterSession(server_session, std::move(manager));
|
||||
|
||||
// Signal the wakeup event.
|
||||
m_event->Signal();
|
||||
// Resume tracking the port.
|
||||
this->LinkToDeferredList(server);
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
|
||||
std::shared_ptr<SessionRequestManager>&& manager) {
|
||||
Result rc{ResultSuccess};
|
||||
Result ServerManager::OnSessionEvent(Session* session) {
|
||||
Result res = ResultSuccess;
|
||||
|
||||
// Try to receive a message.
|
||||
std::shared_ptr<HLERequestContext> context;
|
||||
rc = session->ReceiveRequestHLE(&context, manager);
|
||||
auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle());
|
||||
res = server_session->ReceiveRequestHLE(&session->GetContext(), session->GetManager());
|
||||
|
||||
// If the session has been closed, we're done.
|
||||
if (rc == Kernel::ResultSessionClosed) {
|
||||
// Close the session.
|
||||
session->Close();
|
||||
|
||||
// Finish.
|
||||
if (res == Kernel::ResultSessionClosed) {
|
||||
this->DestroySession(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
ASSERT(R_SUCCEEDED(rc));
|
||||
|
||||
RequestState request{
|
||||
.session = session,
|
||||
.context = std::move(context),
|
||||
.manager = std::move(manager),
|
||||
};
|
||||
R_ASSERT(res);
|
||||
|
||||
// Complete the sync request with deferral handling.
|
||||
R_RETURN(this->CompleteSyncRequest(std::move(request)));
|
||||
R_RETURN(this->CompleteSyncRequest(session));
|
||||
}
|
||||
|
||||
Result ServerManager::CompleteSyncRequest(RequestState&& request) {
|
||||
Result rc{ResultSuccess};
|
||||
Result service_rc{ResultSuccess};
|
||||
Result ServerManager::CompleteSyncRequest(Session* session) {
|
||||
Result res = ResultSuccess;
|
||||
Result service_res = ResultSuccess;
|
||||
|
||||
// Mark the request as not deferred.
|
||||
request.context->SetIsDeferred(false);
|
||||
session->GetContext()->SetIsDeferred(false);
|
||||
|
||||
// Complete the request. We have exclusive access to this session.
|
||||
service_rc = request.manager->CompleteSyncRequest(request.session, *request.context);
|
||||
auto* server_session = static_cast<Kernel::KServerSession*>(session->GetNativeHandle());
|
||||
service_res =
|
||||
session->GetManager()->CompleteSyncRequest(server_session, *session->GetContext());
|
||||
|
||||
// If we've been deferred, we're done.
|
||||
if (request.context->GetIsDeferred()) {
|
||||
// Insert into deferral list.
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_deferrals.emplace_back(std::move(request));
|
||||
if (session->GetContext()->GetIsDeferred()) {
|
||||
// Insert into deferred session list.
|
||||
std::scoped_lock ll{m_deferred_list_mutex};
|
||||
m_deferred_sessions.push_back(session);
|
||||
|
||||
// Finish.
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Send the reply.
|
||||
rc = request.session->SendReplyHLE();
|
||||
res = server_session->SendReplyHLE();
|
||||
|
||||
// If the session has been closed, we're done.
|
||||
if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ResultSessionClosed) {
|
||||
// Close the session.
|
||||
request.session->Close();
|
||||
|
||||
// Finish.
|
||||
if (res == Kernel::ResultSessionClosed || service_res == IPC::ResultSessionClosed) {
|
||||
this->DestroySession(session);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
ASSERT(R_SUCCEEDED(rc));
|
||||
ASSERT(R_SUCCEEDED(service_rc));
|
||||
R_ASSERT(res);
|
||||
R_ASSERT(service_res);
|
||||
|
||||
// Reinsert the session.
|
||||
{
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_sessions.emplace(request.session, std::move(request.manager));
|
||||
}
|
||||
// We succeeded, so we can process future messages on this session.
|
||||
this->LinkToDeferredList(session);
|
||||
|
||||
// Signal the wakeup event.
|
||||
m_event->Signal();
|
||||
|
||||
// We succeeded.
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) {
|
||||
ON_RESULT_FAILURE {
|
||||
std::scoped_lock ll{m_list_mutex};
|
||||
m_deferrals.splice(m_deferrals.end(), deferrals);
|
||||
};
|
||||
Result ServerManager::OnDeferralEvent() {
|
||||
// Clear event before grabbing the list.
|
||||
m_deferral_event->Clear();
|
||||
|
||||
while (!deferrals.empty()) {
|
||||
RequestState request = deferrals.front();
|
||||
deferrals.pop_front();
|
||||
// Get and clear list.
|
||||
const auto deferrals = [&] {
|
||||
std::scoped_lock lk{m_deferred_list_mutex};
|
||||
return std::move(m_deferred_sessions);
|
||||
}();
|
||||
|
||||
// Try again to complete the request.
|
||||
R_TRY(this->CompleteSyncRequest(std::move(request)));
|
||||
// Relink deferral event.
|
||||
this->LinkToDeferredList(std::addressof(*m_deferral_holder));
|
||||
|
||||
// For each session, try again to complete the request.
|
||||
for (auto* session : deferrals) {
|
||||
R_ASSERT(this->CompleteSyncRequest(session));
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void ServerManager::DestroySession(Session* session) {
|
||||
// Unlink.
|
||||
{
|
||||
std::scoped_lock lk{m_deferred_list_mutex};
|
||||
m_sessions.erase(m_sessions.iterator_to(*session));
|
||||
}
|
||||
|
||||
// Free the session.
|
||||
delete session;
|
||||
}
|
||||
|
||||
} // namespace Service
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/hle_ipc.h"
|
||||
#include "core/hle/service/mutex.h"
|
||||
#include "core/hle/service/os/multi_wait.h"
|
||||
#include "core/hle/service/os/mutex.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
@@ -24,11 +23,13 @@ namespace Kernel {
|
||||
class KEvent;
|
||||
class KServerPort;
|
||||
class KServerSession;
|
||||
class KSynchronizationObject;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Service {
|
||||
|
||||
class Port;
|
||||
class Session;
|
||||
|
||||
class ServerManager {
|
||||
public:
|
||||
explicit ServerManager(Core::System& system);
|
||||
@@ -52,34 +53,40 @@ public:
|
||||
static void RunServer(std::unique_ptr<ServerManager>&& server);
|
||||
|
||||
private:
|
||||
struct RequestState;
|
||||
|
||||
void LinkToDeferredList(MultiWaitHolder* holder);
|
||||
void LinkDeferred();
|
||||
MultiWaitHolder* WaitSignaled();
|
||||
Result Process(MultiWaitHolder* holder);
|
||||
bool WaitAndProcessImpl();
|
||||
Result LoopProcessImpl();
|
||||
Result WaitAndProcessImpl();
|
||||
Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory);
|
||||
Result OnSessionEvent(Kernel::KServerSession* session,
|
||||
std::shared_ptr<SessionRequestManager>&& manager);
|
||||
Result OnDeferralEvent(std::list<RequestState>&& deferrals);
|
||||
Result CompleteSyncRequest(RequestState&& state);
|
||||
|
||||
Result OnPortEvent(Port* port);
|
||||
Result OnSessionEvent(Session* session);
|
||||
Result OnDeferralEvent();
|
||||
Result CompleteSyncRequest(Session* session);
|
||||
|
||||
private:
|
||||
void DestroySession(Session* session);
|
||||
|
||||
private:
|
||||
Core::System& m_system;
|
||||
Mutex m_serve_mutex;
|
||||
std::mutex m_list_mutex;
|
||||
Mutex m_selection_mutex;
|
||||
|
||||
// Guest state tracking
|
||||
std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{};
|
||||
std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
|
||||
Kernel::KEvent* m_event{};
|
||||
// Events
|
||||
Kernel::KEvent* m_wakeup_event{};
|
||||
Kernel::KEvent* m_deferral_event{};
|
||||
|
||||
// Deferral tracking
|
||||
struct RequestState {
|
||||
Kernel::KServerSession* session;
|
||||
std::shared_ptr<HLERequestContext> context;
|
||||
std::shared_ptr<SessionRequestManager> manager;
|
||||
};
|
||||
std::list<RequestState> m_deferrals{};
|
||||
// Deferred wait list
|
||||
std::mutex m_deferred_list_mutex{};
|
||||
MultiWait m_deferred_list{};
|
||||
|
||||
// Guest state tracking
|
||||
MultiWait m_multi_wait{};
|
||||
Common::IntrusiveListBaseTraits<Port>::ListType m_servers{};
|
||||
Common::IntrusiveListBaseTraits<Session>::ListType m_sessions{};
|
||||
std::list<Session*> m_deferred_sessions{};
|
||||
std::optional<MultiWaitHolder> m_wakeup_holder{};
|
||||
std::optional<MultiWaitHolder> m_deferral_holder{};
|
||||
|
||||
// Host state tracking
|
||||
Common::Event m_stopped{};
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_process_page_table.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
@@ -46,12 +47,23 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
|
||||
|
||||
StandardVmCallbacks::~StandardVmCallbacks() = default;
|
||||
|
||||
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
|
||||
system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size);
|
||||
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
|
||||
// Return zero on invalid address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
std::memset(data, 0, size);
|
||||
return;
|
||||
}
|
||||
|
||||
system.ApplicationMemory().ReadBlock(address, data, size);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
|
||||
system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size);
|
||||
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
|
||||
// Skip invalid memory write address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
system.ApplicationMemory().WriteBlock(address, data, size);
|
||||
}
|
||||
|
||||
u64 StandardVmCallbacks::HidKeysDown() {
|
||||
@@ -81,21 +93,25 @@ void StandardVmCallbacks::CommandLog(std::string_view data) {
|
||||
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
||||
}
|
||||
|
||||
VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
|
||||
bool StandardVmCallbacks::IsAddressInRange(VAddr in) const {
|
||||
if ((in < metadata.main_nso_extents.base ||
|
||||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
|
||||
(in < metadata.heap_extents.base ||
|
||||
in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
|
||||
LOG_ERROR(CheatEngine,
|
||||
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
|
||||
(in < metadata.alias_extents.base ||
|
||||
in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
|
||||
(in < metadata.aslr_extents.base ||
|
||||
in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
|
||||
LOG_DEBUG(CheatEngine,
|
||||
"Cheat attempting to access memory at invalid address={:016X}, if this "
|
||||
"persists, "
|
||||
"the cheat may be incorrect. However, this may be normal early in execution if "
|
||||
"the game has not properly set up yet.",
|
||||
in);
|
||||
return 0; ///< Invalid addresses will hard crash
|
||||
return false; ///< Invalid addresses will hard crash
|
||||
}
|
||||
|
||||
return in;
|
||||
return true;
|
||||
}
|
||||
|
||||
CheatParser::~CheatParser() = default;
|
||||
@@ -211,16 +227,14 @@ void CheatEngine::Initialize() {
|
||||
.base = GetInteger(page_table.GetHeapRegionStart()),
|
||||
.size = page_table.GetHeapRegionSize(),
|
||||
};
|
||||
|
||||
metadata.address_space_extents = {
|
||||
.base = GetInteger(page_table.GetAddressSpaceStart()),
|
||||
.size = page_table.GetAddressSpaceSize(),
|
||||
};
|
||||
|
||||
metadata.alias_extents = {
|
||||
metadata.aslr_extents = {
|
||||
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
||||
.size = page_table.GetAliasCodeRegionSize(),
|
||||
};
|
||||
metadata.alias_extents = {
|
||||
.base = GetInteger(page_table.GetAliasRegionStart()),
|
||||
.size = page_table.GetAliasRegionSize(),
|
||||
};
|
||||
|
||||
is_pending_reload.exchange(true);
|
||||
}
|
||||
|
||||
@@ -27,17 +27,17 @@ public:
|
||||
StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
|
||||
~StandardVmCallbacks() override;
|
||||
|
||||
void MemoryRead(VAddr address, void* data, u64 size) override;
|
||||
void MemoryWrite(VAddr address, const void* data, u64 size) override;
|
||||
void MemoryReadUnsafe(VAddr address, void* data, u64 size) override;
|
||||
void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override;
|
||||
u64 HidKeysDown() override;
|
||||
void DebugLog(u8 id, u64 value) override;
|
||||
void CommandLog(std::string_view data) override;
|
||||
|
||||
private:
|
||||
VAddr SanitizeAddress(VAddr address) const;
|
||||
bool IsAddressInRange(VAddr address) const;
|
||||
|
||||
const CheatProcessMetadata& metadata;
|
||||
System& system;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
// Intermediary class that parses a text file or other disk format for storing cheats into a
|
||||
|
||||
@@ -18,7 +18,7 @@ struct CheatProcessMetadata {
|
||||
MemoryRegionExtents main_nso_extents{};
|
||||
MemoryRegionExtents heap_extents{};
|
||||
MemoryRegionExtents alias_extents{};
|
||||
MemoryRegionExtents address_space_extents{};
|
||||
MemoryRegionExtents aslr_extents{};
|
||||
std::array<u8, 0x20> main_nso_build_id{};
|
||||
};
|
||||
|
||||
|
||||
@@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||
} break;
|
||||
case CheatVmOpcodeType::EndConditionalBlock: {
|
||||
// 20000000
|
||||
// There's actually nothing left to process here!
|
||||
opcode.opcode = EndConditionalOpcode{};
|
||||
opcode.opcode = EndConditionalOpcode{
|
||||
.is_else = ((first_dword >> 24) & 0xf) == 1,
|
||||
};
|
||||
} break;
|
||||
case CheatVmOpcodeType::ControlLoop: {
|
||||
// 300R0000 VVVVVVVV
|
||||
@@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||
.idx = first_dword & 0xF,
|
||||
};
|
||||
} break;
|
||||
case CheatVmOpcodeType::PauseProcess: {
|
||||
/* FF0????? */
|
||||
/* FF0 = opcode 0xFF0 */
|
||||
/* Pauses the current process. */
|
||||
opcode.opcode = PauseProcessOpcode{};
|
||||
} break;
|
||||
case CheatVmOpcodeType::ResumeProcess: {
|
||||
/* FF0????? */
|
||||
/* FF0 = opcode 0xFF0 */
|
||||
/* Pauses the current process. */
|
||||
opcode.opcode = ResumeProcessOpcode{};
|
||||
} break;
|
||||
case CheatVmOpcodeType::DebugLog: {
|
||||
// FFFTIX##
|
||||
// FFFTI0Ma aaaaaaaa
|
||||
@@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void DmntCheatVm::SkipConditionalBlock() {
|
||||
void DmntCheatVm::SkipConditionalBlock(bool is_if) {
|
||||
if (condition_depth > 0) {
|
||||
// We want to continue until we're out of the current block.
|
||||
const std::size_t desired_depth = condition_depth - 1;
|
||||
@@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() {
|
||||
// We also support nesting of conditional blocks, and Gateway does not.
|
||||
if (skip_opcode.begin_conditional_block) {
|
||||
condition_depth++;
|
||||
} else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
|
||||
condition_depth--;
|
||||
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) {
|
||||
if (!end_cond->is_else) {
|
||||
condition_depth--;
|
||||
} else if (is_if && condition_depth - 1 == desired_depth) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
|
||||
return metadata.main_nso_extents.base + rel_address;
|
||||
case MemoryAccessType::Heap:
|
||||
return metadata.heap_extents.base + rel_address;
|
||||
case MemoryAccessType::Alias:
|
||||
return metadata.alias_extents.base + rel_address;
|
||||
case MemoryAccessType::Aslr:
|
||||
return metadata.aslr_extents.base + rel_address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() {
|
||||
registers.fill(0);
|
||||
saved_values.fill(0);
|
||||
loop_tops.fill(0);
|
||||
static_registers.fill(0);
|
||||
instruction_ptr = 0;
|
||||
condition_depth = 0;
|
||||
decode_success = true;
|
||||
@@ -753,7 +773,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width);
|
||||
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, store_static->bit_width);
|
||||
break;
|
||||
}
|
||||
} else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
|
||||
@@ -766,7 +786,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width);
|
||||
callbacks->MemoryReadUnsafe(src_address, &src_value, begin_cond->bit_width);
|
||||
break;
|
||||
}
|
||||
// Check against condition.
|
||||
@@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
}
|
||||
// Skip conditional block if condition not met.
|
||||
if (!cond_met) {
|
||||
SkipConditionalBlock();
|
||||
SkipConditionalBlock(true);
|
||||
}
|
||||
} else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) {
|
||||
// Decrement the condition depth.
|
||||
// We will assume, graciously, that mismatched conditional block ends are a nop.
|
||||
if (condition_depth > 0) {
|
||||
condition_depth--;
|
||||
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
|
||||
if (end_cond->is_else) {
|
||||
/* Skip to the end of the conditional block. */
|
||||
this->SkipConditionalBlock(false);
|
||||
} else {
|
||||
/* Decrement the condition depth. */
|
||||
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
|
||||
if (condition_depth > 0) {
|
||||
condition_depth--;
|
||||
}
|
||||
}
|
||||
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
|
||||
if (ctrl_loop->start_loop) {
|
||||
@@ -832,8 +857,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryRead(src_address, ®isters[ldr_memory->reg_index],
|
||||
ldr_memory->bit_width);
|
||||
callbacks->MemoryReadUnsafe(src_address, ®isters[ldr_memory->reg_index],
|
||||
ldr_memory->bit_width);
|
||||
break;
|
||||
}
|
||||
} else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
|
||||
@@ -849,7 +874,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width);
|
||||
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_static->bit_width);
|
||||
break;
|
||||
}
|
||||
// Increment register if relevant.
|
||||
@@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
// Check for keypress.
|
||||
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
|
||||
// Keys not pressed. Skip conditional block.
|
||||
SkipConditionalBlock();
|
||||
SkipConditionalBlock(true);
|
||||
}
|
||||
} else if (auto perform_math_reg =
|
||||
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
|
||||
@@ -1007,7 +1032,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width);
|
||||
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_register->bit_width);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1086,7 +1111,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width);
|
||||
callbacks->MemoryReadUnsafe(cond_address, &cond_value,
|
||||
begin_reg_cond->bit_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1116,7 +1142,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
|
||||
// Skip conditional block if condition not met.
|
||||
if (!cond_met) {
|
||||
SkipConditionalBlock();
|
||||
SkipConditionalBlock(true);
|
||||
}
|
||||
} else if (auto save_restore_reg =
|
||||
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
|
||||
@@ -1178,6 +1204,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
// Store a register to a static register.
|
||||
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
|
||||
}
|
||||
} else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
|
||||
// TODO: Pause cheat process
|
||||
} else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
|
||||
// TODO: Resume cheat process
|
||||
} else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
|
||||
// Read value from memory.
|
||||
u64 log_value = 0;
|
||||
@@ -1224,7 +1254,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width);
|
||||
callbacks->MemoryReadUnsafe(val_address, &log_value, debug_log->bit_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 {
|
||||
DoubleExtendedWidth = 0xF0,
|
||||
|
||||
// Double-extended width opcodes.
|
||||
PauseProcess = 0xFF0,
|
||||
ResumeProcess = 0xFF1,
|
||||
DebugLog = 0xFFF,
|
||||
};
|
||||
|
||||
enum class MemoryAccessType : u32 {
|
||||
MainNso = 0,
|
||||
Heap = 1,
|
||||
Alias = 2,
|
||||
Aslr = 3,
|
||||
};
|
||||
|
||||
enum class ConditionalComparisonType : u32 {
|
||||
@@ -131,7 +135,9 @@ struct BeginConditionalOpcode {
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct EndConditionalOpcode {};
|
||||
struct EndConditionalOpcode {
|
||||
bool is_else;
|
||||
};
|
||||
|
||||
struct ControlLoopOpcode {
|
||||
bool start_loop{};
|
||||
@@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode {
|
||||
u32 idx{};
|
||||
};
|
||||
|
||||
struct PauseProcessOpcode {};
|
||||
|
||||
struct ResumeProcessOpcode {};
|
||||
|
||||
struct DebugLogOpcode {
|
||||
u32 bit_width{};
|
||||
u32 log_id{};
|
||||
@@ -244,8 +254,8 @@ struct CheatVmOpcode {
|
||||
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
||||
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
||||
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
|
||||
UnrecognizedInstruction>
|
||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
||||
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
|
||||
opcode{};
|
||||
};
|
||||
|
||||
@@ -256,8 +266,8 @@ public:
|
||||
public:
|
||||
virtual ~Callbacks();
|
||||
|
||||
virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
|
||||
virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
|
||||
virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0;
|
||||
virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0;
|
||||
|
||||
virtual u64 HidKeysDown() = 0;
|
||||
|
||||
@@ -296,7 +306,7 @@ private:
|
||||
std::array<std::size_t, NumRegisters> loop_tops{};
|
||||
|
||||
bool DecodeNextOpcode(CheatVmOpcode& out);
|
||||
void SkipConditionalBlock();
|
||||
void SkipConditionalBlock(bool is_if);
|
||||
void ResetState();
|
||||
|
||||
// For implementing the DebugLog opcode.
|
||||
|
||||
@@ -145,9 +145,8 @@ void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_m
|
||||
}
|
||||
|
||||
Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
|
||||
std::vector<u8>& data) const {
|
||||
const auto size = GetDataSize(current_config.trimming_format);
|
||||
data.resize(size);
|
||||
std::span<u8> data) const {
|
||||
const auto size = std::min(GetDataSize(current_config.trimming_format), data.size());
|
||||
system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size);
|
||||
return processor_state;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "common/typed_address.h"
|
||||
#include "hid_core/irsensor/irs_types.h"
|
||||
#include "hid_core/irsensor/processor_base.h"
|
||||
@@ -39,7 +41,7 @@ public:
|
||||
// Transfer memory where the image data will be stored
|
||||
void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
|
||||
|
||||
Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const;
|
||||
Core::IrSensor::ImageTransferProcessorState GetState(std::span<u8> data) const;
|
||||
|
||||
private:
|
||||
// This is nn::irsensor::ImageTransferProcessorConfig
|
||||
|
||||
@@ -52,9 +52,42 @@ ResourceManager::ResourceManager(Core::System& system_,
|
||||
std::shared_ptr<HidFirmwareSettings> settings)
|
||||
: firmware_settings{settings}, system{system_}, service_context{system_, "hid"} {
|
||||
applet_resource = std::make_shared<AppletResource>(system);
|
||||
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent("HID::UpdatePadCallback",
|
||||
[this](s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
UpdateNpad(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
UpdateControllers(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
UpdateMouseKeyboard(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
UpdateMotion(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
ResourceManager::~ResourceManager() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(touch_update_event);
|
||||
input_event->Finalize();
|
||||
};
|
||||
@@ -201,6 +234,7 @@ void ResourceManager::InitializeHidCommonSampler() {
|
||||
|
||||
debug_pad->SetAppletResource(applet_resource, &shared_mutex);
|
||||
digitizer->SetAppletResource(applet_resource, &shared_mutex);
|
||||
unique_pad->SetAppletResource(applet_resource, &shared_mutex);
|
||||
keyboard->SetAppletResource(applet_resource, &shared_mutex);
|
||||
|
||||
const auto settings =
|
||||
@@ -214,6 +248,14 @@ void ResourceManager::InitializeHidCommonSampler() {
|
||||
home_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
sleep_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
capture_button->SetAppletResource(applet_resource, &shared_mutex);
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
||||
default_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
||||
mouse_keyboard_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
||||
motion_update_event);
|
||||
}
|
||||
|
||||
void ResourceManager::InitializeTouchScreenSampler() {
|
||||
@@ -465,55 +507,9 @@ IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<Resource
|
||||
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
// Register update callbacks
|
||||
npad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateNpad(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
default_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateDefaultCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateControllers(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
mouse_keyboard_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMouseKeyboardCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMouseKeyboard(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdateMotionCallback",
|
||||
[this, resource](
|
||||
s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
const auto guard = LockService();
|
||||
resource->UpdateMotion(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
|
||||
default_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
|
||||
mouse_keyboard_update_event);
|
||||
system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
|
||||
motion_update_event);
|
||||
}
|
||||
|
||||
IAppletResource::~IAppletResource() {
|
||||
system.CoreTiming().UnscheduleEvent(npad_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(default_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event);
|
||||
system.CoreTiming().UnscheduleEvent(motion_update_event);
|
||||
resource_manager->FreeAppletResourceId(aruid);
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,10 @@ private:
|
||||
std::shared_ptr<SixAxis> six_axis{nullptr};
|
||||
std::shared_ptr<SleepButton> sleep_button{nullptr};
|
||||
std::shared_ptr<UniquePad> unique_pad{nullptr};
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event;
|
||||
|
||||
// TODO: Create these resources
|
||||
// std::shared_ptr<AudioControl> audio_control{nullptr};
|
||||
@@ -179,11 +183,6 @@ public:
|
||||
private:
|
||||
void GetSharedMemoryHandle(HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> npad_update_event{nullptr};
|
||||
std::shared_ptr<Core::Timing::EventType> default_update_event{nullptr};
|
||||
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event{nullptr};
|
||||
std::shared_ptr<Core::Timing::EventType> motion_update_event{nullptr};
|
||||
|
||||
u64 aruid{};
|
||||
std::shared_ptr<ResourceManager> resource_manager;
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ Result NpadAbstractSixAxisHandler::UpdateSixAxisState() {
|
||||
Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
|
||||
for (std::size_t i = 0; i < AruidIndexMax; i++) {
|
||||
auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
|
||||
if (data->flag.is_assigned) {
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
|
||||
|
||||
@@ -17,10 +17,6 @@ void Digitizer::OnInit() {}
|
||||
void Digitizer::OnRelease() {}
|
||||
|
||||
void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
@@ -20,8 +20,5 @@ public:
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -102,6 +102,8 @@ Result NPad::Activate(u64 aruid) {
|
||||
for (std::size_t i = 0; i < 19; ++i) {
|
||||
WriteEmptyEntry(npad);
|
||||
}
|
||||
|
||||
controller.is_active = true;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
@@ -129,7 +131,7 @@ void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t c
|
||||
|
||||
auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
|
||||
if (!data->flag.is_assigned) {
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -461,9 +463,16 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock lock{*applet_resource_holder.shared_mutex};
|
||||
for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
|
||||
const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
const auto aruid = data->aruid;
|
||||
|
||||
if (!data->flag.is_assigned) {
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool is_set{};
|
||||
const auto aruid = data->aruid;
|
||||
npad_resource.IsSupportedNpadStyleSet(is_set, aruid);
|
||||
// Wait until style is defined
|
||||
if (!is_set) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -484,6 +493,10 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!controller.is_active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RequestPadStateUpdate(aruid, controller.device->GetNpadIdType());
|
||||
auto& pad_state = controller.npad_pad_state;
|
||||
auto& libnx_state = controller.npad_libnx_state;
|
||||
@@ -592,7 +605,9 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw;
|
||||
libnx_state.l_stick = pad_state.l_stick;
|
||||
libnx_state.r_stick = pad_state.r_stick;
|
||||
npad->system_ext_lifo.WriteNextEntry(pad_state);
|
||||
libnx_state.sampling_number =
|
||||
npad->system_ext_lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
npad->system_ext_lifo.WriteNextEntry(libnx_state);
|
||||
|
||||
press_state |= static_cast<u64>(pad_state.npad_buttons.raw);
|
||||
}
|
||||
@@ -1060,6 +1075,7 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
|
||||
// TODO: Remove this once abstract pad is emulated properly
|
||||
const auto aruid_index = npad_resource.GetIndexFromAruid(aruid);
|
||||
for (auto& controller : controller_data[aruid_index]) {
|
||||
controller.is_active = false;
|
||||
controller.is_connected = false;
|
||||
controller.shared_memory = nullptr;
|
||||
}
|
||||
|
||||
@@ -164,6 +164,7 @@ private:
|
||||
NpadInternalState* shared_memory = nullptr;
|
||||
Core::HID::EmulatedController* device = nullptr;
|
||||
|
||||
bool is_active{};
|
||||
bool is_connected{};
|
||||
|
||||
// Dual joycons can have only one side connected
|
||||
|
||||
@@ -28,142 +28,148 @@ void SixAxis::OnRelease() {}
|
||||
|
||||
void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
std::scoped_lock shared_lock{*shared_mutex};
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
return;
|
||||
}
|
||||
for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) {
|
||||
const auto* data = applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
|
||||
auto& controller = controller_data[i];
|
||||
const auto& controller_type = controller.device->GetNpadStyleIndex();
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None ||
|
||||
!controller.device->IsConnected()) {
|
||||
if (data == nullptr || !data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& motion_state = controller.device->GetMotions();
|
||||
auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
|
||||
auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
|
||||
auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
|
||||
auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
|
||||
auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
|
||||
auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
|
||||
|
||||
auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
|
||||
auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
|
||||
auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
|
||||
auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
|
||||
auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
|
||||
auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
|
||||
|
||||
// Clear previous state
|
||||
sixaxis_fullkey_state = {};
|
||||
sixaxis_handheld_state = {};
|
||||
sixaxis_dual_left_state = {};
|
||||
sixaxis_dual_right_state = {};
|
||||
sixaxis_left_lifo_state = {};
|
||||
sixaxis_right_lifo_state = {};
|
||||
|
||||
if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
|
||||
controller.sixaxis_at_rest = true;
|
||||
for (std::size_t e = 0; e < motion_state.size(); ++e) {
|
||||
controller.sixaxis_at_rest =
|
||||
controller.sixaxis_at_rest && motion_state[e].is_at_rest;
|
||||
}
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
|
||||
const Core::HID::ControllerMotion& hid_state) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
static constexpr Core::HID::SixAxisSensorState default_motion_state = {
|
||||
.delta_time = std::chrono::nanoseconds(5ms).count(),
|
||||
.accel = {0, 0, -1.0f},
|
||||
.orientation =
|
||||
{
|
||||
Common::Vec3f{1.0f, 0, 0},
|
||||
Common::Vec3f{0, 1.0f, 0},
|
||||
Common::Vec3f{0, 0, 1.0f},
|
||||
},
|
||||
.attribute = {1},
|
||||
for (std::size_t i = 0; i < controller_data.size(); ++i) {
|
||||
NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i];
|
||||
auto& controller = controller_data[i];
|
||||
const auto& controller_type = controller.device->GetNpadStyleIndex();
|
||||
|
||||
if (!data->flag.enable_six_axis_sensor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (controller_type == Core::HID::NpadStyleIndex::None ||
|
||||
!controller.device->IsConnected()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& motion_state = controller.device->GetMotions();
|
||||
auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
|
||||
auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
|
||||
auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
|
||||
auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
|
||||
auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
|
||||
auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
|
||||
|
||||
auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo;
|
||||
auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo;
|
||||
auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo;
|
||||
auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo;
|
||||
auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo;
|
||||
auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo;
|
||||
|
||||
// Clear previous state
|
||||
sixaxis_fullkey_state = {};
|
||||
sixaxis_handheld_state = {};
|
||||
sixaxis_dual_left_state = {};
|
||||
sixaxis_dual_right_state = {};
|
||||
sixaxis_left_lifo_state = {};
|
||||
sixaxis_right_lifo_state = {};
|
||||
|
||||
if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
|
||||
controller.sixaxis_at_rest = true;
|
||||
for (std::size_t e = 0; e < motion_state.size(); ++e) {
|
||||
controller.sixaxis_at_rest =
|
||||
controller.sixaxis_at_rest && motion_state[e].is_at_rest;
|
||||
}
|
||||
}
|
||||
|
||||
const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
|
||||
const Core::HID::ControllerMotion& hid_state) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
static constexpr Core::HID::SixAxisSensorState default_motion_state = {
|
||||
.delta_time = std::chrono::nanoseconds(5ms).count(),
|
||||
.accel = {0, 0, -1.0f},
|
||||
.orientation =
|
||||
{
|
||||
Common::Vec3f{1.0f, 0, 0},
|
||||
Common::Vec3f{0, 1.0f, 0},
|
||||
Common::Vec3f{0, 0, 1.0f},
|
||||
},
|
||||
.attribute = {1},
|
||||
};
|
||||
if (!controller.sixaxis_sensor_enabled) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
}
|
||||
if (!Settings::values.motion_enabled.GetValue()) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
}
|
||||
state.attribute.is_connected.Assign(1);
|
||||
state.delta_time = std::chrono::nanoseconds(5ms).count();
|
||||
state.accel = hid_state.accel;
|
||||
state.gyro = hid_state.gyro;
|
||||
state.rotation = hid_state.rotation;
|
||||
state.orientation = hid_state.orientation;
|
||||
};
|
||||
if (!controller.sixaxis_sensor_enabled) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Fullkey:
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
set_motion_state(sixaxis_handheld_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
set_motion_state(sixaxis_dual_left_state, motion_state[0]);
|
||||
set_motion_state(sixaxis_dual_right_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
using namespace std::literals::chrono_literals;
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!Settings::values.motion_enabled.GetValue()) {
|
||||
state = default_motion_state;
|
||||
return;
|
||||
|
||||
sixaxis_fullkey_state.sampling_number =
|
||||
sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_handheld_state.sampling_number =
|
||||
sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_left_state.sampling_number =
|
||||
sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_right_state.sampling_number =
|
||||
sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_left_lifo_state.sampling_number =
|
||||
sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_right_lifo_state.sampling_number =
|
||||
sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
|
||||
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
|
||||
// This buffer only is updated on handheld on HW
|
||||
sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
|
||||
} else {
|
||||
// Handheld doesn't update this buffer on HW
|
||||
sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
|
||||
}
|
||||
state.attribute.is_connected.Assign(1);
|
||||
state.delta_time = std::chrono::nanoseconds(5ms).count();
|
||||
state.accel = hid_state.accel;
|
||||
state.gyro = hid_state.gyro;
|
||||
state.rotation = hid_state.rotation;
|
||||
state.orientation = hid_state.orientation;
|
||||
};
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::None:
|
||||
ASSERT(false);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Fullkey:
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
set_motion_state(sixaxis_handheld_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
set_motion_state(sixaxis_dual_left_state, motion_state[0]);
|
||||
set_motion_state(sixaxis_dual_right_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::Pokeball:
|
||||
using namespace std::literals::chrono_literals;
|
||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||
sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
|
||||
sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
|
||||
sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
|
||||
sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
|
||||
}
|
||||
|
||||
sixaxis_fullkey_state.sampling_number =
|
||||
sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_handheld_state.sampling_number =
|
||||
sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_left_state.sampling_number =
|
||||
sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_dual_right_state.sampling_number =
|
||||
sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_left_lifo_state.sampling_number =
|
||||
sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
sixaxis_right_lifo_state.sampling_number =
|
||||
sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
|
||||
|
||||
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
|
||||
// This buffer only is updated on handheld on HW
|
||||
sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
|
||||
} else {
|
||||
// Handheld doesn't update this buffer on HW
|
||||
sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
|
||||
}
|
||||
|
||||
sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
|
||||
sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
|
||||
sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
|
||||
sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Result TouchResource::ActivateTouch(u64 aruid) {
|
||||
auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
TouchAruidData& touch_data = aruid_data[aruid_index];
|
||||
|
||||
if (!applet_data->flag.is_assigned) {
|
||||
if (applet_data == nullptr || !applet_data->flag.is_assigned) {
|
||||
touch_data = {};
|
||||
continue;
|
||||
}
|
||||
@@ -124,7 +124,7 @@ Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) {
|
||||
auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
TouchAruidData& touch_data = aruid_data[aruid_index];
|
||||
|
||||
if (!applet_data->flag.is_assigned) {
|
||||
if (applet_data == nullptr || !applet_data->flag.is_assigned) {
|
||||
touch_data = {};
|
||||
continue;
|
||||
}
|
||||
@@ -324,7 +324,7 @@ Result TouchResource::SetTouchScreenConfiguration(
|
||||
const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
TouchAruidData& data = aruid_data[aruid_index];
|
||||
|
||||
if (!applet_data->flag.is_assigned) {
|
||||
if (applet_data == nullptr || !applet_data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
if (aruid != data.aruid) {
|
||||
@@ -344,7 +344,7 @@ Result TouchResource::GetTouchScreenConfiguration(
|
||||
const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index);
|
||||
const TouchAruidData& data = aruid_data[aruid_index];
|
||||
|
||||
if (!applet_data->flag.is_assigned) {
|
||||
if (applet_data == nullptr || !applet_data->flag.is_assigned) {
|
||||
continue;
|
||||
}
|
||||
if (aruid != data.aruid) {
|
||||
|
||||
@@ -17,10 +17,6 @@ void UniquePad::OnInit() {}
|
||||
void UniquePad::OnRelease() {}
|
||||
|
||||
void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
||||
if (!smart_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 aruid = applet_resource->GetActiveAruid();
|
||||
auto* data = applet_resource->GetAruidData(aruid);
|
||||
|
||||
|
||||
@@ -20,8 +20,5 @@ public:
|
||||
|
||||
// When the controller is requesting an update for the shared memory
|
||||
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
|
||||
|
||||
private:
|
||||
bool smart_update{};
|
||||
};
|
||||
} // namespace Service::HID
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Host1x {
|
||||
|
||||
Host1x::Host1x(Core::System& system_)
|
||||
: system{system_}, syncpoint_manager{},
|
||||
memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 12},
|
||||
memory_manager(system.DeviceMemory()), gmmu_manager{system, memory_manager, 32, 0, 12},
|
||||
allocator{std::make_unique<Common::FlatAllocator<u32, 0, 32>>(1 << 12)} {}
|
||||
|
||||
Host1x::~Host1x() = default;
|
||||
|
||||
@@ -22,11 +22,12 @@ using Tegra::Memory::GuestMemoryFlags;
|
||||
std::atomic<size_t> MemoryManager::unique_identifier_generator{};
|
||||
|
||||
MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
|
||||
u64 address_space_bits_, u64 big_page_bits_, u64 page_bits_)
|
||||
u64 address_space_bits_, GPUVAddr split_address_, u64 big_page_bits_,
|
||||
u64 page_bits_)
|
||||
: system{system_}, memory{memory_}, address_space_bits{address_space_bits_},
|
||||
page_bits{page_bits_}, big_page_bits{big_page_bits_}, entries{}, big_entries{},
|
||||
page_table{address_space_bits, address_space_bits + page_bits - 38,
|
||||
page_bits != big_page_bits ? page_bits : 0},
|
||||
split_address{split_address_}, page_bits{page_bits_}, big_page_bits{big_page_bits_},
|
||||
entries{}, big_entries{}, page_table{address_space_bits, address_space_bits + page_bits - 38,
|
||||
page_bits != big_page_bits ? page_bits : 0},
|
||||
kind_map{PTEKind::INVALID}, unique_identifier{unique_identifier_generator.fetch_add(
|
||||
1, std::memory_order_acq_rel)},
|
||||
accumulator{std::make_unique<VideoCommon::InvalidationAccumulator>()} {
|
||||
@@ -48,10 +49,10 @@ MemoryManager::MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager&
|
||||
entries.resize(page_table_size / 32, 0);
|
||||
}
|
||||
|
||||
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_, u64 big_page_bits_,
|
||||
u64 page_bits_)
|
||||
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, big_page_bits_,
|
||||
page_bits_) {}
|
||||
MemoryManager::MemoryManager(Core::System& system_, u64 address_space_bits_,
|
||||
GPUVAddr split_address_, u64 big_page_bits_, u64 page_bits_)
|
||||
: MemoryManager(system_, system_.Host1x().MemoryManager(), address_space_bits_, split_address_,
|
||||
big_page_bits_, page_bits_) {}
|
||||
|
||||
MemoryManager::~MemoryManager() = default;
|
||||
|
||||
|
||||
@@ -36,10 +36,11 @@ namespace Tegra {
|
||||
class MemoryManager final {
|
||||
public:
|
||||
explicit MemoryManager(Core::System& system_, u64 address_space_bits_ = 40,
|
||||
u64 big_page_bits_ = 16, u64 page_bits_ = 12);
|
||||
explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
|
||||
u64 address_space_bits_ = 40, u64 big_page_bits_ = 16,
|
||||
GPUVAddr split_address = 1ULL << 34, u64 big_page_bits_ = 16,
|
||||
u64 page_bits_ = 12);
|
||||
explicit MemoryManager(Core::System& system_, MaxwellDeviceMemoryManager& memory_,
|
||||
u64 address_space_bits_ = 40, GPUVAddr split_address = 1ULL << 34,
|
||||
u64 big_page_bits_ = 16, u64 page_bits_ = 12);
|
||||
~MemoryManager();
|
||||
|
||||
size_t GetID() const {
|
||||
@@ -192,6 +193,7 @@ private:
|
||||
MaxwellDeviceMemoryManager& memory;
|
||||
|
||||
const u64 address_space_bits;
|
||||
GPUVAddr split_address;
|
||||
const u64 page_bits;
|
||||
u64 address_space_size;
|
||||
u64 page_size;
|
||||
|
||||
@@ -73,8 +73,11 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
|
||||
ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("Adv. Graphics"));
|
||||
ui->tabWidget->addTab(audio_tab.get(), tr("Audio"));
|
||||
ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles"));
|
||||
|
||||
// Only show Linux tab on Unix
|
||||
linux_tab->setVisible(false);
|
||||
#ifdef __unix__
|
||||
linux_tab->setVisible(true);
|
||||
ui->tabWidget->addTab(linux_tab.get(), tr("Linux"));
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1353,6 +1353,13 @@ void GMainWindow::InitializeHotkeys() {
|
||||
LinkActionShortcut(ui->action_TAS_Start, QStringLiteral("TAS Start/Stop"), true);
|
||||
LinkActionShortcut(ui->action_TAS_Record, QStringLiteral("TAS Record"), true);
|
||||
LinkActionShortcut(ui->action_TAS_Reset, QStringLiteral("TAS Reset"), true);
|
||||
LinkActionShortcut(ui->action_View_Lobby,
|
||||
QStringLiteral("Multiplayer Browse Public Game Lobby"));
|
||||
LinkActionShortcut(ui->action_Start_Room, QStringLiteral("Multiplayer Create Room"));
|
||||
LinkActionShortcut(ui->action_Connect_To_Room,
|
||||
QStringLiteral("Multiplayer Direct Connect to Room"));
|
||||
LinkActionShortcut(ui->action_Show_Room, QStringLiteral("Multiplayer Show Current Room"));
|
||||
LinkActionShortcut(ui->action_Leave_Room, QStringLiteral("Multiplayer Leave Room"));
|
||||
|
||||
static const QString main_window = QStringLiteral("Main Window");
|
||||
const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
|
||||
|
||||
@@ -77,16 +77,23 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
|
||||
|
||||
// UI Buttons
|
||||
connect(ui->refresh_list, &QPushButton::clicked, this, &Lobby::RefreshLobby);
|
||||
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
|
||||
connect(ui->games_owned, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterOwned);
|
||||
connect(ui->hide_empty, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterEmpty);
|
||||
connect(ui->hide_full, &QCheckBox::toggled, proxy, &LobbyFilterProxyModel::SetFilterFull);
|
||||
connect(ui->search, &QLineEdit::textChanged, proxy, &LobbyFilterProxyModel::SetFilterSearch);
|
||||
connect(ui->room_list, &QTreeView::doubleClicked, this, &Lobby::OnJoinRoom);
|
||||
connect(ui->room_list, &QTreeView::clicked, this, &Lobby::OnExpandRoom);
|
||||
|
||||
// Actions
|
||||
connect(&room_list_watcher, &QFutureWatcher<AnnounceMultiplayerRoom::RoomList>::finished, this,
|
||||
&Lobby::OnRefreshLobby);
|
||||
|
||||
// Load persistent filters after events are connected to make sure they apply
|
||||
ui->search->setText(
|
||||
QString::fromStdString(UISettings::values.multiplayer_filter_text.GetValue()));
|
||||
ui->games_owned->setChecked(UISettings::values.multiplayer_filter_games_owned.GetValue());
|
||||
ui->hide_empty->setChecked(UISettings::values.multiplayer_filter_hide_empty.GetValue());
|
||||
ui->hide_full->setChecked(UISettings::values.multiplayer_filter_hide_full.GetValue());
|
||||
}
|
||||
|
||||
Lobby::~Lobby() = default;
|
||||
@@ -204,6 +211,10 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
||||
|
||||
// Save settings
|
||||
UISettings::values.multiplayer_nickname = ui->nickname->text().toStdString();
|
||||
UISettings::values.multiplayer_filter_text = ui->search->text().toStdString();
|
||||
UISettings::values.multiplayer_filter_games_owned = ui->games_owned->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_empty = ui->hide_empty->isChecked();
|
||||
UISettings::values.multiplayer_filter_hide_full = ui->hide_full->isChecked();
|
||||
UISettings::values.multiplayer_ip =
|
||||
proxy->data(connection_index, LobbyItemHost::HostIPRole).value<QString>().toStdString();
|
||||
UISettings::values.multiplayer_port =
|
||||
|
||||
@@ -193,12 +193,29 @@ public:
|
||||
}
|
||||
|
||||
QVariant data(int role) const override {
|
||||
if (role != Qt::DisplayRole) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
auto members = data(MemberListRole).toList();
|
||||
return QStringLiteral("%1 / %2 ")
|
||||
.arg(QString::number(members.size()), data(MaxPlayerRole).toString());
|
||||
}
|
||||
case Qt::ForegroundRole: {
|
||||
auto members = data(MemberListRole).toList();
|
||||
auto max_players = data(MaxPlayerRole).toInt();
|
||||
if (members.size() >= max_players) {
|
||||
return QBrush(QColor(255, 48, 32));
|
||||
} else if (members.size() == (max_players - 1)) {
|
||||
return QBrush(QColor(255, 140, 32));
|
||||
} else if (members.size() == 0) {
|
||||
return QBrush(QColor(128, 128, 128));
|
||||
}
|
||||
// FIXME: How to return a value that tells Qt not to modify the
|
||||
// text color from the default (as if Qt::ForegroundRole wasn't overridden)?
|
||||
return QBrush(nullptr);
|
||||
}
|
||||
default:
|
||||
return LobbyItem::data(role);
|
||||
}
|
||||
auto members = data(MemberListRole).toList();
|
||||
return QStringLiteral("%1 / %2 ")
|
||||
.arg(QString::number(members.size()), data(MaxPlayerRole).toString());
|
||||
}
|
||||
|
||||
bool operator<(const QStandardItem& other) const override {
|
||||
|
||||
+13
-1
@@ -169,6 +169,13 @@ struct Values {
|
||||
|
||||
// multiplayer settings
|
||||
Setting<std::string> multiplayer_nickname{linkage, {}, "nickname", Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_filter_text{linkage, {}, "filter_text", Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_games_owned{linkage, false, "filter_games_owned",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_empty{linkage, false, "filter_games_hide_empty",
|
||||
Category::Multiplayer};
|
||||
Setting<bool> multiplayer_filter_hide_full{linkage, false, "filter_games_hide_full",
|
||||
Category::Multiplayer};
|
||||
Setting<std::string> multiplayer_ip{linkage, {}, "ip", Category::Multiplayer};
|
||||
Setting<u16, true> multiplayer_port{linkage, 24872, 0,
|
||||
UINT16_MAX, "port", Category::Multiplayer};
|
||||
@@ -222,7 +229,7 @@ void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
|
||||
// This must be in alphabetical order according to action name as it must have the same order as
|
||||
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||
// clang-format off
|
||||
const std::array<Shortcut, 23> default_hotkeys{{
|
||||
const std::array<Shortcut, 28> default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
|
||||
@@ -236,6 +243,11 @@ const std::array<Shortcut, 23> default_hotkeys{{
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Browse Public Game Lobby")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+B"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Create Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+N"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Direct Connect to Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+C"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Leave Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+L"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Multiplayer Show Current Room")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+R"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}},
|
||||
{QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}},
|
||||
|
||||
Reference in New Issue
Block a user