diff options
| author | 2021-12-18 13:57:14 +0800 | |
|---|---|---|
| committer | 2021-12-18 13:57:14 +0800 | |
| commit | e49184e6069a9d791d2df3c1958f5c4b1187e124 (patch) | |
| tree | b776caf722e0be0e680f67b0ad0842628162ef1c /src/core/hle | |
| parent | Implement convert legacy to generic (diff) | |
| parent | Merge pull request #7570 from ameerj/favorites-expanded (diff) | |
| download | yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.gz yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.xz yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.zip | |
Merge branch 'yuzu-emu:master' into convert_legacy
Diffstat (limited to 'src/core/hle')
84 files changed, 3898 insertions, 2881 deletions
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 8ff0f695d..36fc0944a 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/hardware_properties.h" | 10 | #include "core/hardware_properties.h" |
| 11 | #include "core/hle/kernel/init/init_slab_setup.h" | 11 | #include "core/hle/kernel/init/init_slab_setup.h" |
| 12 | #include "core/hle/kernel/k_code_memory.h" | ||
| 12 | #include "core/hle/kernel/k_event.h" | 13 | #include "core/hle/kernel/k_event.h" |
| 13 | #include "core/hle/kernel/k_memory_layout.h" | 14 | #include "core/hle/kernel/k_memory_layout.h" |
| 14 | #include "core/hle/kernel/k_memory_manager.h" | 15 | #include "core/hle/kernel/k_memory_manager.h" |
| @@ -32,6 +33,7 @@ namespace Kernel::Init { | |||
| 32 | HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ | 33 | HANDLER(KPort, (SLAB_COUNT(KPort)), ##__VA_ARGS__) \ |
| 33 | HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ | 34 | HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ |
| 34 | HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ | 35 | HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ |
| 36 | HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \ | ||
| 35 | HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ | 37 | HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ |
| 36 | HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) | 38 | HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) |
| 37 | 39 | ||
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 1b429bc1e..783c69858 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/hle/kernel/k_scheduler.h" | 8 | #include "core/hle/kernel/k_scheduler.h" |
| 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 9 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 10 | #include "core/hle/kernel/k_thread.h" | 10 | #include "core/hle/kernel/k_thread.h" |
| 11 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/svc_results.h" | 13 | #include "core/hle/kernel/svc_results.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | 14 | #include "core/hle/kernel/time_manager.h" |
| @@ -28,7 +29,7 @@ bool ReadFromUser(Core::System& system, s32* out, VAddr address) { | |||
| 28 | 29 | ||
| 29 | bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) { | 30 | bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) { |
| 30 | auto& monitor = system.Monitor(); | 31 | auto& monitor = system.Monitor(); |
| 31 | const auto current_core = system.CurrentCoreIndex(); | 32 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); |
| 32 | 33 | ||
| 33 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 34 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. |
| 34 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 35 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| @@ -58,7 +59,7 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu | |||
| 58 | 59 | ||
| 59 | bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) { | 60 | bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) { |
| 60 | auto& monitor = system.Monitor(); | 61 | auto& monitor = system.Monitor(); |
| 61 | const auto current_core = system.CurrentCoreIndex(); | 62 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); |
| 62 | 63 | ||
| 63 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 64 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. |
| 64 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 65 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| @@ -85,6 +86,27 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 | |||
| 85 | return true; | 86 | return true; |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 89 | class ThreadQueueImplForKAddressArbiter final : public KThreadQueue { | ||
| 90 | public: | ||
| 91 | explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t) | ||
| 92 | : KThreadQueue(kernel_), m_tree(t) {} | ||
| 93 | |||
| 94 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 95 | bool cancel_timer_task) override { | ||
| 96 | // If the thread is waiting on an address arbiter, remove it from the tree. | ||
| 97 | if (waiting_thread->IsWaitingForAddressArbiter()) { | ||
| 98 | m_tree->erase(m_tree->iterator_to(*waiting_thread)); | ||
| 99 | waiting_thread->ClearAddressArbiter(); | ||
| 100 | } | ||
| 101 | |||
| 102 | // Invoke the base cancel wait handler. | ||
| 103 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 104 | } | ||
| 105 | |||
| 106 | private: | ||
| 107 | KAddressArbiter::ThreadTree* m_tree; | ||
| 108 | }; | ||
| 109 | |||
| 88 | } // namespace | 110 | } // namespace |
| 89 | 111 | ||
| 90 | ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { | 112 | ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { |
| @@ -96,14 +118,14 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) { | |||
| 96 | auto it = thread_tree.nfind_light({addr, -1}); | 118 | auto it = thread_tree.nfind_light({addr, -1}); |
| 97 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 119 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 98 | (it->GetAddressArbiterKey() == addr)) { | 120 | (it->GetAddressArbiterKey() == addr)) { |
| 121 | // End the thread's wait. | ||
| 99 | KThread* target_thread = std::addressof(*it); | 122 | KThread* target_thread = std::addressof(*it); |
| 100 | target_thread->SetSyncedObject(nullptr, ResultSuccess); | 123 | target_thread->EndWait(ResultSuccess); |
| 101 | 124 | ||
| 102 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 125 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| 103 | target_thread->Wakeup(); | 126 | target_thread->ClearAddressArbiter(); |
| 104 | 127 | ||
| 105 | it = thread_tree.erase(it); | 128 | it = thread_tree.erase(it); |
| 106 | target_thread->ClearAddressArbiter(); | ||
| 107 | ++num_waiters; | 129 | ++num_waiters; |
| 108 | } | 130 | } |
| 109 | } | 131 | } |
| @@ -129,14 +151,14 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 | |||
| 129 | auto it = thread_tree.nfind_light({addr, -1}); | 151 | auto it = thread_tree.nfind_light({addr, -1}); |
| 130 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 152 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 131 | (it->GetAddressArbiterKey() == addr)) { | 153 | (it->GetAddressArbiterKey() == addr)) { |
| 154 | // End the thread's wait. | ||
| 132 | KThread* target_thread = std::addressof(*it); | 155 | KThread* target_thread = std::addressof(*it); |
| 133 | target_thread->SetSyncedObject(nullptr, ResultSuccess); | 156 | target_thread->EndWait(ResultSuccess); |
| 134 | 157 | ||
| 135 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 158 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| 136 | target_thread->Wakeup(); | 159 | target_thread->ClearAddressArbiter(); |
| 137 | 160 | ||
| 138 | it = thread_tree.erase(it); | 161 | it = thread_tree.erase(it); |
| 139 | target_thread->ClearAddressArbiter(); | ||
| 140 | ++num_waiters; | 162 | ++num_waiters; |
| 141 | } | 163 | } |
| 142 | } | 164 | } |
| @@ -197,14 +219,14 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 197 | 219 | ||
| 198 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && | 220 | while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) && |
| 199 | (it->GetAddressArbiterKey() == addr)) { | 221 | (it->GetAddressArbiterKey() == addr)) { |
| 222 | // End the thread's wait. | ||
| 200 | KThread* target_thread = std::addressof(*it); | 223 | KThread* target_thread = std::addressof(*it); |
| 201 | target_thread->SetSyncedObject(nullptr, ResultSuccess); | 224 | target_thread->EndWait(ResultSuccess); |
| 202 | 225 | ||
| 203 | ASSERT(target_thread->IsWaitingForAddressArbiter()); | 226 | ASSERT(target_thread->IsWaitingForAddressArbiter()); |
| 204 | target_thread->Wakeup(); | 227 | target_thread->ClearAddressArbiter(); |
| 205 | 228 | ||
| 206 | it = thread_tree.erase(it); | 229 | it = thread_tree.erase(it); |
| 207 | target_thread->ClearAddressArbiter(); | ||
| 208 | ++num_waiters; | 230 | ++num_waiters; |
| 209 | } | 231 | } |
| 210 | } | 232 | } |
| @@ -214,6 +236,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 | |||
| 214 | ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { | 236 | ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { |
| 215 | // Prepare to wait. | 237 | // Prepare to wait. |
| 216 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 238 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 239 | ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); | ||
| 217 | 240 | ||
| 218 | { | 241 | { |
| 219 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; | 242 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; |
| @@ -224,9 +247,6 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 224 | return ResultTerminationRequested; | 247 | return ResultTerminationRequested; |
| 225 | } | 248 | } |
| 226 | 249 | ||
| 227 | // Set the synced object. | ||
| 228 | cur_thread->SetSyncedObject(nullptr, ResultTimedOut); | ||
| 229 | |||
| 230 | // Read the value from userspace. | 250 | // Read the value from userspace. |
| 231 | s32 user_value{}; | 251 | s32 user_value{}; |
| 232 | bool succeeded{}; | 252 | bool succeeded{}; |
| @@ -256,31 +276,20 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 256 | // Set the arbiter. | 276 | // Set the arbiter. |
| 257 | cur_thread->SetAddressArbiter(&thread_tree, addr); | 277 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 258 | thread_tree.insert(*cur_thread); | 278 | thread_tree.insert(*cur_thread); |
| 259 | cur_thread->SetState(ThreadState::Waiting); | ||
| 260 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | ||
| 261 | } | ||
| 262 | |||
| 263 | // Cancel the timer wait. | ||
| 264 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); | ||
| 265 | 279 | ||
| 266 | // Remove from the address arbiter. | 280 | // Wait for the thread to finish. |
| 267 | { | 281 | cur_thread->BeginWait(std::addressof(wait_queue)); |
| 268 | KScopedSchedulerLock sl(kernel); | 282 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| 269 | |||
| 270 | if (cur_thread->IsWaitingForAddressArbiter()) { | ||
| 271 | thread_tree.erase(thread_tree.iterator_to(*cur_thread)); | ||
| 272 | cur_thread->ClearAddressArbiter(); | ||
| 273 | } | ||
| 274 | } | 283 | } |
| 275 | 284 | ||
| 276 | // Get the result. | 285 | // Get the result. |
| 277 | KSynchronizationObject* dummy{}; | 286 | return cur_thread->GetWaitResult(); |
| 278 | return cur_thread->GetWaitResult(&dummy); | ||
| 279 | } | 287 | } |
| 280 | 288 | ||
| 281 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | 289 | ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
| 282 | // Prepare to wait. | 290 | // Prepare to wait. |
| 283 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 291 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 292 | ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); | ||
| 284 | 293 | ||
| 285 | { | 294 | { |
| 286 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; | 295 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; |
| @@ -291,9 +300,6 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 291 | return ResultTerminationRequested; | 300 | return ResultTerminationRequested; |
| 292 | } | 301 | } |
| 293 | 302 | ||
| 294 | // Set the synced object. | ||
| 295 | cur_thread->SetSyncedObject(nullptr, ResultTimedOut); | ||
| 296 | |||
| 297 | // Read the value from userspace. | 303 | // Read the value from userspace. |
| 298 | s32 user_value{}; | 304 | s32 user_value{}; |
| 299 | if (!ReadFromUser(system, &user_value, addr)) { | 305 | if (!ReadFromUser(system, &user_value, addr)) { |
| @@ -316,26 +322,14 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 316 | // Set the arbiter. | 322 | // Set the arbiter. |
| 317 | cur_thread->SetAddressArbiter(&thread_tree, addr); | 323 | cur_thread->SetAddressArbiter(&thread_tree, addr); |
| 318 | thread_tree.insert(*cur_thread); | 324 | thread_tree.insert(*cur_thread); |
| 319 | cur_thread->SetState(ThreadState::Waiting); | ||
| 320 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | ||
| 321 | } | ||
| 322 | |||
| 323 | // Cancel the timer wait. | ||
| 324 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); | ||
| 325 | 325 | ||
| 326 | // Remove from the address arbiter. | 326 | // Wait for the thread to finish. |
| 327 | { | 327 | cur_thread->BeginWait(std::addressof(wait_queue)); |
| 328 | KScopedSchedulerLock sl(kernel); | 328 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
| 329 | |||
| 330 | if (cur_thread->IsWaitingForAddressArbiter()) { | ||
| 331 | thread_tree.erase(thread_tree.iterator_to(*cur_thread)); | ||
| 332 | cur_thread->ClearAddressArbiter(); | ||
| 333 | } | ||
| 334 | } | 329 | } |
| 335 | 330 | ||
| 336 | // Get the result. | 331 | // Get the result. |
| 337 | KSynchronizationObject* dummy{}; | 332 | return cur_thread->GetWaitResult(); |
| 338 | return cur_thread->GetWaitResult(&dummy); | ||
| 339 | } | 333 | } |
| 340 | 334 | ||
| 341 | } // namespace Kernel | 335 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index e4fcdbc67..165b76747 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h | |||
| @@ -170,6 +170,10 @@ public: | |||
| 170 | } | 170 | } |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | const std::string& GetName() const { | ||
| 174 | return name; | ||
| 175 | } | ||
| 176 | |||
| 173 | private: | 177 | private: |
| 174 | void RegisterWithKernel(); | 178 | void RegisterWithKernel(); |
| 175 | void UnregisterWithKernel(); | 179 | void UnregisterWithKernel(); |
diff --git a/src/core/hle/kernel/k_class_token.cpp b/src/core/hle/kernel/k_class_token.cpp index 0be0027be..21e2fe494 100644 --- a/src/core/hle/kernel/k_class_token.cpp +++ b/src/core/hle/kernel/k_class_token.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "core/hle/kernel/k_class_token.h" | 6 | #include "core/hle/kernel/k_class_token.h" |
| 7 | #include "core/hle/kernel/k_client_port.h" | 7 | #include "core/hle/kernel/k_client_port.h" |
| 8 | #include "core/hle/kernel/k_client_session.h" | 8 | #include "core/hle/kernel/k_client_session.h" |
| 9 | #include "core/hle/kernel/k_code_memory.h" | ||
| 9 | #include "core/hle/kernel/k_event.h" | 10 | #include "core/hle/kernel/k_event.h" |
| 10 | #include "core/hle/kernel/k_port.h" | 11 | #include "core/hle/kernel/k_port.h" |
| 11 | #include "core/hle/kernel/k_process.h" | 12 | #include "core/hle/kernel/k_process.h" |
| @@ -48,7 +49,7 @@ static_assert(ClassToken<KWritableEvent> == 0b10001001'00000000); | |||
| 48 | static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000); | 49 | static_assert(ClassToken<KTransferMemory> == 0b10010001'00000000); |
| 49 | // static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000); | 50 | // static_assert(ClassToken<KDeviceAddressSpace> == 0b01100001'00000000); |
| 50 | // static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000); | 51 | // static_assert(ClassToken<KSessionRequest> == 0b10100001'00000000); |
| 51 | // static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000); | 52 | static_assert(ClassToken<KCodeMemory> == 0b11000001'00000000); |
| 52 | 53 | ||
| 53 | // Ensure that the token hierarchy is correct. | 54 | // Ensure that the token hierarchy is correct. |
| 54 | 55 | ||
| @@ -79,7 +80,7 @@ static_assert(ClassToken<KWritableEvent> == ((0b10001001 << 8) | ClassToken<KAut | |||
| 79 | static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); | 80 | static_assert(ClassToken<KTransferMemory> == ((0b10010001 << 8) | ClassToken<KAutoObject>)); |
| 80 | // static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>)); | 81 | // static_assert(ClassToken<KDeviceAddressSpace> == ((0b01100001 << 8) | ClassToken<KAutoObject>)); |
| 81 | // static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>)); | 82 | // static_assert(ClassToken<KSessionRequest> == ((0b10100001 << 8) | ClassToken<KAutoObject>)); |
| 82 | // static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>)); | 83 | static_assert(ClassToken<KCodeMemory> == ((0b11000001 << 8) | ClassToken<KAutoObject>)); |
| 83 | 84 | ||
| 84 | // Ensure that the token hierarchy reflects the class hierarchy. | 85 | // Ensure that the token hierarchy reflects the class hierarchy. |
| 85 | 86 | ||
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp new file mode 100644 index 000000000..d69f7ffb7 --- /dev/null +++ b/src/core/hle/kernel/k_code_memory.cpp | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/common_types.h" | ||
| 6 | #include "core/device_memory.h" | ||
| 7 | #include "core/hle/kernel/k_auto_object.h" | ||
| 8 | #include "core/hle/kernel/k_code_memory.h" | ||
| 9 | #include "core/hle/kernel/k_light_lock.h" | ||
| 10 | #include "core/hle/kernel/k_memory_block.h" | ||
| 11 | #include "core/hle/kernel/k_page_linked_list.h" | ||
| 12 | #include "core/hle/kernel/k_page_table.h" | ||
| 13 | #include "core/hle/kernel/k_process.h" | ||
| 14 | #include "core/hle/kernel/slab_helpers.h" | ||
| 15 | #include "core/hle/kernel/svc_types.h" | ||
| 16 | #include "core/hle/result.h" | ||
| 17 | |||
| 18 | namespace Kernel { | ||
| 19 | |||
| 20 | KCodeMemory::KCodeMemory(KernelCore& kernel_) | ||
| 21 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {} | ||
| 22 | |||
| 23 | ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) { | ||
| 24 | // Set members. | ||
| 25 | m_owner = kernel.CurrentProcess(); | ||
| 26 | |||
| 27 | // Get the owner page table. | ||
| 28 | auto& page_table = m_owner->PageTable(); | ||
| 29 | |||
| 30 | // Construct the page group. | ||
| 31 | KMemoryInfo kBlockInfo = page_table.QueryInfo(addr); | ||
| 32 | m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); | ||
| 33 | |||
| 34 | // Lock the memory. | ||
| 35 | R_TRY(page_table.LockForCodeMemory(addr, size)) | ||
| 36 | |||
| 37 | // Clear the memory. | ||
| 38 | for (const auto& block : m_page_group.Nodes()) { | ||
| 39 | std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); | ||
| 40 | } | ||
| 41 | |||
| 42 | // Set remaining tracking members. | ||
| 43 | m_address = addr; | ||
| 44 | m_is_initialized = true; | ||
| 45 | m_is_owner_mapped = false; | ||
| 46 | m_is_mapped = false; | ||
| 47 | |||
| 48 | // We succeeded. | ||
| 49 | return ResultSuccess; | ||
| 50 | } | ||
| 51 | |||
| 52 | void KCodeMemory::Finalize() { | ||
| 53 | // Unlock. | ||
| 54 | if (!m_is_mapped && !m_is_owner_mapped) { | ||
| 55 | const size_t size = m_page_group.GetNumPages() * PageSize; | ||
| 56 | m_owner->PageTable().UnlockForCodeMemory(m_address, size); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | ResultCode KCodeMemory::Map(VAddr address, size_t size) { | ||
| 61 | // Validate the size. | ||
| 62 | R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); | ||
| 63 | |||
| 64 | // Lock ourselves. | ||
| 65 | KScopedLightLock lk(m_lock); | ||
| 66 | |||
| 67 | // Ensure we're not already mapped. | ||
| 68 | R_UNLESS(!m_is_mapped, ResultInvalidState); | ||
| 69 | |||
| 70 | // Map the memory. | ||
| 71 | R_TRY(kernel.CurrentProcess()->PageTable().MapPages( | ||
| 72 | address, m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); | ||
| 73 | |||
| 74 | // Mark ourselves as mapped. | ||
| 75 | m_is_mapped = true; | ||
| 76 | |||
| 77 | return ResultSuccess; | ||
| 78 | } | ||
| 79 | |||
| 80 | ResultCode KCodeMemory::Unmap(VAddr address, size_t size) { | ||
| 81 | // Validate the size. | ||
| 82 | R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); | ||
| 83 | |||
| 84 | // Lock ourselves. | ||
| 85 | KScopedLightLock lk(m_lock); | ||
| 86 | |||
| 87 | // Unmap the memory. | ||
| 88 | R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, m_page_group, | ||
| 89 | KMemoryState::CodeOut)); | ||
| 90 | |||
| 91 | // Mark ourselves as unmapped. | ||
| 92 | m_is_mapped = false; | ||
| 93 | |||
| 94 | return ResultSuccess; | ||
| 95 | } | ||
| 96 | |||
| 97 | ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) { | ||
| 98 | // Validate the size. | ||
| 99 | R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); | ||
| 100 | |||
| 101 | // Lock ourselves. | ||
| 102 | KScopedLightLock lk(m_lock); | ||
| 103 | |||
| 104 | // Ensure we're not already mapped. | ||
| 105 | R_UNLESS(!m_is_owner_mapped, ResultInvalidState); | ||
| 106 | |||
| 107 | // Convert the memory permission. | ||
| 108 | KMemoryPermission k_perm{}; | ||
| 109 | switch (perm) { | ||
| 110 | case Svc::MemoryPermission::Read: | ||
| 111 | k_perm = KMemoryPermission::UserRead; | ||
| 112 | break; | ||
| 113 | case Svc::MemoryPermission::ReadExecute: | ||
| 114 | k_perm = KMemoryPermission::UserReadExecute; | ||
| 115 | break; | ||
| 116 | default: | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | |||
| 120 | // Map the memory. | ||
| 121 | R_TRY( | ||
| 122 | m_owner->PageTable().MapPages(address, m_page_group, KMemoryState::GeneratedCode, k_perm)); | ||
| 123 | |||
| 124 | // Mark ourselves as mapped. | ||
| 125 | m_is_owner_mapped = true; | ||
| 126 | |||
| 127 | return ResultSuccess; | ||
| 128 | } | ||
| 129 | |||
| 130 | ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { | ||
| 131 | // Validate the size. | ||
| 132 | R_UNLESS(m_page_group.GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize); | ||
| 133 | |||
| 134 | // Lock ourselves. | ||
| 135 | KScopedLightLock lk(m_lock); | ||
| 136 | |||
| 137 | // Unmap the memory. | ||
| 138 | R_TRY(m_owner->PageTable().UnmapPages(address, m_page_group, KMemoryState::GeneratedCode)); | ||
| 139 | |||
| 140 | // Mark ourselves as unmapped. | ||
| 141 | m_is_owner_mapped = false; | ||
| 142 | |||
| 143 | return ResultSuccess; | ||
| 144 | } | ||
| 145 | |||
| 146 | } // namespace Kernel \ No newline at end of file | ||
diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h new file mode 100644 index 000000000..e0ba19a53 --- /dev/null +++ b/src/core/hle/kernel/k_code_memory.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/device_memory.h" | ||
| 9 | #include "core/hle/kernel/k_auto_object.h" | ||
| 10 | #include "core/hle/kernel/k_light_lock.h" | ||
| 11 | #include "core/hle/kernel/k_page_linked_list.h" | ||
| 12 | #include "core/hle/kernel/k_process.h" | ||
| 13 | #include "core/hle/kernel/slab_helpers.h" | ||
| 14 | #include "core/hle/kernel/svc_types.h" | ||
| 15 | #include "core/hle/result.h" | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | enum class CodeMemoryOperation : u32 { | ||
| 20 | Map = 0, | ||
| 21 | MapToOwner = 1, | ||
| 22 | Unmap = 2, | ||
| 23 | UnmapFromOwner = 3, | ||
| 24 | }; | ||
| 25 | |||
| 26 | class KCodeMemory final | ||
| 27 | : public KAutoObjectWithSlabHeapAndContainer<KCodeMemory, KAutoObjectWithList> { | ||
| 28 | KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject); | ||
| 29 | |||
| 30 | public: | ||
| 31 | explicit KCodeMemory(KernelCore& kernel_); | ||
| 32 | |||
| 33 | ResultCode Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size); | ||
| 34 | void Finalize(); | ||
| 35 | |||
| 36 | ResultCode Map(VAddr address, size_t size); | ||
| 37 | ResultCode Unmap(VAddr address, size_t size); | ||
| 38 | ResultCode MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm); | ||
| 39 | ResultCode UnmapFromOwner(VAddr address, size_t size); | ||
| 40 | |||
| 41 | bool IsInitialized() const { | ||
| 42 | return m_is_initialized; | ||
| 43 | } | ||
| 44 | static void PostDestroy([[maybe_unused]] uintptr_t arg) {} | ||
| 45 | |||
| 46 | KProcess* GetOwner() const { | ||
| 47 | return m_owner; | ||
| 48 | } | ||
| 49 | VAddr GetSourceAddress() const { | ||
| 50 | return m_address; | ||
| 51 | } | ||
| 52 | size_t GetSize() const { | ||
| 53 | return m_is_initialized ? m_page_group.GetNumPages() * PageSize : 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | private: | ||
| 57 | KPageLinkedList m_page_group{}; | ||
| 58 | KProcess* m_owner{}; | ||
| 59 | VAddr m_address{}; | ||
| 60 | KLightLock m_lock; | ||
| 61 | bool m_is_initialized{}; | ||
| 62 | bool m_is_owner_mapped{}; | ||
| 63 | bool m_is_mapped{}; | ||
| 64 | }; | ||
| 65 | |||
| 66 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 7fa9b8cc3..aadcc297a 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 11 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 12 | #include "core/hle/kernel/k_synchronization_object.h" | 12 | #include "core/hle/kernel/k_synchronization_object.h" |
| 13 | #include "core/hle/kernel/k_thread.h" | 13 | #include "core/hle/kernel/k_thread.h" |
| 14 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 14 | #include "core/hle/kernel/kernel.h" | 15 | #include "core/hle/kernel/kernel.h" |
| 15 | #include "core/hle/kernel/svc_common.h" | 16 | #include "core/hle/kernel/svc_common.h" |
| 16 | #include "core/hle/kernel/svc_results.h" | 17 | #include "core/hle/kernel/svc_results.h" |
| @@ -33,7 +34,7 @@ bool WriteToUser(Core::System& system, VAddr address, const u32* p) { | |||
| 33 | bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero, | 34 | bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero, |
| 34 | u32 new_orr_mask) { | 35 | u32 new_orr_mask) { |
| 35 | auto& monitor = system.Monitor(); | 36 | auto& monitor = system.Monitor(); |
| 36 | const auto current_core = system.CurrentCoreIndex(); | 37 | const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); |
| 37 | 38 | ||
| 38 | // Load the value from the address. | 39 | // Load the value from the address. |
| 39 | const auto expected = monitor.ExclusiveRead32(current_core, address); | 40 | const auto expected = monitor.ExclusiveRead32(current_core, address); |
| @@ -57,6 +58,48 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero | |||
| 57 | return true; | 58 | return true; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 61 | class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue { | ||
| 62 | public: | ||
| 63 | explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_) | ||
| 64 | : KThreadQueue(kernel_) {} | ||
| 65 | |||
| 66 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 67 | bool cancel_timer_task) override { | ||
| 68 | // Remove the thread as a waiter from its owner. | ||
| 69 | waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread); | ||
| 70 | |||
| 71 | // Invoke the base cancel wait handler. | ||
| 72 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 73 | } | ||
| 74 | }; | ||
| 75 | |||
| 76 | class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue { | ||
| 77 | private: | ||
| 78 | KConditionVariable::ThreadTree* m_tree; | ||
| 79 | |||
| 80 | public: | ||
| 81 | explicit ThreadQueueImplForKConditionVariableWaitConditionVariable( | ||
| 82 | KernelCore& kernel_, KConditionVariable::ThreadTree* t) | ||
| 83 | : KThreadQueue(kernel_), m_tree(t) {} | ||
| 84 | |||
| 85 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 86 | bool cancel_timer_task) override { | ||
| 87 | // Remove the thread as a waiter from its owner. | ||
| 88 | if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { | ||
| 89 | owner->RemoveWaiter(waiting_thread); | ||
| 90 | } | ||
| 91 | |||
| 92 | // If the thread is waiting on a condvar, remove it from the tree. | ||
| 93 | if (waiting_thread->IsWaitingForConditionVariable()) { | ||
| 94 | m_tree->erase(m_tree->iterator_to(*waiting_thread)); | ||
| 95 | waiting_thread->ClearConditionVariable(); | ||
| 96 | } | ||
| 97 | |||
| 98 | // Invoke the base cancel wait handler. | ||
| 99 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 60 | } // namespace | 103 | } // namespace |
| 61 | 104 | ||
| 62 | KConditionVariable::KConditionVariable(Core::System& system_) | 105 | KConditionVariable::KConditionVariable(Core::System& system_) |
| @@ -78,84 +121,77 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { | |||
| 78 | 121 | ||
| 79 | // Determine the next tag. | 122 | // Determine the next tag. |
| 80 | u32 next_value{}; | 123 | u32 next_value{}; |
| 81 | if (next_owner_thread) { | 124 | if (next_owner_thread != nullptr) { |
| 82 | next_value = next_owner_thread->GetAddressKeyValue(); | 125 | next_value = next_owner_thread->GetAddressKeyValue(); |
| 83 | if (num_waiters > 1) { | 126 | if (num_waiters > 1) { |
| 84 | next_value |= Svc::HandleWaitMask; | 127 | next_value |= Svc::HandleWaitMask; |
| 85 | } | 128 | } |
| 86 | 129 | ||
| 87 | next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); | 130 | // Write the value to userspace. |
| 88 | next_owner_thread->Wakeup(); | 131 | ResultCode result{ResultSuccess}; |
| 89 | } | 132 | if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] { |
| 90 | 133 | result = ResultSuccess; | |
| 91 | // Write the value to userspace. | 134 | } else { |
| 92 | if (!WriteToUser(system, addr, std::addressof(next_value))) { | 135 | result = ResultInvalidCurrentMemory; |
| 93 | if (next_owner_thread) { | ||
| 94 | next_owner_thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); | ||
| 95 | } | 136 | } |
| 96 | 137 | ||
| 97 | return ResultInvalidCurrentMemory; | 138 | // Signal the next owner thread. |
| 139 | next_owner_thread->EndWait(result); | ||
| 140 | return result; | ||
| 141 | } else { | ||
| 142 | // Just write the value to userspace. | ||
| 143 | R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)), | ||
| 144 | ResultInvalidCurrentMemory); | ||
| 145 | |||
| 146 | return ResultSuccess; | ||
| 98 | } | 147 | } |
| 99 | } | 148 | } |
| 100 | |||
| 101 | return ResultSuccess; | ||
| 102 | } | 149 | } |
| 103 | 150 | ||
| 104 | ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { | 151 | ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { |
| 105 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 152 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 153 | ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel); | ||
| 106 | 154 | ||
| 107 | // Wait for the address. | 155 | // Wait for the address. |
| 156 | KThread* owner_thread{}; | ||
| 108 | { | 157 | { |
| 109 | KScopedAutoObject<KThread> owner_thread; | 158 | KScopedSchedulerLock sl(kernel); |
| 110 | ASSERT(owner_thread.IsNull()); | ||
| 111 | { | ||
| 112 | KScopedSchedulerLock sl(kernel); | ||
| 113 | cur_thread->SetSyncedObject(nullptr, ResultSuccess); | ||
| 114 | 159 | ||
| 115 | // Check if the thread should terminate. | 160 | // Check if the thread should terminate. |
| 116 | R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); | 161 | R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested); |
| 117 | 162 | ||
| 118 | { | 163 | // Read the tag from userspace. |
| 119 | // Read the tag from userspace. | 164 | u32 test_tag{}; |
| 120 | u32 test_tag{}; | 165 | R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory); |
| 121 | R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), | ||
| 122 | ResultInvalidCurrentMemory); | ||
| 123 | |||
| 124 | // If the tag isn't the handle (with wait mask), we're done. | ||
| 125 | R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), ResultSuccess); | ||
| 126 | |||
| 127 | // Get the lock owner thread. | ||
| 128 | owner_thread = | ||
| 129 | kernel.CurrentProcess()->GetHandleTable().GetObjectWithoutPseudoHandle<KThread>( | ||
| 130 | handle); | ||
| 131 | R_UNLESS(owner_thread.IsNotNull(), ResultInvalidHandle); | ||
| 132 | |||
| 133 | // Update the lock. | ||
| 134 | cur_thread->SetAddressKey(addr, value); | ||
| 135 | owner_thread->AddWaiter(cur_thread); | ||
| 136 | cur_thread->SetState(ThreadState::Waiting); | ||
| 137 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||
| 138 | cur_thread->SetMutexWaitAddressForDebugging(addr); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | ASSERT(owner_thread.IsNotNull()); | ||
| 142 | } | ||
| 143 | 166 | ||
| 144 | // Remove the thread as a waiter from the lock owner. | 167 | // If the tag isn't the handle (with wait mask), we're done. |
| 145 | { | 168 | R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask)); |
| 146 | KScopedSchedulerLock sl(kernel); | 169 | |
| 147 | KThread* owner_thread = cur_thread->GetLockOwner(); | 170 | // Get the lock owner thread. |
| 148 | if (owner_thread != nullptr) { | 171 | owner_thread = kernel.CurrentProcess() |
| 149 | owner_thread->RemoveWaiter(cur_thread); | 172 | ->GetHandleTable() |
| 150 | } | 173 | .GetObjectWithoutPseudoHandle<KThread>(handle) |
| 174 | .ReleasePointerUnsafe(); | ||
| 175 | R_UNLESS(owner_thread != nullptr, ResultInvalidHandle); | ||
| 176 | |||
| 177 | // Update the lock. | ||
| 178 | cur_thread->SetAddressKey(addr, value); | ||
| 179 | owner_thread->AddWaiter(cur_thread); | ||
| 180 | |||
| 181 | // Begin waiting. | ||
| 182 | cur_thread->BeginWait(std::addressof(wait_queue)); | ||
| 183 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||
| 184 | cur_thread->SetMutexWaitAddressForDebugging(addr); | ||
| 151 | } | 185 | } |
| 152 | 186 | ||
| 187 | // Close our reference to the owner thread, now that the wait is over. | ||
| 188 | owner_thread->Close(); | ||
| 189 | |||
| 153 | // Get the wait result. | 190 | // Get the wait result. |
| 154 | KSynchronizationObject* dummy{}; | 191 | return cur_thread->GetWaitResult(); |
| 155 | return cur_thread->GetWaitResult(std::addressof(dummy)); | ||
| 156 | } | 192 | } |
| 157 | 193 | ||
| 158 | KThread* KConditionVariable::SignalImpl(KThread* thread) { | 194 | void KConditionVariable::SignalImpl(KThread* thread) { |
| 159 | // Check pre-conditions. | 195 | // Check pre-conditions. |
| 160 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | 196 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 161 | 197 | ||
| @@ -169,18 +205,16 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { | |||
| 169 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. | 205 | // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable. |
| 170 | // TODO(bunnei): We should call CanAccessAtomic(..) here. | 206 | // TODO(bunnei): We should call CanAccessAtomic(..) here. |
| 171 | can_access = true; | 207 | can_access = true; |
| 172 | if (can_access) { | 208 | if (can_access) [[likely]] { |
| 173 | UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag, | 209 | UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag, |
| 174 | Svc::HandleWaitMask); | 210 | Svc::HandleWaitMask); |
| 175 | } | 211 | } |
| 176 | } | 212 | } |
| 177 | 213 | ||
| 178 | KThread* thread_to_close = nullptr; | 214 | if (can_access) [[likely]] { |
| 179 | if (can_access) { | ||
| 180 | if (prev_tag == Svc::InvalidHandle) { | 215 | if (prev_tag == Svc::InvalidHandle) { |
| 181 | // If nobody held the lock previously, we're all good. | 216 | // If nobody held the lock previously, we're all good. |
| 182 | thread->SetSyncedObject(nullptr, ResultSuccess); | 217 | thread->EndWait(ResultSuccess); |
| 183 | thread->Wakeup(); | ||
| 184 | } else { | 218 | } else { |
| 185 | // Get the previous owner. | 219 | // Get the previous owner. |
| 186 | KThread* owner_thread = kernel.CurrentProcess() | 220 | KThread* owner_thread = kernel.CurrentProcess() |
| @@ -189,33 +223,22 @@ KThread* KConditionVariable::SignalImpl(KThread* thread) { | |||
| 189 | static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask)) | 223 | static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask)) |
| 190 | .ReleasePointerUnsafe(); | 224 | .ReleasePointerUnsafe(); |
| 191 | 225 | ||
| 192 | if (owner_thread) { | 226 | if (owner_thread) [[likely]] { |
| 193 | // Add the thread as a waiter on the owner. | 227 | // Add the thread as a waiter on the owner. |
| 194 | owner_thread->AddWaiter(thread); | 228 | owner_thread->AddWaiter(thread); |
| 195 | thread_to_close = owner_thread; | 229 | owner_thread->Close(); |
| 196 | } else { | 230 | } else { |
| 197 | // The lock was tagged with a thread that doesn't exist. | 231 | // The lock was tagged with a thread that doesn't exist. |
| 198 | thread->SetSyncedObject(nullptr, ResultInvalidState); | 232 | thread->EndWait(ResultInvalidState); |
| 199 | thread->Wakeup(); | ||
| 200 | } | 233 | } |
| 201 | } | 234 | } |
| 202 | } else { | 235 | } else { |
| 203 | // If the address wasn't accessible, note so. | 236 | // If the address wasn't accessible, note so. |
| 204 | thread->SetSyncedObject(nullptr, ResultInvalidCurrentMemory); | 237 | thread->EndWait(ResultInvalidCurrentMemory); |
| 205 | thread->Wakeup(); | ||
| 206 | } | 238 | } |
| 207 | |||
| 208 | return thread_to_close; | ||
| 209 | } | 239 | } |
| 210 | 240 | ||
| 211 | void KConditionVariable::Signal(u64 cv_key, s32 count) { | 241 | void KConditionVariable::Signal(u64 cv_key, s32 count) { |
| 212 | // Prepare for signaling. | ||
| 213 | constexpr int MaxThreads = 16; | ||
| 214 | |||
| 215 | KLinkedList<KThread> thread_list{kernel}; | ||
| 216 | std::array<KThread*, MaxThreads> thread_array; | ||
| 217 | s32 num_to_close{}; | ||
| 218 | |||
| 219 | // Perform signaling. | 242 | // Perform signaling. |
| 220 | s32 num_waiters{}; | 243 | s32 num_waiters{}; |
| 221 | { | 244 | { |
| @@ -226,14 +249,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 226 | (it->GetConditionVariableKey() == cv_key)) { | 249 | (it->GetConditionVariableKey() == cv_key)) { |
| 227 | KThread* target_thread = std::addressof(*it); | 250 | KThread* target_thread = std::addressof(*it); |
| 228 | 251 | ||
| 229 | if (KThread* thread = SignalImpl(target_thread); thread != nullptr) { | 252 | this->SignalImpl(target_thread); |
| 230 | if (num_to_close < MaxThreads) { | ||
| 231 | thread_array[num_to_close++] = thread; | ||
| 232 | } else { | ||
| 233 | thread_list.push_back(*thread); | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | it = thread_tree.erase(it); | 253 | it = thread_tree.erase(it); |
| 238 | target_thread->ClearConditionVariable(); | 254 | target_thread->ClearConditionVariable(); |
| 239 | ++num_waiters; | 255 | ++num_waiters; |
| @@ -245,27 +261,16 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) { | |||
| 245 | WriteToUser(system, cv_key, std::addressof(has_waiter_flag)); | 261 | WriteToUser(system, cv_key, std::addressof(has_waiter_flag)); |
| 246 | } | 262 | } |
| 247 | } | 263 | } |
| 248 | |||
| 249 | // Close threads in the array. | ||
| 250 | for (auto i = 0; i < num_to_close; ++i) { | ||
| 251 | thread_array[i]->Close(); | ||
| 252 | } | ||
| 253 | |||
| 254 | // Close threads in the list. | ||
| 255 | for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) { | ||
| 256 | (*it).Close(); | ||
| 257 | } | ||
| 258 | } | 264 | } |
| 259 | 265 | ||
| 260 | ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { | 266 | ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) { |
| 261 | // Prepare to wait. | 267 | // Prepare to wait. |
| 262 | KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); | 268 | KThread* cur_thread = GetCurrentThreadPointer(kernel); |
| 269 | ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue( | ||
| 270 | kernel, std::addressof(thread_tree)); | ||
| 263 | 271 | ||
| 264 | { | 272 | { |
| 265 | KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout}; | 273 | KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout); |
| 266 | |||
| 267 | // Set the synced object. | ||
| 268 | cur_thread->SetSyncedObject(nullptr, ResultTimedOut); | ||
| 269 | 274 | ||
| 270 | // Check that the thread isn't terminating. | 275 | // Check that the thread isn't terminating. |
| 271 | if (cur_thread->IsTerminationRequested()) { | 276 | if (cur_thread->IsTerminationRequested()) { |
| @@ -290,8 +295,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) | |||
| 290 | } | 295 | } |
| 291 | 296 | ||
| 292 | // Wake up the next owner. | 297 | // Wake up the next owner. |
| 293 | next_owner_thread->SetSyncedObject(nullptr, ResultSuccess); | 298 | next_owner_thread->EndWait(ResultSuccess); |
| 294 | next_owner_thread->Wakeup(); | ||
| 295 | } | 299 | } |
| 296 | 300 | ||
| 297 | // Write to the cv key. | 301 | // Write to the cv key. |
| @@ -308,40 +312,21 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) | |||
| 308 | } | 312 | } |
| 309 | } | 313 | } |
| 310 | 314 | ||
| 311 | // Update condition variable tracking. | 315 | // If timeout is zero, time out. |
| 312 | { | 316 | R_UNLESS(timeout != 0, ResultTimedOut); |
| 313 | cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); | ||
| 314 | thread_tree.insert(*cur_thread); | ||
| 315 | } | ||
| 316 | 317 | ||
| 317 | // If the timeout is non-zero, set the thread as waiting. | 318 | // Update condition variable tracking. |
| 318 | if (timeout != 0) { | 319 | cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value); |
| 319 | cur_thread->SetState(ThreadState::Waiting); | 320 | thread_tree.insert(*cur_thread); |
| 320 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||
| 321 | cur_thread->SetMutexWaitAddressForDebugging(addr); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | // Cancel the timer wait. | ||
| 326 | kernel.TimeManager().UnscheduleTimeEvent(cur_thread); | ||
| 327 | |||
| 328 | // Remove from the condition variable. | ||
| 329 | { | ||
| 330 | KScopedSchedulerLock sl(kernel); | ||
| 331 | |||
| 332 | if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) { | ||
| 333 | owner->RemoveWaiter(cur_thread); | ||
| 334 | } | ||
| 335 | 321 | ||
| 336 | if (cur_thread->IsWaitingForConditionVariable()) { | 322 | // Begin waiting. |
| 337 | thread_tree.erase(thread_tree.iterator_to(*cur_thread)); | 323 | cur_thread->BeginWait(std::addressof(wait_queue)); |
| 338 | cur_thread->ClearConditionVariable(); | 324 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); |
| 339 | } | 325 | cur_thread->SetMutexWaitAddressForDebugging(addr); |
| 340 | } | 326 | } |
| 341 | 327 | ||
| 342 | // Get the result. | 328 | // Get the wait result. |
| 343 | KSynchronizationObject* dummy{}; | 329 | return cur_thread->GetWaitResult(); |
| 344 | return cur_thread->GetWaitResult(std::addressof(dummy)); | ||
| 345 | } | 330 | } |
| 346 | 331 | ||
| 347 | } // namespace Kernel | 332 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h index 861dbd420..5e4815d08 100644 --- a/src/core/hle/kernel/k_condition_variable.h +++ b/src/core/hle/kernel/k_condition_variable.h | |||
| @@ -34,7 +34,7 @@ public: | |||
| 34 | [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); | 34 | [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout); |
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | [[nodiscard]] KThread* SignalImpl(KThread* thread); | 37 | void SignalImpl(KThread* thread); |
| 38 | 38 | ||
| 39 | ThreadTree thread_tree; | 39 | ThreadTree thread_tree; |
| 40 | 40 | ||
diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp index e90fc0628..cf95f0852 100644 --- a/src/core/hle/kernel/k_handle_table.cpp +++ b/src/core/hle/kernel/k_handle_table.cpp | |||
| @@ -13,6 +13,7 @@ ResultCode KHandleTable::Finalize() { | |||
| 13 | // Get the table and clear our record of it. | 13 | // Get the table and clear our record of it. |
| 14 | u16 saved_table_size = 0; | 14 | u16 saved_table_size = 0; |
| 15 | { | 15 | { |
| 16 | KScopedDisableDispatch dd(kernel); | ||
| 16 | KScopedSpinLock lk(m_lock); | 17 | KScopedSpinLock lk(m_lock); |
| 17 | 18 | ||
| 18 | std::swap(m_table_size, saved_table_size); | 19 | std::swap(m_table_size, saved_table_size); |
| @@ -43,6 +44,7 @@ bool KHandleTable::Remove(Handle handle) { | |||
| 43 | // Find the object and free the entry. | 44 | // Find the object and free the entry. |
| 44 | KAutoObject* obj = nullptr; | 45 | KAutoObject* obj = nullptr; |
| 45 | { | 46 | { |
| 47 | KScopedDisableDispatch dd(kernel); | ||
| 46 | KScopedSpinLock lk(m_lock); | 48 | KScopedSpinLock lk(m_lock); |
| 47 | 49 | ||
| 48 | if (this->IsValidHandle(handle)) { | 50 | if (this->IsValidHandle(handle)) { |
| @@ -62,6 +64,7 @@ bool KHandleTable::Remove(Handle handle) { | |||
| 62 | } | 64 | } |
| 63 | 65 | ||
| 64 | ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { | 66 | ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { |
| 67 | KScopedDisableDispatch dd(kernel); | ||
| 65 | KScopedSpinLock lk(m_lock); | 68 | KScopedSpinLock lk(m_lock); |
| 66 | 69 | ||
| 67 | // Never exceed our capacity. | 70 | // Never exceed our capacity. |
| @@ -84,6 +87,7 @@ ResultCode KHandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) { | |||
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | ResultCode KHandleTable::Reserve(Handle* out_handle) { | 89 | ResultCode KHandleTable::Reserve(Handle* out_handle) { |
| 90 | KScopedDisableDispatch dd(kernel); | ||
| 87 | KScopedSpinLock lk(m_lock); | 91 | KScopedSpinLock lk(m_lock); |
| 88 | 92 | ||
| 89 | // Never exceed our capacity. | 93 | // Never exceed our capacity. |
| @@ -94,6 +98,7 @@ ResultCode KHandleTable::Reserve(Handle* out_handle) { | |||
| 94 | } | 98 | } |
| 95 | 99 | ||
| 96 | void KHandleTable::Unreserve(Handle handle) { | 100 | void KHandleTable::Unreserve(Handle handle) { |
| 101 | KScopedDisableDispatch dd(kernel); | ||
| 97 | KScopedSpinLock lk(m_lock); | 102 | KScopedSpinLock lk(m_lock); |
| 98 | 103 | ||
| 99 | // Unpack the handle. | 104 | // Unpack the handle. |
| @@ -112,6 +117,7 @@ void KHandleTable::Unreserve(Handle handle) { | |||
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { | 119 | void KHandleTable::Register(Handle handle, KAutoObject* obj, u16 type) { |
| 120 | KScopedDisableDispatch dd(kernel); | ||
| 115 | KScopedSpinLock lk(m_lock); | 121 | KScopedSpinLock lk(m_lock); |
| 116 | 122 | ||
| 117 | // Unpack the handle. | 123 | // Unpack the handle. |
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 95ec905ae..4b114ec2f 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h | |||
| @@ -68,6 +68,7 @@ public: | |||
| 68 | template <typename T = KAutoObject> | 68 | template <typename T = KAutoObject> |
| 69 | KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { | 69 | KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { |
| 70 | // Lock and look up in table. | 70 | // Lock and look up in table. |
| 71 | KScopedDisableDispatch dd(kernel); | ||
| 71 | KScopedSpinLock lk(m_lock); | 72 | KScopedSpinLock lk(m_lock); |
| 72 | 73 | ||
| 73 | if constexpr (std::is_same_v<T, KAutoObject>) { | 74 | if constexpr (std::is_same_v<T, KAutoObject>) { |
| @@ -122,6 +123,7 @@ public: | |||
| 122 | size_t num_opened; | 123 | size_t num_opened; |
| 123 | { | 124 | { |
| 124 | // Lock the table. | 125 | // Lock the table. |
| 126 | KScopedDisableDispatch dd(kernel); | ||
| 125 | KScopedSpinLock lk(m_lock); | 127 | KScopedSpinLock lk(m_lock); |
| 126 | for (num_opened = 0; num_opened < num_handles; num_opened++) { | 128 | for (num_opened = 0; num_opened < num_handles; num_opened++) { |
| 127 | // Get the current handle. | 129 | // Get the current handle. |
diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp new file mode 100644 index 000000000..a8001fffc --- /dev/null +++ b/src/core/hle/kernel/k_light_condition_variable.cpp | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_light_condition_variable.h" | ||
| 6 | #include "core/hle/kernel/k_scheduler.h" | ||
| 7 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 8 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 9 | #include "core/hle/kernel/svc_results.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue { | ||
| 16 | public: | ||
| 17 | ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl, | ||
| 18 | bool term) | ||
| 19 | : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {} | ||
| 20 | |||
| 21 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 22 | bool cancel_timer_task) override { | ||
| 23 | // Only process waits if we're allowed to. | ||
| 24 | if (ResultTerminationRequested == wait_result && m_allow_terminating_thread) { | ||
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 28 | // Remove the thread from the waiting thread from the light condition variable. | ||
| 29 | m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); | ||
| 30 | |||
| 31 | // Invoke the base cancel wait handler. | ||
| 32 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 33 | } | ||
| 34 | |||
| 35 | private: | ||
| 36 | KThread::WaiterList* m_wait_list; | ||
| 37 | bool m_allow_terminating_thread; | ||
| 38 | }; | ||
| 39 | |||
| 40 | } // namespace | ||
| 41 | |||
| 42 | void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { | ||
| 43 | // Create thread queue. | ||
| 44 | KThread* owner = GetCurrentThreadPointer(kernel); | ||
| 45 | |||
| 46 | ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list), | ||
| 47 | allow_terminating_thread); | ||
| 48 | |||
| 49 | // Sleep the thread. | ||
| 50 | { | ||
| 51 | KScopedSchedulerLockAndSleep lk(kernel, owner, timeout); | ||
| 52 | |||
| 53 | if (!allow_terminating_thread && owner->IsTerminationRequested()) { | ||
| 54 | lk.CancelSleep(); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | lock->Unlock(); | ||
| 59 | |||
| 60 | // Add the thread to the queue. | ||
| 61 | wait_list.push_back(*owner); | ||
| 62 | |||
| 63 | // Begin waiting. | ||
| 64 | owner->BeginWait(std::addressof(wait_queue)); | ||
| 65 | } | ||
| 66 | |||
| 67 | // Re-acquire the lock. | ||
| 68 | lock->Lock(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void KLightConditionVariable::Broadcast() { | ||
| 72 | KScopedSchedulerLock lk(kernel); | ||
| 73 | |||
| 74 | // Signal all threads. | ||
| 75 | for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) { | ||
| 76 | it->EndWait(ResultSuccess); | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h index fb0ad783a..5d6d7f128 100644 --- a/src/core/hle/kernel/k_light_condition_variable.h +++ b/src/core/hle/kernel/k_light_condition_variable.h | |||
| @@ -2,72 +2,24 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | 5 | #pragma once |
| 9 | 6 | ||
| 10 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/k_scheduler.h" | 8 | #include "core/hle/kernel/k_thread.h" |
| 12 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | ||
| 13 | #include "core/hle/kernel/time_manager.h" | ||
| 14 | 9 | ||
| 15 | namespace Kernel { | 10 | namespace Kernel { |
| 11 | |||
| 16 | class KernelCore; | 12 | class KernelCore; |
| 13 | class KLightLock; | ||
| 17 | 14 | ||
| 18 | class KLightConditionVariable { | 15 | class KLightConditionVariable { |
| 19 | public: | 16 | public: |
| 20 | explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} | 17 | explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {} |
| 21 | 18 | ||
| 22 | void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true) { | 19 | void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true); |
| 23 | WaitImpl(lock, timeout, allow_terminating_thread); | 20 | void Broadcast(); |
| 24 | } | ||
| 25 | |||
| 26 | void Broadcast() { | ||
| 27 | KScopedSchedulerLock lk{kernel}; | ||
| 28 | |||
| 29 | // Signal all threads. | ||
| 30 | for (auto& thread : wait_list) { | ||
| 31 | thread.SetState(ThreadState::Runnable); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | 21 | ||
| 35 | private: | 22 | private: |
| 36 | void WaitImpl(KLightLock* lock, s64 timeout, bool allow_terminating_thread) { | ||
| 37 | KThread* owner = GetCurrentThreadPointer(kernel); | ||
| 38 | |||
| 39 | // Sleep the thread. | ||
| 40 | { | ||
| 41 | KScopedSchedulerLockAndSleep lk{kernel, owner, timeout}; | ||
| 42 | |||
| 43 | if (!allow_terminating_thread && owner->IsTerminationRequested()) { | ||
| 44 | lk.CancelSleep(); | ||
| 45 | return; | ||
| 46 | } | ||
| 47 | |||
| 48 | lock->Unlock(); | ||
| 49 | |||
| 50 | // Set the thread as waiting. | ||
| 51 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | ||
| 52 | |||
| 53 | // Add the thread to the queue. | ||
| 54 | wait_list.push_back(GetCurrentThread(kernel)); | ||
| 55 | } | ||
| 56 | |||
| 57 | // Remove the thread from the wait list. | ||
| 58 | { | ||
| 59 | KScopedSchedulerLock sl{kernel}; | ||
| 60 | |||
| 61 | wait_list.erase(wait_list.iterator_to(GetCurrentThread(kernel))); | ||
| 62 | } | ||
| 63 | |||
| 64 | // Cancel the task that the sleep setup. | ||
| 65 | kernel.TimeManager().UnscheduleTimeEvent(owner); | ||
| 66 | |||
| 67 | // Re-acquire the lock. | ||
| 68 | lock->Lock(); | ||
| 69 | } | ||
| 70 | |||
| 71 | KernelCore& kernel; | 23 | KernelCore& kernel; |
| 72 | KThread::WaiterList wait_list{}; | 24 | KThread::WaiterList wait_list{}; |
| 73 | }; | 25 | }; |
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 0896e705f..4620342eb 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp | |||
| @@ -5,44 +5,59 @@ | |||
| 5 | #include "core/hle/kernel/k_light_lock.h" | 5 | #include "core/hle/kernel/k_light_lock.h" |
| 6 | #include "core/hle/kernel/k_scheduler.h" | 6 | #include "core/hle/kernel/k_scheduler.h" |
| 7 | #include "core/hle/kernel/k_thread.h" | 7 | #include "core/hle/kernel/k_thread.h" |
| 8 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 9 | 10 | ||
| 10 | namespace Kernel { | 11 | namespace Kernel { |
| 11 | 12 | ||
| 13 | namespace { | ||
| 14 | |||
| 15 | class ThreadQueueImplForKLightLock final : public KThreadQueue { | ||
| 16 | public: | ||
| 17 | explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {} | ||
| 18 | |||
| 19 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 20 | bool cancel_timer_task) override { | ||
| 21 | // Remove the thread as a waiter from its owner. | ||
| 22 | if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) { | ||
| 23 | owner->RemoveWaiter(waiting_thread); | ||
| 24 | } | ||
| 25 | |||
| 26 | // Invoke the base cancel wait handler. | ||
| 27 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 28 | } | ||
| 29 | }; | ||
| 30 | |||
| 31 | } // namespace | ||
| 32 | |||
| 12 | void KLightLock::Lock() { | 33 | void KLightLock::Lock() { |
| 13 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); | 34 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); |
| 14 | const uintptr_t cur_thread_tag = (cur_thread | 1); | ||
| 15 | 35 | ||
| 16 | while (true) { | 36 | while (true) { |
| 17 | uintptr_t old_tag = tag.load(std::memory_order_relaxed); | 37 | uintptr_t old_tag = tag.load(std::memory_order_relaxed); |
| 18 | 38 | ||
| 19 | while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1, | 39 | while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1), |
| 20 | std::memory_order_acquire)) { | 40 | std::memory_order_acquire)) { |
| 21 | if ((old_tag | 1) == cur_thread_tag) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | } | 41 | } |
| 25 | 42 | ||
| 26 | if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) { | 43 | if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) { |
| 27 | break; | 44 | break; |
| 28 | } | 45 | } |
| 29 | |||
| 30 | LockSlowPath(old_tag | 1, cur_thread); | ||
| 31 | } | 46 | } |
| 32 | } | 47 | } |
| 33 | 48 | ||
| 34 | void KLightLock::Unlock() { | 49 | void KLightLock::Unlock() { |
| 35 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); | 50 | const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)); |
| 51 | |||
| 36 | uintptr_t expected = cur_thread; | 52 | uintptr_t expected = cur_thread; |
| 37 | do { | 53 | if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) { |
| 38 | if (expected != cur_thread) { | 54 | this->UnlockSlowPath(cur_thread); |
| 39 | return UnlockSlowPath(cur_thread); | 55 | } |
| 40 | } | ||
| 41 | } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release)); | ||
| 42 | } | 56 | } |
| 43 | 57 | ||
| 44 | void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | 58 | bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { |
| 45 | KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread); | 59 | KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread); |
| 60 | ThreadQueueImplForKLightLock wait_queue(kernel); | ||
| 46 | 61 | ||
| 47 | // Pend the current thread waiting on the owner thread. | 62 | // Pend the current thread waiting on the owner thread. |
| 48 | { | 63 | { |
| @@ -50,7 +65,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | |||
| 50 | 65 | ||
| 51 | // Ensure we actually have locking to do. | 66 | // Ensure we actually have locking to do. |
| 52 | if (tag.load(std::memory_order_relaxed) != _owner) { | 67 | if (tag.load(std::memory_order_relaxed) != _owner) { |
| 53 | return; | 68 | return false; |
| 54 | } | 69 | } |
| 55 | 70 | ||
| 56 | // Add the current thread as a waiter on the owner. | 71 | // Add the current thread as a waiter on the owner. |
| @@ -58,22 +73,15 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { | |||
| 58 | cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); | 73 | cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag))); |
| 59 | owner_thread->AddWaiter(cur_thread); | 74 | owner_thread->AddWaiter(cur_thread); |
| 60 | 75 | ||
| 61 | // Set thread states. | 76 | // Begin waiting to hold the lock. |
| 62 | cur_thread->SetState(ThreadState::Waiting); | 77 | cur_thread->BeginWait(std::addressof(wait_queue)); |
| 63 | 78 | ||
| 64 | if (owner_thread->IsSuspended()) { | 79 | if (owner_thread->IsSuspended()) { |
| 65 | owner_thread->ContinueIfHasKernelWaiters(); | 80 | owner_thread->ContinueIfHasKernelWaiters(); |
| 66 | } | 81 | } |
| 67 | } | 82 | } |
| 68 | 83 | ||
| 69 | // We're no longer waiting on the lock owner. | 84 | return true; |
| 70 | { | ||
| 71 | KScopedSchedulerLock sl{kernel}; | ||
| 72 | |||
| 73 | if (KThread* owner_thread = cur_thread->GetLockOwner(); owner_thread != nullptr) { | ||
| 74 | owner_thread->RemoveWaiter(cur_thread); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | 85 | } |
| 78 | 86 | ||
| 79 | void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | 87 | void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { |
| @@ -81,22 +89,20 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | |||
| 81 | 89 | ||
| 82 | // Unlock. | 90 | // Unlock. |
| 83 | { | 91 | { |
| 84 | KScopedSchedulerLock sl{kernel}; | 92 | KScopedSchedulerLock sl(kernel); |
| 85 | 93 | ||
| 86 | // Get the next owner. | 94 | // Get the next owner. |
| 87 | s32 num_waiters = 0; | 95 | s32 num_waiters; |
| 88 | KThread* next_owner = owner_thread->RemoveWaiterByKey( | 96 | KThread* next_owner = owner_thread->RemoveWaiterByKey( |
| 89 | std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); | 97 | std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag))); |
| 90 | 98 | ||
| 91 | // Pass the lock to the next owner. | 99 | // Pass the lock to the next owner. |
| 92 | uintptr_t next_tag = 0; | 100 | uintptr_t next_tag = 0; |
| 93 | if (next_owner != nullptr) { | 101 | if (next_owner != nullptr) { |
| 94 | next_tag = reinterpret_cast<uintptr_t>(next_owner); | 102 | next_tag = |
| 95 | if (num_waiters > 1) { | 103 | reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1); |
| 96 | next_tag |= 0x1; | ||
| 97 | } | ||
| 98 | 104 | ||
| 99 | next_owner->SetState(ThreadState::Runnable); | 105 | next_owner->EndWait(ResultSuccess); |
| 100 | 106 | ||
| 101 | if (next_owner->IsSuspended()) { | 107 | if (next_owner->IsSuspended()) { |
| 102 | next_owner->ContinueIfHasKernelWaiters(); | 108 | next_owner->ContinueIfHasKernelWaiters(); |
| @@ -110,7 +116,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { | |||
| 110 | } | 116 | } |
| 111 | 117 | ||
| 112 | // Write the new tag value. | 118 | // Write the new tag value. |
| 113 | tag.store(next_tag); | 119 | tag.store(next_tag, std::memory_order_release); |
| 114 | } | 120 | } |
| 115 | } | 121 | } |
| 116 | 122 | ||
diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h index ad853661d..4163b8a85 100644 --- a/src/core/hle/kernel/k_light_lock.h +++ b/src/core/hle/kernel/k_light_lock.h | |||
| @@ -20,7 +20,7 @@ public: | |||
| 20 | 20 | ||
| 21 | void Unlock(); | 21 | void Unlock(); |
| 22 | 22 | ||
| 23 | void LockSlowPath(uintptr_t owner, uintptr_t cur_thread); | 23 | bool LockSlowPath(uintptr_t owner, uintptr_t cur_thread); |
| 24 | 24 | ||
| 25 | void UnlockSlowPath(uintptr_t cur_thread); | 25 | void UnlockSlowPath(uintptr_t cur_thread); |
| 26 | 26 | ||
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index a7fdb5fb8..fd491146f 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h | |||
| @@ -131,6 +131,26 @@ enum class KMemoryPermission : u8 { | |||
| 131 | 131 | ||
| 132 | UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | | 132 | UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | |
| 133 | Svc::MemoryPermission::Execute), | 133 | Svc::MemoryPermission::Execute), |
| 134 | |||
| 135 | KernelShift = 3, | ||
| 136 | |||
| 137 | KernelRead = Read << KernelShift, | ||
| 138 | KernelWrite = Write << KernelShift, | ||
| 139 | KernelExecute = Execute << KernelShift, | ||
| 140 | |||
| 141 | NotMapped = (1 << (2 * KernelShift)), | ||
| 142 | |||
| 143 | KernelReadWrite = KernelRead | KernelWrite, | ||
| 144 | KernelReadExecute = KernelRead | KernelExecute, | ||
| 145 | |||
| 146 | UserRead = Read | KernelRead, | ||
| 147 | UserWrite = Write | KernelWrite, | ||
| 148 | UserExecute = Execute, | ||
| 149 | |||
| 150 | UserReadWrite = UserRead | UserWrite, | ||
| 151 | UserReadExecute = UserRead | UserExecute, | ||
| 152 | |||
| 153 | IpcLockChangeMask = NotMapped | UserReadWrite | ||
| 134 | }; | 154 | }; |
| 135 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); | 155 | DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); |
| 136 | 156 | ||
diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h index 3362fb236..0e2ae582a 100644 --- a/src/core/hle/kernel/k_page_linked_list.h +++ b/src/core/hle/kernel/k_page_linked_list.h | |||
| @@ -27,6 +27,10 @@ public: | |||
| 27 | return num_pages; | 27 | return num_pages; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | constexpr std::size_t GetSize() const { | ||
| 31 | return GetNumPages() * PageSize; | ||
| 32 | } | ||
| 33 | |||
| 30 | private: | 34 | private: |
| 31 | u64 addr{}; | 35 | u64 addr{}; |
| 32 | std::size_t num_pages{}; | 36 | std::size_t num_pages{}; |
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 526b87241..99982e5a3 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp | |||
| @@ -368,6 +368,33 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st | |||
| 368 | return ResultSuccess; | 368 | return ResultSuccess; |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, | ||
| 372 | KPageTable& src_page_table, VAddr src_addr) { | ||
| 373 | std::lock_guard lock{page_table_lock}; | ||
| 374 | |||
| 375 | const std::size_t num_pages{size / PageSize}; | ||
| 376 | |||
| 377 | // Check that the memory is mapped in the destination process. | ||
| 378 | size_t num_allocator_blocks; | ||
| 379 | R_TRY(CheckMemoryState(&num_allocator_blocks, dst_addr, size, KMemoryState::All, | ||
| 380 | KMemoryState::SharedCode, KMemoryPermission::UserReadWrite, | ||
| 381 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, | ||
| 382 | KMemoryAttribute::None)); | ||
| 383 | |||
| 384 | // Check that the memory is mapped in the source process. | ||
| 385 | R_TRY(src_page_table.CheckMemoryState(src_addr, size, KMemoryState::FlagCanMapProcess, | ||
| 386 | KMemoryState::FlagCanMapProcess, KMemoryPermission::None, | ||
| 387 | KMemoryPermission::None, KMemoryAttribute::All, | ||
| 388 | KMemoryAttribute::None)); | ||
| 389 | |||
| 390 | CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); | ||
| 391 | |||
| 392 | // Apply the memory block update. | ||
| 393 | block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None, | ||
| 394 | KMemoryAttribute::None); | ||
| 395 | |||
| 396 | return ResultSuccess; | ||
| 397 | } | ||
| 371 | void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { | 398 | void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { |
| 372 | auto node{page_linked_list.Nodes().begin()}; | 399 | auto node{page_linked_list.Nodes().begin()}; |
| 373 | PAddr map_addr{node->GetAddress()}; | 400 | PAddr map_addr{node->GetAddress()}; |
| @@ -685,8 +712,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, | |||
| 685 | return ResultSuccess; | 712 | return ResultSuccess; |
| 686 | } | 713 | } |
| 687 | 714 | ||
| 688 | ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, | 715 | ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, |
| 689 | KMemoryPermission perm) { | 716 | KMemoryPermission perm) { |
| 690 | 717 | ||
| 691 | std::lock_guard lock{page_table_lock}; | 718 | std::lock_guard lock{page_table_lock}; |
| 692 | 719 | ||
| @@ -942,6 +969,60 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) | |||
| 942 | return ResultSuccess; | 969 | return ResultSuccess; |
| 943 | } | 970 | } |
| 944 | 971 | ||
| 972 | ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { | ||
| 973 | std::lock_guard lock{page_table_lock}; | ||
| 974 | |||
| 975 | KMemoryPermission new_perm = KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite; | ||
| 976 | |||
| 977 | KMemoryPermission old_perm{}; | ||
| 978 | |||
| 979 | if (const ResultCode result{CheckMemoryState( | ||
| 980 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | ||
| 981 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::Mask, | ||
| 982 | KMemoryPermission::UserReadWrite, KMemoryAttribute::All, KMemoryAttribute::None)}; | ||
| 983 | result.IsError()) { | ||
| 984 | return result; | ||
| 985 | } | ||
| 986 | |||
| 987 | new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; | ||
| 988 | |||
| 989 | block_manager->UpdateLock( | ||
| 990 | addr, size / PageSize, | ||
| 991 | [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { | ||
| 992 | block->ShareToDevice(permission); | ||
| 993 | }, | ||
| 994 | new_perm); | ||
| 995 | |||
| 996 | return ResultSuccess; | ||
| 997 | } | ||
| 998 | |||
| 999 | ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { | ||
| 1000 | std::lock_guard lock{page_table_lock}; | ||
| 1001 | |||
| 1002 | KMemoryPermission new_perm = KMemoryPermission::UserReadWrite; | ||
| 1003 | |||
| 1004 | KMemoryPermission old_perm{}; | ||
| 1005 | |||
| 1006 | if (const ResultCode result{CheckMemoryState( | ||
| 1007 | nullptr, &old_perm, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, | ||
| 1008 | KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, KMemoryPermission::None, | ||
| 1009 | KMemoryAttribute::All, KMemoryAttribute::Locked)}; | ||
| 1010 | result.IsError()) { | ||
| 1011 | return result; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | new_perm = (new_perm != KMemoryPermission::None) ? new_perm : old_perm; | ||
| 1015 | |||
| 1016 | block_manager->UpdateLock( | ||
| 1017 | addr, size / PageSize, | ||
| 1018 | [](KMemoryBlockManager::iterator block, KMemoryPermission permission) { | ||
| 1019 | block->UnshareToDevice(permission); | ||
| 1020 | }, | ||
| 1021 | new_perm); | ||
| 1022 | |||
| 1023 | return ResultSuccess; | ||
| 1024 | } | ||
| 1025 | |||
| 945 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { | 1026 | ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { |
| 946 | block_manager = std::make_unique<KMemoryBlockManager>(start, end); | 1027 | block_manager = std::make_unique<KMemoryBlockManager>(start, end); |
| 947 | 1028 | ||
| @@ -1231,4 +1312,42 @@ ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermissi | |||
| 1231 | return ResultSuccess; | 1312 | return ResultSuccess; |
| 1232 | } | 1313 | } |
| 1233 | 1314 | ||
| 1315 | ResultCode KPageTable::CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, | ||
| 1316 | KMemoryState state_mask, KMemoryState state, | ||
| 1317 | KMemoryPermission perm_mask, KMemoryPermission perm, | ||
| 1318 | KMemoryAttribute attr_mask, KMemoryAttribute attr) const { | ||
| 1319 | // Get information about the first block. | ||
| 1320 | const VAddr last_addr = addr + size - 1; | ||
| 1321 | KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; | ||
| 1322 | KMemoryInfo info = it->GetMemoryInfo(); | ||
| 1323 | |||
| 1324 | // If the start address isn't aligned, we need a block. | ||
| 1325 | const size_t blocks_for_start_align = | ||
| 1326 | (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0; | ||
| 1327 | |||
| 1328 | while (true) { | ||
| 1329 | // Validate against the provided masks. | ||
| 1330 | R_TRY(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); | ||
| 1331 | |||
| 1332 | // Break once we're done. | ||
| 1333 | if (last_addr <= info.GetLastAddress()) { | ||
| 1334 | break; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | // Advance our iterator. | ||
| 1338 | it++; | ||
| 1339 | info = it->GetMemoryInfo(); | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | // If the end address isn't aligned, we need a block. | ||
| 1343 | const size_t blocks_for_end_align = | ||
| 1344 | (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0; | ||
| 1345 | |||
| 1346 | if (out_blocks_needed != nullptr) { | ||
| 1347 | *out_blocks_needed = blocks_for_start_align + blocks_for_end_align; | ||
| 1348 | } | ||
| 1349 | |||
| 1350 | return ResultSuccess; | ||
| 1351 | } | ||
| 1352 | |||
| 1234 | } // namespace Kernel | 1353 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 770c4841c..d784aa67e 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h | |||
| @@ -33,6 +33,8 @@ public: | |||
| 33 | KMemoryPermission perm); | 33 | KMemoryPermission perm); |
| 34 | ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); | 34 | ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); |
| 35 | ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); | 35 | ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); |
| 36 | ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, | ||
| 37 | VAddr src_addr); | ||
| 36 | ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); | 38 | ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); |
| 37 | ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); | 39 | ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); |
| 38 | ResultCode UnmapMemory(VAddr addr, std::size_t size); | 40 | ResultCode UnmapMemory(VAddr addr, std::size_t size); |
| @@ -41,7 +43,7 @@ public: | |||
| 41 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, | 43 | ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, |
| 42 | KMemoryPermission perm); | 44 | KMemoryPermission perm); |
| 43 | ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); | 45 | ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); |
| 44 | ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); | 46 | ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 45 | KMemoryInfo QueryInfo(VAddr addr); | 47 | KMemoryInfo QueryInfo(VAddr addr); |
| 46 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); | 48 | ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); |
| 47 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); | 49 | ResultCode ResetTransferMemory(VAddr addr, std::size_t size); |
| @@ -55,6 +57,8 @@ public: | |||
| 55 | KMemoryPermission perm, PAddr map_addr = 0); | 57 | KMemoryPermission perm, PAddr map_addr = 0); |
| 56 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); | 58 | ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 57 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); | 59 | ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); |
| 60 | ResultCode LockForCodeMemory(VAddr addr, std::size_t size); | ||
| 61 | ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); | ||
| 58 | 62 | ||
| 59 | Common::PageTable& PageTableImpl() { | 63 | Common::PageTable& PageTableImpl() { |
| 60 | return page_table_impl; | 64 | return page_table_impl; |
| @@ -115,6 +119,10 @@ private: | |||
| 115 | return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, | 119 | return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, |
| 116 | perm, attr_mask, attr, ignore_attr); | 120 | perm, attr_mask, attr, ignore_attr); |
| 117 | } | 121 | } |
| 122 | ResultCode CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size, | ||
| 123 | KMemoryState state_mask, KMemoryState state, | ||
| 124 | KMemoryPermission perm_mask, KMemoryPermission perm, | ||
| 125 | KMemoryAttribute attr_mask, KMemoryAttribute attr) const; | ||
| 118 | 126 | ||
| 119 | std::recursive_mutex page_table_lock; | 127 | std::recursive_mutex page_table_lock; |
| 120 | std::unique_ptr<KMemoryBlockManager> block_manager; | 128 | std::unique_ptr<KMemoryBlockManager> block_manager; |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 76fd8c285..90dda40dc 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -60,6 +60,7 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority | |||
| 60 | thread->GetContext64().cpu_registers[0] = 0; | 60 | thread->GetContext64().cpu_registers[0] = 0; |
| 61 | thread->GetContext32().cpu_registers[1] = thread_handle; | 61 | thread->GetContext32().cpu_registers[1] = thread_handle; |
| 62 | thread->GetContext64().cpu_registers[1] = thread_handle; | 62 | thread->GetContext64().cpu_registers[1] = thread_handle; |
| 63 | thread->DisableDispatch(); | ||
| 63 | 64 | ||
| 64 | auto& kernel = system.Kernel(); | 65 | auto& kernel = system.Kernel(); |
| 65 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires | 66 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires |
| @@ -227,12 +228,15 @@ void KProcess::PinCurrentThread() { | |||
| 227 | const s32 core_id = GetCurrentCoreId(kernel); | 228 | const s32 core_id = GetCurrentCoreId(kernel); |
| 228 | KThread* cur_thread = GetCurrentThreadPointer(kernel); | 229 | KThread* cur_thread = GetCurrentThreadPointer(kernel); |
| 229 | 230 | ||
| 230 | // Pin it. | 231 | // If the thread isn't terminated, pin it. |
| 231 | PinThread(core_id, cur_thread); | 232 | if (!cur_thread->IsTerminationRequested()) { |
| 232 | cur_thread->Pin(); | 233 | // Pin it. |
| 234 | PinThread(core_id, cur_thread); | ||
| 235 | cur_thread->Pin(); | ||
| 233 | 236 | ||
| 234 | // An update is needed. | 237 | // An update is needed. |
| 235 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 238 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 239 | } | ||
| 236 | } | 240 | } |
| 237 | 241 | ||
| 238 | void KProcess::UnpinCurrentThread() { | 242 | void KProcess::UnpinCurrentThread() { |
| @@ -250,6 +254,20 @@ void KProcess::UnpinCurrentThread() { | |||
| 250 | KScheduler::SetSchedulerUpdateNeeded(kernel); | 254 | KScheduler::SetSchedulerUpdateNeeded(kernel); |
| 251 | } | 255 | } |
| 252 | 256 | ||
| 257 | void KProcess::UnpinThread(KThread* thread) { | ||
| 258 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); | ||
| 259 | |||
| 260 | // Get the thread's core id. | ||
| 261 | const auto core_id = thread->GetActiveCore(); | ||
| 262 | |||
| 263 | // Unpin it. | ||
| 264 | UnpinThread(core_id, thread); | ||
| 265 | thread->Unpin(); | ||
| 266 | |||
| 267 | // An update is needed. | ||
| 268 | KScheduler::SetSchedulerUpdateNeeded(kernel); | ||
| 269 | } | ||
| 270 | |||
| 253 | ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, | 271 | ResultCode KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address, |
| 254 | [[maybe_unused]] size_t size) { | 272 | [[maybe_unused]] size_t size) { |
| 255 | // Lock ourselves, to prevent concurrent access. | 273 | // Lock ourselves, to prevent concurrent access. |
| @@ -528,7 +546,7 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { | |||
| 528 | std::lock_guard lock{HLE::g_hle_lock}; | 546 | std::lock_guard lock{HLE::g_hle_lock}; |
| 529 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, | 547 | const auto ReprotectSegment = [&](const CodeSet::Segment& segment, |
| 530 | KMemoryPermission permission) { | 548 | KMemoryPermission permission) { |
| 531 | page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); | 549 | page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); |
| 532 | }; | 550 | }; |
| 533 | 551 | ||
| 534 | kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), | 552 | kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), |
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 8a8c1fcbb..cb93c7e24 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h | |||
| @@ -347,6 +347,7 @@ public: | |||
| 347 | 347 | ||
| 348 | void PinCurrentThread(); | 348 | void PinCurrentThread(); |
| 349 | void UnpinCurrentThread(); | 349 | void UnpinCurrentThread(); |
| 350 | void UnpinThread(KThread* thread); | ||
| 350 | 351 | ||
| 351 | KLightLock& GetStateLock() { | 352 | KLightLock& GetStateLock() { |
| 352 | return state_lock; | 353 | return state_lock; |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 6a7d80d03..277201de4 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -240,8 +240,8 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s3 | |||
| 240 | 240 | ||
| 241 | // If the thread is runnable, we want to change its priority in the queue. | 241 | // If the thread is runnable, we want to change its priority in the queue. |
| 242 | if (thread->GetRawState() == ThreadState::Runnable) { | 242 | if (thread->GetRawState() == ThreadState::Runnable) { |
| 243 | GetPriorityQueue(kernel).ChangePriority( | 243 | GetPriorityQueue(kernel).ChangePriority(old_priority, |
| 244 | old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread); | 244 | thread == kernel.GetCurrentEmuThread(), thread); |
| 245 | IncrementScheduledCount(thread); | 245 | IncrementScheduledCount(thread); |
| 246 | SetSchedulerUpdateNeeded(kernel); | 246 | SetSchedulerUpdateNeeded(kernel); |
| 247 | } | 247 | } |
| @@ -360,7 +360,7 @@ void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) { | |||
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | bool KScheduler::CanSchedule(KernelCore& kernel) { | 362 | bool KScheduler::CanSchedule(KernelCore& kernel) { |
| 363 | return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1; | 363 | return kernel.GetCurrentEmuThread()->GetDisableDispatchCount() <= 1; |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { | 366 | bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) { |
| @@ -376,20 +376,30 @@ void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) { | |||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | void KScheduler::DisableScheduling(KernelCore& kernel) { | 378 | void KScheduler::DisableScheduling(KernelCore& kernel) { |
| 379 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { | 379 | // If we are shutting down the kernel, none of this is relevant anymore. |
| 380 | ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0); | 380 | if (kernel.IsShuttingDown()) { |
| 381 | scheduler->GetCurrentThread()->DisableDispatch(); | 381 | return; |
| 382 | } | 382 | } |
| 383 | |||
| 384 | ASSERT(GetCurrentThreadPointer(kernel)->GetDisableDispatchCount() >= 0); | ||
| 385 | GetCurrentThreadPointer(kernel)->DisableDispatch(); | ||
| 383 | } | 386 | } |
| 384 | 387 | ||
| 385 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { | 388 | void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) { |
| 386 | if (auto* scheduler = kernel.CurrentScheduler(); scheduler) { | 389 | // If we are shutting down the kernel, none of this is relevant anymore. |
| 387 | ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1); | 390 | if (kernel.IsShuttingDown()) { |
| 388 | if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) { | 391 | return; |
| 389 | scheduler->GetCurrentThread()->EnableDispatch(); | 392 | } |
| 390 | } | 393 | |
| 394 | auto* current_thread = GetCurrentThreadPointer(kernel); | ||
| 395 | |||
| 396 | ASSERT(current_thread->GetDisableDispatchCount() >= 1); | ||
| 397 | |||
| 398 | if (current_thread->GetDisableDispatchCount() > 1) { | ||
| 399 | current_thread->EnableDispatch(); | ||
| 400 | } else { | ||
| 401 | RescheduleCores(kernel, cores_needing_scheduling); | ||
| 391 | } | 402 | } |
| 392 | RescheduleCores(kernel, cores_needing_scheduling); | ||
| 393 | } | 403 | } |
| 394 | 404 | ||
| 395 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | 405 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { |
| @@ -617,13 +627,17 @@ KScheduler::KScheduler(Core::System& system_, s32 core_id_) : system{system_}, c | |||
| 617 | state.highest_priority_thread = nullptr; | 627 | state.highest_priority_thread = nullptr; |
| 618 | } | 628 | } |
| 619 | 629 | ||
| 620 | KScheduler::~KScheduler() { | 630 | void KScheduler::Finalize() { |
| 621 | if (idle_thread) { | 631 | if (idle_thread) { |
| 622 | idle_thread->Close(); | 632 | idle_thread->Close(); |
| 623 | idle_thread = nullptr; | 633 | idle_thread = nullptr; |
| 624 | } | 634 | } |
| 625 | } | 635 | } |
| 626 | 636 | ||
| 637 | KScheduler::~KScheduler() { | ||
| 638 | ASSERT(!idle_thread); | ||
| 639 | } | ||
| 640 | |||
| 627 | KThread* KScheduler::GetCurrentThread() const { | 641 | KThread* KScheduler::GetCurrentThread() const { |
| 628 | if (auto result = current_thread.load(); result) { | 642 | if (auto result = current_thread.load(); result) { |
| 629 | return result; | 643 | return result; |
| @@ -642,10 +656,12 @@ void KScheduler::RescheduleCurrentCore() { | |||
| 642 | if (phys_core.IsInterrupted()) { | 656 | if (phys_core.IsInterrupted()) { |
| 643 | phys_core.ClearInterrupt(); | 657 | phys_core.ClearInterrupt(); |
| 644 | } | 658 | } |
| 659 | |||
| 645 | guard.Lock(); | 660 | guard.Lock(); |
| 646 | if (state.needs_scheduling.load()) { | 661 | if (state.needs_scheduling.load()) { |
| 647 | Schedule(); | 662 | Schedule(); |
| 648 | } else { | 663 | } else { |
| 664 | GetCurrentThread()->EnableDispatch(); | ||
| 649 | guard.Unlock(); | 665 | guard.Unlock(); |
| 650 | } | 666 | } |
| 651 | } | 667 | } |
| @@ -655,26 +671,33 @@ void KScheduler::OnThreadStart() { | |||
| 655 | } | 671 | } |
| 656 | 672 | ||
| 657 | void KScheduler::Unload(KThread* thread) { | 673 | void KScheduler::Unload(KThread* thread) { |
| 674 | ASSERT(thread); | ||
| 675 | |||
| 658 | LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); | 676 | LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr"); |
| 659 | 677 | ||
| 660 | if (thread) { | 678 | if (thread->IsCallingSvc()) { |
| 661 | if (thread->IsCallingSvc()) { | 679 | thread->ClearIsCallingSvc(); |
| 662 | thread->ClearIsCallingSvc(); | 680 | } |
| 663 | } | 681 | |
| 664 | if (!thread->IsTerminationRequested()) { | 682 | auto& physical_core = system.Kernel().PhysicalCore(core_id); |
| 665 | prev_thread = thread; | 683 | if (!physical_core.IsInitialized()) { |
| 666 | 684 | return; | |
| 667 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | 685 | } |
| 668 | cpu_core.SaveContext(thread->GetContext32()); | 686 | |
| 669 | cpu_core.SaveContext(thread->GetContext64()); | 687 | Core::ARM_Interface& cpu_core = physical_core.ArmInterface(); |
| 670 | // Save the TPIDR_EL0 system register in case it was modified. | 688 | cpu_core.SaveContext(thread->GetContext32()); |
| 671 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); | 689 | cpu_core.SaveContext(thread->GetContext64()); |
| 672 | cpu_core.ClearExclusiveState(); | 690 | // Save the TPIDR_EL0 system register in case it was modified. |
| 673 | } else { | 691 | thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); |
| 674 | prev_thread = nullptr; | 692 | cpu_core.ClearExclusiveState(); |
| 675 | } | 693 | |
| 676 | thread->context_guard.Unlock(); | 694 | if (!thread->IsTerminationRequested() && thread->GetActiveCore() == core_id) { |
| 695 | prev_thread = thread; | ||
| 696 | } else { | ||
| 697 | prev_thread = nullptr; | ||
| 677 | } | 698 | } |
| 699 | |||
| 700 | thread->context_guard.Unlock(); | ||
| 678 | } | 701 | } |
| 679 | 702 | ||
| 680 | void KScheduler::Reload(KThread* thread) { | 703 | void KScheduler::Reload(KThread* thread) { |
| @@ -683,11 +706,6 @@ void KScheduler::Reload(KThread* thread) { | |||
| 683 | if (thread) { | 706 | if (thread) { |
| 684 | ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); | 707 | ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable."); |
| 685 | 708 | ||
| 686 | auto* const thread_owner_process = thread->GetOwnerProcess(); | ||
| 687 | if (thread_owner_process != nullptr) { | ||
| 688 | system.Kernel().MakeCurrentProcess(thread_owner_process); | ||
| 689 | } | ||
| 690 | |||
| 691 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); | 709 | Core::ARM_Interface& cpu_core = system.ArmInterface(core_id); |
| 692 | cpu_core.LoadContext(thread->GetContext32()); | 710 | cpu_core.LoadContext(thread->GetContext32()); |
| 693 | cpu_core.LoadContext(thread->GetContext64()); | 711 | cpu_core.LoadContext(thread->GetContext64()); |
| @@ -705,7 +723,7 @@ void KScheduler::SwitchContextStep2() { | |||
| 705 | } | 723 | } |
| 706 | 724 | ||
| 707 | void KScheduler::ScheduleImpl() { | 725 | void KScheduler::ScheduleImpl() { |
| 708 | KThread* previous_thread = current_thread.load(); | 726 | KThread* previous_thread = GetCurrentThread(); |
| 709 | KThread* next_thread = state.highest_priority_thread; | 727 | KThread* next_thread = state.highest_priority_thread; |
| 710 | 728 | ||
| 711 | state.needs_scheduling = false; | 729 | state.needs_scheduling = false; |
| @@ -717,10 +735,15 @@ void KScheduler::ScheduleImpl() { | |||
| 717 | 735 | ||
| 718 | // If we're not actually switching thread, there's nothing to do. | 736 | // If we're not actually switching thread, there's nothing to do. |
| 719 | if (next_thread == current_thread.load()) { | 737 | if (next_thread == current_thread.load()) { |
| 738 | previous_thread->EnableDispatch(); | ||
| 720 | guard.Unlock(); | 739 | guard.Unlock(); |
| 721 | return; | 740 | return; |
| 722 | } | 741 | } |
| 723 | 742 | ||
| 743 | if (next_thread->GetCurrentCore() != core_id) { | ||
| 744 | next_thread->SetCurrentCore(core_id); | ||
| 745 | } | ||
| 746 | |||
| 724 | current_thread.store(next_thread); | 747 | current_thread.store(next_thread); |
| 725 | 748 | ||
| 726 | KProcess* const previous_process = system.Kernel().CurrentProcess(); | 749 | KProcess* const previous_process = system.Kernel().CurrentProcess(); |
| @@ -731,11 +754,7 @@ void KScheduler::ScheduleImpl() { | |||
| 731 | Unload(previous_thread); | 754 | Unload(previous_thread); |
| 732 | 755 | ||
| 733 | std::shared_ptr<Common::Fiber>* old_context; | 756 | std::shared_ptr<Common::Fiber>* old_context; |
| 734 | if (previous_thread != nullptr) { | 757 | old_context = &previous_thread->GetHostContext(); |
| 735 | old_context = &previous_thread->GetHostContext(); | ||
| 736 | } else { | ||
| 737 | old_context = &idle_thread->GetHostContext(); | ||
| 738 | } | ||
| 739 | guard.Unlock(); | 758 | guard.Unlock(); |
| 740 | 759 | ||
| 741 | Common::Fiber::YieldTo(*old_context, *switch_fiber); | 760 | Common::Fiber::YieldTo(*old_context, *switch_fiber); |
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 7df288438..82fcd99e7 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h | |||
| @@ -33,6 +33,8 @@ public: | |||
| 33 | explicit KScheduler(Core::System& system_, s32 core_id_); | 33 | explicit KScheduler(Core::System& system_, s32 core_id_); |
| 34 | ~KScheduler(); | 34 | ~KScheduler(); |
| 35 | 35 | ||
| 36 | void Finalize(); | ||
| 37 | |||
| 36 | /// Reschedules to the next available thread (call after current thread is suspended) | 38 | /// Reschedules to the next available thread (call after current thread is suspended) |
| 37 | void RescheduleCurrentCore(); | 39 | void RescheduleCurrentCore(); |
| 38 | 40 | ||
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index c571f2992..93c47f1b1 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h | |||
| @@ -23,6 +23,11 @@ public: | |||
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | void Lock() { | 25 | void Lock() { |
| 26 | // If we are shutting down the kernel, none of this is relevant anymore. | ||
| 27 | if (kernel.IsShuttingDown()) { | ||
| 28 | return; | ||
| 29 | } | ||
| 30 | |||
| 26 | if (IsLockedByCurrentThread()) { | 31 | if (IsLockedByCurrentThread()) { |
| 27 | // If we already own the lock, we can just increment the count. | 32 | // If we already own the lock, we can just increment the count. |
| 28 | ASSERT(lock_count > 0); | 33 | ASSERT(lock_count > 0); |
| @@ -43,6 +48,11 @@ public: | |||
| 43 | } | 48 | } |
| 44 | 49 | ||
| 45 | void Unlock() { | 50 | void Unlock() { |
| 51 | // If we are shutting down the kernel, none of this is relevant anymore. | ||
| 52 | if (kernel.IsShuttingDown()) { | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 46 | ASSERT(IsLockedByCurrentThread()); | 56 | ASSERT(IsLockedByCurrentThread()); |
| 47 | ASSERT(lock_count > 0); | 57 | ASSERT(lock_count > 0); |
| 48 | 58 | ||
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h index 61dc2858f..2995c492d 100644 --- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h +++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #pragma once | 8 | #pragma once |
| 9 | 9 | ||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/kernel/global_scheduler_context.h" | ||
| 11 | #include "core/hle/kernel/k_thread.h" | 12 | #include "core/hle/kernel/k_thread.h" |
| 12 | #include "core/hle/kernel/kernel.h" | 13 | #include "core/hle/kernel/kernel.h" |
| 13 | #include "core/hle/kernel/time_manager.h" | 14 | #include "core/hle/kernel/time_manager.h" |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 2bd53ccbd..d4e4a6b06 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -175,8 +175,7 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 175 | { | 175 | { |
| 176 | KScopedSchedulerLock lock(kernel); | 176 | KScopedSchedulerLock lock(kernel); |
| 177 | if (!context.IsThreadWaiting()) { | 177 | if (!context.IsThreadWaiting()) { |
| 178 | context.GetThread().Wakeup(); | 178 | context.GetThread().EndWait(result); |
| 179 | context.GetThread().SetSyncedObject(nullptr, result); | ||
| 180 | } | 179 | } |
| 181 | } | 180 | } |
| 182 | 181 | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index f168b4f21..e4c5eb74f 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -8,11 +8,66 @@ | |||
| 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 8 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 9 | #include "core/hle/kernel/k_synchronization_object.h" | 9 | #include "core/hle/kernel/k_synchronization_object.h" |
| 10 | #include "core/hle/kernel/k_thread.h" | 10 | #include "core/hle/kernel/k_thread.h" |
| 11 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 12 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/svc_results.h" | 13 | #include "core/hle/kernel/svc_results.h" |
| 13 | 14 | ||
| 14 | namespace Kernel { | 15 | namespace Kernel { |
| 15 | 16 | ||
| 17 | namespace { | ||
| 18 | |||
| 19 | class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait { | ||
| 20 | public: | ||
| 21 | ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o, | ||
| 22 | KSynchronizationObject::ThreadListNode* n, s32 c) | ||
| 23 | : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {} | ||
| 24 | |||
| 25 | void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, | ||
| 26 | ResultCode wait_result) override { | ||
| 27 | // Determine the sync index, and unlink all nodes. | ||
| 28 | s32 sync_index = -1; | ||
| 29 | for (auto i = 0; i < m_count; ++i) { | ||
| 30 | // Check if this is the signaled object. | ||
| 31 | if (m_objects[i] == signaled_object && sync_index == -1) { | ||
| 32 | sync_index = i; | ||
| 33 | } | ||
| 34 | |||
| 35 | // Unlink the current node from the current object. | ||
| 36 | m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); | ||
| 37 | } | ||
| 38 | |||
| 39 | // Set the waiting thread's sync index. | ||
| 40 | waiting_thread->SetSyncedIndex(sync_index); | ||
| 41 | |||
| 42 | // Set the waiting thread as not cancellable. | ||
| 43 | waiting_thread->ClearCancellable(); | ||
| 44 | |||
| 45 | // Invoke the base end wait handler. | ||
| 46 | KThreadQueue::EndWait(waiting_thread, wait_result); | ||
| 47 | } | ||
| 48 | |||
| 49 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 50 | bool cancel_timer_task) override { | ||
| 51 | // Remove all nodes from our list. | ||
| 52 | for (auto i = 0; i < m_count; ++i) { | ||
| 53 | m_objects[i]->UnlinkNode(std::addressof(m_nodes[i])); | ||
| 54 | } | ||
| 55 | |||
| 56 | // Set the waiting thread as not cancellable. | ||
| 57 | waiting_thread->ClearCancellable(); | ||
| 58 | |||
| 59 | // Invoke the base cancel wait handler. | ||
| 60 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 61 | } | ||
| 62 | |||
| 63 | private: | ||
| 64 | KSynchronizationObject** m_objects; | ||
| 65 | KSynchronizationObject::ThreadListNode* m_nodes; | ||
| 66 | s32 m_count; | ||
| 67 | }; | ||
| 68 | |||
| 69 | } // namespace | ||
| 70 | |||
| 16 | void KSynchronizationObject::Finalize() { | 71 | void KSynchronizationObject::Finalize() { |
| 17 | this->OnFinalizeSynchronizationObject(); | 72 | this->OnFinalizeSynchronizationObject(); |
| 18 | KAutoObject::Finalize(); | 73 | KAutoObject::Finalize(); |
| @@ -25,11 +80,19 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 25 | std::vector<ThreadListNode> thread_nodes(num_objects); | 80 | std::vector<ThreadListNode> thread_nodes(num_objects); |
| 26 | 81 | ||
| 27 | // Prepare for wait. | 82 | // Prepare for wait. |
| 28 | KThread* thread = kernel_ctx.CurrentScheduler()->GetCurrentThread(); | 83 | KThread* thread = GetCurrentThreadPointer(kernel_ctx); |
| 84 | ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects, | ||
| 85 | thread_nodes.data(), num_objects); | ||
| 29 | 86 | ||
| 30 | { | 87 | { |
| 31 | // Setup the scheduling lock and sleep. | 88 | // Setup the scheduling lock and sleep. |
| 32 | KScopedSchedulerLockAndSleep slp{kernel_ctx, thread, timeout}; | 89 | KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout); |
| 90 | |||
| 91 | // Check if the thread should terminate. | ||
| 92 | if (thread->IsTerminationRequested()) { | ||
| 93 | slp.CancelSleep(); | ||
| 94 | return ResultTerminationRequested; | ||
| 95 | } | ||
| 33 | 96 | ||
| 34 | // Check if any of the objects are already signaled. | 97 | // Check if any of the objects are already signaled. |
| 35 | for (auto i = 0; i < num_objects; ++i) { | 98 | for (auto i = 0; i < num_objects; ++i) { |
| @@ -48,12 +111,6 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 48 | return ResultTimedOut; | 111 | return ResultTimedOut; |
| 49 | } | 112 | } |
| 50 | 113 | ||
| 51 | // Check if the thread should terminate. | ||
| 52 | if (thread->IsTerminationRequested()) { | ||
| 53 | slp.CancelSleep(); | ||
| 54 | return ResultTerminationRequested; | ||
| 55 | } | ||
| 56 | |||
| 57 | // Check if waiting was canceled. | 114 | // Check if waiting was canceled. |
| 58 | if (thread->IsWaitCancelled()) { | 115 | if (thread->IsWaitCancelled()) { |
| 59 | slp.CancelSleep(); | 116 | slp.CancelSleep(); |
| @@ -66,73 +123,25 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index, | |||
| 66 | thread_nodes[i].thread = thread; | 123 | thread_nodes[i].thread = thread; |
| 67 | thread_nodes[i].next = nullptr; | 124 | thread_nodes[i].next = nullptr; |
| 68 | 125 | ||
| 69 | if (objects[i]->thread_list_tail == nullptr) { | 126 | objects[i]->LinkNode(std::addressof(thread_nodes[i])); |
| 70 | objects[i]->thread_list_head = std::addressof(thread_nodes[i]); | ||
| 71 | } else { | ||
| 72 | objects[i]->thread_list_tail->next = std::addressof(thread_nodes[i]); | ||
| 73 | } | ||
| 74 | |||
| 75 | objects[i]->thread_list_tail = std::addressof(thread_nodes[i]); | ||
| 76 | } | 127 | } |
| 77 | 128 | ||
| 78 | // For debugging only | 129 | // Mark the thread as cancellable. |
| 79 | thread->SetWaitObjectsForDebugging({objects, static_cast<std::size_t>(num_objects)}); | ||
| 80 | |||
| 81 | // Mark the thread as waiting. | ||
| 82 | thread->SetCancellable(); | 130 | thread->SetCancellable(); |
| 83 | thread->SetSyncedObject(nullptr, ResultTimedOut); | ||
| 84 | thread->SetState(ThreadState::Waiting); | ||
| 85 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); | ||
| 86 | } | ||
| 87 | 131 | ||
| 88 | // The lock/sleep is done, so we should be able to get our result. | 132 | // Clear the thread's synced index. |
| 133 | thread->SetSyncedIndex(-1); | ||
| 89 | 134 | ||
| 90 | // Thread is no longer cancellable. | 135 | // Wait for an object to be signaled. |
| 91 | thread->ClearCancellable(); | 136 | thread->BeginWait(std::addressof(wait_queue)); |
| 92 | 137 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); | |
| 93 | // For debugging only | 138 | } |
| 94 | thread->SetWaitObjectsForDebugging({}); | ||
| 95 | 139 | ||
| 96 | // Cancel the timer as needed. | 140 | // Set the output index. |
| 97 | kernel_ctx.TimeManager().UnscheduleTimeEvent(thread); | 141 | *out_index = thread->GetSyncedIndex(); |
| 98 | 142 | ||
| 99 | // Get the wait result. | 143 | // Get the wait result. |
| 100 | ResultCode wait_result{ResultSuccess}; | 144 | return thread->GetWaitResult(); |
| 101 | s32 sync_index = -1; | ||
| 102 | { | ||
| 103 | KScopedSchedulerLock lock(kernel_ctx); | ||
| 104 | KSynchronizationObject* synced_obj; | ||
| 105 | wait_result = thread->GetWaitResult(std::addressof(synced_obj)); | ||
| 106 | |||
| 107 | for (auto i = 0; i < num_objects; ++i) { | ||
| 108 | // Unlink the object from the list. | ||
| 109 | ThreadListNode* prev_ptr = | ||
| 110 | reinterpret_cast<ThreadListNode*>(std::addressof(objects[i]->thread_list_head)); | ||
| 111 | ThreadListNode* prev_val = nullptr; | ||
| 112 | ThreadListNode *prev, *tail_prev; | ||
| 113 | |||
| 114 | do { | ||
| 115 | prev = prev_ptr; | ||
| 116 | prev_ptr = prev_ptr->next; | ||
| 117 | tail_prev = prev_val; | ||
| 118 | prev_val = prev_ptr; | ||
| 119 | } while (prev_ptr != std::addressof(thread_nodes[i])); | ||
| 120 | |||
| 121 | if (objects[i]->thread_list_tail == std::addressof(thread_nodes[i])) { | ||
| 122 | objects[i]->thread_list_tail = tail_prev; | ||
| 123 | } | ||
| 124 | |||
| 125 | prev->next = thread_nodes[i].next; | ||
| 126 | |||
| 127 | if (objects[i] == synced_obj) { | ||
| 128 | sync_index = i; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | // Set output. | ||
| 134 | *out_index = sync_index; | ||
| 135 | return wait_result; | ||
| 136 | } | 145 | } |
| 137 | 146 | ||
| 138 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | 147 | KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) |
| @@ -141,7 +150,7 @@ KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_) | |||
| 141 | KSynchronizationObject::~KSynchronizationObject() = default; | 150 | KSynchronizationObject::~KSynchronizationObject() = default; |
| 142 | 151 | ||
| 143 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { | 152 | void KSynchronizationObject::NotifyAvailable(ResultCode result) { |
| 144 | KScopedSchedulerLock lock(kernel); | 153 | KScopedSchedulerLock sl(kernel); |
| 145 | 154 | ||
| 146 | // If we're not signaled, we've nothing to notify. | 155 | // If we're not signaled, we've nothing to notify. |
| 147 | if (!this->IsSignaled()) { | 156 | if (!this->IsSignaled()) { |
| @@ -150,11 +159,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) { | |||
| 150 | 159 | ||
| 151 | // Iterate over each thread. | 160 | // Iterate over each thread. |
| 152 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { | 161 | for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) { |
| 153 | KThread* thread = cur_node->thread; | 162 | cur_node->thread->NotifyAvailable(this, result); |
| 154 | if (thread->GetState() == ThreadState::Waiting) { | ||
| 155 | thread->SetSyncedObject(this, result); | ||
| 156 | thread->SetState(ThreadState::Runnable); | ||
| 157 | } | ||
| 158 | } | 163 | } |
| 159 | } | 164 | } |
| 160 | 165 | ||
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h index 898e58e16..ec235437b 100644 --- a/src/core/hle/kernel/k_synchronization_object.h +++ b/src/core/hle/kernel/k_synchronization_object.h | |||
| @@ -35,6 +35,38 @@ public: | |||
| 35 | 35 | ||
| 36 | [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; | 36 | [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const; |
| 37 | 37 | ||
| 38 | void LinkNode(ThreadListNode* node_) { | ||
| 39 | // Link the node to the list. | ||
| 40 | if (thread_list_tail == nullptr) { | ||
| 41 | thread_list_head = node_; | ||
| 42 | } else { | ||
| 43 | thread_list_tail->next = node_; | ||
| 44 | } | ||
| 45 | |||
| 46 | thread_list_tail = node_; | ||
| 47 | } | ||
| 48 | |||
| 49 | void UnlinkNode(ThreadListNode* node_) { | ||
| 50 | // Unlink the node from the list. | ||
| 51 | ThreadListNode* prev_ptr = | ||
| 52 | reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head)); | ||
| 53 | ThreadListNode* prev_val = nullptr; | ||
| 54 | ThreadListNode *prev, *tail_prev; | ||
| 55 | |||
| 56 | do { | ||
| 57 | prev = prev_ptr; | ||
| 58 | prev_ptr = prev_ptr->next; | ||
| 59 | tail_prev = prev_val; | ||
| 60 | prev_val = prev_ptr; | ||
| 61 | } while (prev_ptr != node_); | ||
| 62 | |||
| 63 | if (thread_list_tail == node_) { | ||
| 64 | thread_list_tail = tail_prev; | ||
| 65 | } | ||
| 66 | |||
| 67 | prev->next = node_->next; | ||
| 68 | } | ||
| 69 | |||
| 38 | protected: | 70 | protected: |
| 39 | explicit KSynchronizationObject(KernelCore& kernel); | 71 | explicit KSynchronizationObject(KernelCore& kernel); |
| 40 | ~KSynchronizationObject() override; | 72 | ~KSynchronizationObject() override; |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index db65ce79a..752592e2e 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -13,6 +13,9 @@ | |||
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/fiber.h" | 14 | #include "common/fiber.h" |
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/scope_exit.h" | ||
| 17 | #include "common/settings.h" | ||
| 18 | #include "common/thread_queue_list.h" | ||
| 16 | #include "core/core.h" | 19 | #include "core/core.h" |
| 17 | #include "core/cpu_manager.h" | 20 | #include "core/cpu_manager.h" |
| 18 | #include "core/hardware_properties.h" | 21 | #include "core/hardware_properties.h" |
| @@ -56,6 +59,34 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, | |||
| 56 | 59 | ||
| 57 | namespace Kernel { | 60 | namespace Kernel { |
| 58 | 61 | ||
| 62 | namespace { | ||
| 63 | |||
| 64 | class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { | ||
| 65 | public: | ||
| 66 | explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) | ||
| 67 | : KThreadQueueWithoutEndWait(kernel_) {} | ||
| 68 | }; | ||
| 69 | |||
| 70 | class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { | ||
| 71 | public: | ||
| 72 | explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) | ||
| 73 | : KThreadQueue(kernel_), m_wait_list(wl) {} | ||
| 74 | |||
| 75 | void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 76 | bool cancel_timer_task) override { | ||
| 77 | // Remove the thread from the wait list. | ||
| 78 | m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); | ||
| 79 | |||
| 80 | // Invoke the base cancel wait handler. | ||
| 81 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 82 | } | ||
| 83 | |||
| 84 | private: | ||
| 85 | KThread::WaiterList* m_wait_list; | ||
| 86 | }; | ||
| 87 | |||
| 88 | } // namespace | ||
| 89 | |||
| 59 | KThread::KThread(KernelCore& kernel_) | 90 | KThread::KThread(KernelCore& kernel_) |
| 60 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} | 91 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} |
| 61 | KThread::~KThread() = default; | 92 | KThread::~KThread() = default; |
| @@ -82,6 +113,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 82 | [[fallthrough]]; | 113 | [[fallthrough]]; |
| 83 | case ThreadType::HighPriority: | 114 | case ThreadType::HighPriority: |
| 84 | [[fallthrough]]; | 115 | [[fallthrough]]; |
| 116 | case ThreadType::Dummy: | ||
| 117 | [[fallthrough]]; | ||
| 85 | case ThreadType::User: | 118 | case ThreadType::User: |
| 86 | ASSERT(((owner == nullptr) || | 119 | ASSERT(((owner == nullptr) || |
| 87 | (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); | 120 | (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); |
| @@ -127,11 +160,8 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 127 | priority = prio; | 160 | priority = prio; |
| 128 | base_priority = prio; | 161 | base_priority = prio; |
| 129 | 162 | ||
| 130 | // Set sync object and waiting lock to null. | ||
| 131 | synced_object = nullptr; | ||
| 132 | |||
| 133 | // Initialize sleeping queue. | 163 | // Initialize sleeping queue. |
| 134 | sleeping_queue = nullptr; | 164 | wait_queue = nullptr; |
| 135 | 165 | ||
| 136 | // Set suspend flags. | 166 | // Set suspend flags. |
| 137 | suspend_request_flags = 0; | 167 | suspend_request_flags = 0; |
| @@ -184,7 +214,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 184 | // Setup the stack parameters. | 214 | // Setup the stack parameters. |
| 185 | StackParameters& sp = GetStackParameters(); | 215 | StackParameters& sp = GetStackParameters(); |
| 186 | sp.cur_thread = this; | 216 | sp.cur_thread = this; |
| 187 | sp.disable_count = 1; | 217 | sp.disable_count = 0; |
| 188 | SetInExceptionHandler(); | 218 | SetInExceptionHandler(); |
| 189 | 219 | ||
| 190 | // Set thread ID. | 220 | // Set thread ID. |
| @@ -211,15 +241,16 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint | |||
| 211 | // Initialize the thread. | 241 | // Initialize the thread. |
| 212 | R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); | 242 | R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type)); |
| 213 | 243 | ||
| 214 | // Initialize host context. | 244 | // Initialize emulation parameters. |
| 215 | thread->host_context = | 245 | thread->host_context = |
| 216 | std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter); | 246 | std::make_shared<Common::Fiber>(std::move(init_func), init_func_parameter); |
| 247 | thread->is_single_core = !Settings::values.use_multi_core.GetValue(); | ||
| 217 | 248 | ||
| 218 | return ResultSuccess; | 249 | return ResultSuccess; |
| 219 | } | 250 | } |
| 220 | 251 | ||
| 221 | ResultCode KThread::InitializeDummyThread(KThread* thread) { | 252 | ResultCode KThread::InitializeDummyThread(KThread* thread) { |
| 222 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Main); | 253 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); |
| 223 | } | 254 | } |
| 224 | 255 | ||
| 225 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 256 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { |
| @@ -273,11 +304,14 @@ void KThread::Finalize() { | |||
| 273 | 304 | ||
| 274 | auto it = waiter_list.begin(); | 305 | auto it = waiter_list.begin(); |
| 275 | while (it != waiter_list.end()) { | 306 | while (it != waiter_list.end()) { |
| 276 | // The thread shouldn't be a kernel waiter. | 307 | // Clear the lock owner |
| 277 | it->SetLockOwner(nullptr); | 308 | it->SetLockOwner(nullptr); |
| 278 | it->SetSyncedObject(nullptr, ResultInvalidState); | 309 | |
| 279 | it->Wakeup(); | 310 | // Erase the waiter from our list. |
| 280 | it = waiter_list.erase(it); | 311 | it = waiter_list.erase(it); |
| 312 | |||
| 313 | // Cancel the thread's wait. | ||
| 314 | it->CancelWait(ResultInvalidState, true); | ||
| 281 | } | 315 | } |
| 282 | } | 316 | } |
| 283 | 317 | ||
| @@ -294,15 +328,12 @@ bool KThread::IsSignaled() const { | |||
| 294 | return signaled; | 328 | return signaled; |
| 295 | } | 329 | } |
| 296 | 330 | ||
| 297 | void KThread::Wakeup() { | 331 | void KThread::OnTimer() { |
| 298 | KScopedSchedulerLock sl{kernel}; | 332 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 299 | 333 | ||
| 334 | // If we're waiting, cancel the wait. | ||
| 300 | if (GetState() == ThreadState::Waiting) { | 335 | if (GetState() == ThreadState::Waiting) { |
| 301 | if (sleeping_queue != nullptr) { | 336 | wait_queue->CancelWait(this, ResultTimedOut, false); |
| 302 | sleeping_queue->WakeupThread(this); | ||
| 303 | } else { | ||
| 304 | SetState(ThreadState::Runnable); | ||
| 305 | } | ||
| 306 | } | 337 | } |
| 307 | } | 338 | } |
| 308 | 339 | ||
| @@ -327,7 +358,7 @@ void KThread::StartTermination() { | |||
| 327 | 358 | ||
| 328 | // Signal. | 359 | // Signal. |
| 329 | signaled = true; | 360 | signaled = true; |
| 330 | NotifyAvailable(); | 361 | KSynchronizationObject::NotifyAvailable(); |
| 331 | 362 | ||
| 332 | // Clear previous thread in KScheduler. | 363 | // Clear previous thread in KScheduler. |
| 333 | KScheduler::ClearPreviousThread(kernel, this); | 364 | KScheduler::ClearPreviousThread(kernel, this); |
| @@ -475,30 +506,32 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m | |||
| 475 | return ResultSuccess; | 506 | return ResultSuccess; |
| 476 | } | 507 | } |
| 477 | 508 | ||
| 478 | ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | 509 | ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) { |
| 479 | ASSERT(parent != nullptr); | 510 | ASSERT(parent != nullptr); |
| 480 | ASSERT(v_affinity_mask != 0); | 511 | ASSERT(v_affinity_mask != 0); |
| 481 | KScopedLightLock lk{activity_pause_lock}; | 512 | KScopedLightLock lk(activity_pause_lock); |
| 482 | 513 | ||
| 483 | // Set the core mask. | 514 | // Set the core mask. |
| 484 | u64 p_affinity_mask = 0; | 515 | u64 p_affinity_mask = 0; |
| 485 | { | 516 | { |
| 486 | KScopedSchedulerLock sl{kernel}; | 517 | KScopedSchedulerLock sl(kernel); |
| 487 | ASSERT(num_core_migration_disables >= 0); | 518 | ASSERT(num_core_migration_disables >= 0); |
| 488 | 519 | ||
| 489 | // If the core id is no-update magic, preserve the ideal core id. | 520 | // If we're updating, set our ideal virtual core. |
| 490 | if (cpu_core_id == Svc::IdealCoreNoUpdate) { | 521 | if (core_id_ != Svc::IdealCoreNoUpdate) { |
| 491 | cpu_core_id = virtual_ideal_core_id; | 522 | virtual_ideal_core_id = core_id_; |
| 492 | R_UNLESS(((1ULL << cpu_core_id) & v_affinity_mask) != 0, ResultInvalidCombination); | 523 | } else { |
| 524 | // Preserve our ideal core id. | ||
| 525 | core_id_ = virtual_ideal_core_id; | ||
| 526 | R_UNLESS(((1ULL << core_id_) & v_affinity_mask) != 0, ResultInvalidCombination); | ||
| 493 | } | 527 | } |
| 494 | 528 | ||
| 495 | // Set the virtual core/affinity mask. | 529 | // Set our affinity mask. |
| 496 | virtual_ideal_core_id = cpu_core_id; | ||
| 497 | virtual_affinity_mask = v_affinity_mask; | 530 | virtual_affinity_mask = v_affinity_mask; |
| 498 | 531 | ||
| 499 | // Translate the virtual core to a physical core. | 532 | // Translate the virtual core to a physical core. |
| 500 | if (cpu_core_id >= 0) { | 533 | if (core_id_ >= 0) { |
| 501 | cpu_core_id = Core::Hardware::VirtualToPhysicalCoreMap[cpu_core_id]; | 534 | core_id_ = Core::Hardware::VirtualToPhysicalCoreMap[core_id_]; |
| 502 | } | 535 | } |
| 503 | 536 | ||
| 504 | // Translate the virtual affinity mask to a physical one. | 537 | // Translate the virtual affinity mask to a physical one. |
| @@ -513,7 +546,7 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | |||
| 513 | const KAffinityMask old_mask = physical_affinity_mask; | 546 | const KAffinityMask old_mask = physical_affinity_mask; |
| 514 | 547 | ||
| 515 | // Set our new ideals. | 548 | // Set our new ideals. |
| 516 | physical_ideal_core_id = cpu_core_id; | 549 | physical_ideal_core_id = core_id_; |
| 517 | physical_affinity_mask.SetAffinityMask(p_affinity_mask); | 550 | physical_affinity_mask.SetAffinityMask(p_affinity_mask); |
| 518 | 551 | ||
| 519 | if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { | 552 | if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { |
| @@ -531,18 +564,18 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | |||
| 531 | } | 564 | } |
| 532 | } else { | 565 | } else { |
| 533 | // Otherwise, we edit the original affinity for restoration later. | 566 | // Otherwise, we edit the original affinity for restoration later. |
| 534 | original_physical_ideal_core_id = cpu_core_id; | 567 | original_physical_ideal_core_id = core_id_; |
| 535 | original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); | 568 | original_physical_affinity_mask.SetAffinityMask(p_affinity_mask); |
| 536 | } | 569 | } |
| 537 | } | 570 | } |
| 538 | 571 | ||
| 539 | // Update the pinned waiter list. | 572 | // Update the pinned waiter list. |
| 573 | ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, std::addressof(pinned_waiter_list)); | ||
| 540 | { | 574 | { |
| 541 | bool retry_update{}; | 575 | bool retry_update{}; |
| 542 | bool thread_is_pinned{}; | ||
| 543 | do { | 576 | do { |
| 544 | // Lock the scheduler. | 577 | // Lock the scheduler. |
| 545 | KScopedSchedulerLock sl{kernel}; | 578 | KScopedSchedulerLock sl(kernel); |
| 546 | 579 | ||
| 547 | // Don't do any further management if our termination has been requested. | 580 | // Don't do any further management if our termination has been requested. |
| 548 | R_SUCCEED_IF(IsTerminationRequested()); | 581 | R_SUCCEED_IF(IsTerminationRequested()); |
| @@ -570,12 +603,9 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | |||
| 570 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | 603 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), |
| 571 | ResultTerminationRequested); | 604 | ResultTerminationRequested); |
| 572 | 605 | ||
| 573 | // Note that the thread was pinned. | ||
| 574 | thread_is_pinned = true; | ||
| 575 | |||
| 576 | // Wait until the thread isn't pinned any more. | 606 | // Wait until the thread isn't pinned any more. |
| 577 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); | 607 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); |
| 578 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | 608 | GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_)); |
| 579 | } else { | 609 | } else { |
| 580 | // If the thread isn't pinned, release the scheduler lock and retry until it's | 610 | // If the thread isn't pinned, release the scheduler lock and retry until it's |
| 581 | // not current. | 611 | // not current. |
| @@ -583,16 +613,6 @@ ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | |||
| 583 | } | 613 | } |
| 584 | } | 614 | } |
| 585 | } while (retry_update); | 615 | } while (retry_update); |
| 586 | |||
| 587 | // If the thread was pinned, it no longer is, and we should remove the current thread from | ||
| 588 | // our waiter list. | ||
| 589 | if (thread_is_pinned) { | ||
| 590 | // Lock the scheduler. | ||
| 591 | KScopedSchedulerLock sl{kernel}; | ||
| 592 | |||
| 593 | // Remove from the list. | ||
| 594 | pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); | ||
| 595 | } | ||
| 596 | } | 616 | } |
| 597 | 617 | ||
| 598 | return ResultSuccess; | 618 | return ResultSuccess; |
| @@ -641,15 +661,9 @@ void KThread::WaitCancel() { | |||
| 641 | KScopedSchedulerLock sl{kernel}; | 661 | KScopedSchedulerLock sl{kernel}; |
| 642 | 662 | ||
| 643 | // Check if we're waiting and cancellable. | 663 | // Check if we're waiting and cancellable. |
| 644 | if (GetState() == ThreadState::Waiting && cancellable) { | 664 | if (this->GetState() == ThreadState::Waiting && cancellable) { |
| 645 | if (sleeping_queue != nullptr) { | 665 | wait_cancelled = false; |
| 646 | sleeping_queue->WakeupThread(this); | 666 | wait_queue->CancelWait(this, ResultCancelled, true); |
| 647 | wait_cancelled = true; | ||
| 648 | } else { | ||
| 649 | SetSyncedObject(nullptr, ResultCancelled); | ||
| 650 | SetState(ThreadState::Runnable); | ||
| 651 | wait_cancelled = false; | ||
| 652 | } | ||
| 653 | } else { | 667 | } else { |
| 654 | // Otherwise, note that we cancelled a wait. | 668 | // Otherwise, note that we cancelled a wait. |
| 655 | wait_cancelled = true; | 669 | wait_cancelled = true; |
| @@ -700,60 +714,59 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { | |||
| 700 | // Set the activity. | 714 | // Set the activity. |
| 701 | { | 715 | { |
| 702 | // Lock the scheduler. | 716 | // Lock the scheduler. |
| 703 | KScopedSchedulerLock sl{kernel}; | 717 | KScopedSchedulerLock sl(kernel); |
| 704 | 718 | ||
| 705 | // Verify our state. | 719 | // Verify our state. |
| 706 | const auto cur_state = GetState(); | 720 | const auto cur_state = this->GetState(); |
| 707 | R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), | 721 | R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), |
| 708 | ResultInvalidState); | 722 | ResultInvalidState); |
| 709 | 723 | ||
| 710 | // Either pause or resume. | 724 | // Either pause or resume. |
| 711 | if (activity == Svc::ThreadActivity::Paused) { | 725 | if (activity == Svc::ThreadActivity::Paused) { |
| 712 | // Verify that we're not suspended. | 726 | // Verify that we're not suspended. |
| 713 | R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState); | 727 | R_UNLESS(!this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); |
| 714 | 728 | ||
| 715 | // Suspend. | 729 | // Suspend. |
| 716 | RequestSuspend(SuspendType::Thread); | 730 | this->RequestSuspend(SuspendType::Thread); |
| 717 | } else { | 731 | } else { |
| 718 | ASSERT(activity == Svc::ThreadActivity::Runnable); | 732 | ASSERT(activity == Svc::ThreadActivity::Runnable); |
| 719 | 733 | ||
| 720 | // Verify that we're suspended. | 734 | // Verify that we're suspended. |
| 721 | R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState); | 735 | R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); |
| 722 | 736 | ||
| 723 | // Resume. | 737 | // Resume. |
| 724 | Resume(SuspendType::Thread); | 738 | this->Resume(SuspendType::Thread); |
| 725 | } | 739 | } |
| 726 | } | 740 | } |
| 727 | 741 | ||
| 728 | // If the thread is now paused, update the pinned waiter list. | 742 | // If the thread is now paused, update the pinned waiter list. |
| 729 | if (activity == Svc::ThreadActivity::Paused) { | 743 | if (activity == Svc::ThreadActivity::Paused) { |
| 730 | bool thread_is_pinned{}; | 744 | ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, |
| 731 | bool thread_is_current{}; | 745 | std::addressof(pinned_waiter_list)); |
| 746 | |||
| 747 | bool thread_is_current; | ||
| 732 | do { | 748 | do { |
| 733 | // Lock the scheduler. | 749 | // Lock the scheduler. |
| 734 | KScopedSchedulerLock sl{kernel}; | 750 | KScopedSchedulerLock sl(kernel); |
| 735 | 751 | ||
| 736 | // Don't do any further management if our termination has been requested. | 752 | // Don't do any further management if our termination has been requested. |
| 737 | R_SUCCEED_IF(IsTerminationRequested()); | 753 | R_SUCCEED_IF(this->IsTerminationRequested()); |
| 754 | |||
| 755 | // By default, treat the thread as not current. | ||
| 756 | thread_is_current = false; | ||
| 738 | 757 | ||
| 739 | // Check whether the thread is pinned. | 758 | // Check whether the thread is pinned. |
| 740 | if (GetStackParameters().is_pinned) { | 759 | if (this->GetStackParameters().is_pinned) { |
| 741 | // Verify that the current thread isn't terminating. | 760 | // Verify that the current thread isn't terminating. |
| 742 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | 761 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), |
| 743 | ResultTerminationRequested); | 762 | ResultTerminationRequested); |
| 744 | 763 | ||
| 745 | // Note that the thread was pinned and not current. | ||
| 746 | thread_is_pinned = true; | ||
| 747 | thread_is_current = false; | ||
| 748 | |||
| 749 | // Wait until the thread isn't pinned any more. | 764 | // Wait until the thread isn't pinned any more. |
| 750 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); | 765 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); |
| 751 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | 766 | GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_)); |
| 752 | } else { | 767 | } else { |
| 753 | // Check if the thread is currently running. | 768 | // Check if the thread is currently running. |
| 754 | // If it is, we'll need to retry. | 769 | // If it is, we'll need to retry. |
| 755 | thread_is_current = false; | ||
| 756 | |||
| 757 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | 770 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
| 758 | if (kernel.Scheduler(i).GetCurrentThread() == this) { | 771 | if (kernel.Scheduler(i).GetCurrentThread() == this) { |
| 759 | thread_is_current = true; | 772 | thread_is_current = true; |
| @@ -762,16 +775,6 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { | |||
| 762 | } | 775 | } |
| 763 | } | 776 | } |
| 764 | } while (thread_is_current); | 777 | } while (thread_is_current); |
| 765 | |||
| 766 | // If the thread was pinned, it no longer is, and we should remove the current thread from | ||
| 767 | // our waiter list. | ||
| 768 | if (thread_is_pinned) { | ||
| 769 | // Lock the scheduler. | ||
| 770 | KScopedSchedulerLock sl{kernel}; | ||
| 771 | |||
| 772 | // Remove from the list. | ||
| 773 | pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); | ||
| 774 | } | ||
| 775 | } | 778 | } |
| 776 | 779 | ||
| 777 | return ResultSuccess; | 780 | return ResultSuccess; |
| @@ -966,6 +969,9 @@ ResultCode KThread::Run() { | |||
| 966 | 969 | ||
| 967 | // Set our state and finish. | 970 | // Set our state and finish. |
| 968 | SetState(ThreadState::Runnable); | 971 | SetState(ThreadState::Runnable); |
| 972 | |||
| 973 | DisableDispatch(); | ||
| 974 | |||
| 969 | return ResultSuccess; | 975 | return ResultSuccess; |
| 970 | } | 976 | } |
| 971 | } | 977 | } |
| @@ -996,27 +1002,61 @@ ResultCode KThread::Sleep(s64 timeout) { | |||
| 996 | ASSERT(this == GetCurrentThreadPointer(kernel)); | 1002 | ASSERT(this == GetCurrentThreadPointer(kernel)); |
| 997 | ASSERT(timeout > 0); | 1003 | ASSERT(timeout > 0); |
| 998 | 1004 | ||
| 1005 | ThreadQueueImplForKThreadSleep wait_queue_(kernel); | ||
| 999 | { | 1006 | { |
| 1000 | // Setup the scheduling lock and sleep. | 1007 | // Setup the scheduling lock and sleep. |
| 1001 | KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; | 1008 | KScopedSchedulerLockAndSleep slp(kernel, this, timeout); |
| 1002 | 1009 | ||
| 1003 | // Check if the thread should terminate. | 1010 | // Check if the thread should terminate. |
| 1004 | if (IsTerminationRequested()) { | 1011 | if (this->IsTerminationRequested()) { |
| 1005 | slp.CancelSleep(); | 1012 | slp.CancelSleep(); |
| 1006 | return ResultTerminationRequested; | 1013 | return ResultTerminationRequested; |
| 1007 | } | 1014 | } |
| 1008 | 1015 | ||
| 1009 | // Mark the thread as waiting. | 1016 | // Wait for the sleep to end. |
| 1010 | SetState(ThreadState::Waiting); | 1017 | this->BeginWait(std::addressof(wait_queue_)); |
| 1011 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); | 1018 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); |
| 1012 | } | 1019 | } |
| 1013 | 1020 | ||
| 1014 | // The lock/sleep is done. | 1021 | return ResultSuccess; |
| 1022 | } | ||
| 1015 | 1023 | ||
| 1016 | // Cancel the timer. | 1024 | void KThread::BeginWait(KThreadQueue* queue) { |
| 1017 | kernel.TimeManager().UnscheduleTimeEvent(this); | 1025 | // Set our state as waiting. |
| 1026 | SetState(ThreadState::Waiting); | ||
| 1018 | 1027 | ||
| 1019 | return ResultSuccess; | 1028 | // Set our wait queue. |
| 1029 | wait_queue = queue; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { | ||
| 1033 | // Lock the scheduler. | ||
| 1034 | KScopedSchedulerLock sl(kernel); | ||
| 1035 | |||
| 1036 | // If we're waiting, notify our queue that we're available. | ||
| 1037 | if (GetState() == ThreadState::Waiting) { | ||
| 1038 | wait_queue->NotifyAvailable(this, signaled_object, wait_result_); | ||
| 1039 | } | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | void KThread::EndWait(ResultCode wait_result_) { | ||
| 1043 | // Lock the scheduler. | ||
| 1044 | KScopedSchedulerLock sl(kernel); | ||
| 1045 | |||
| 1046 | // If we're waiting, notify our queue that we're available. | ||
| 1047 | if (GetState() == ThreadState::Waiting) { | ||
| 1048 | wait_queue->EndWait(this, wait_result_); | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | void KThread::CancelWait(ResultCode wait_result_, bool cancel_timer_task) { | ||
| 1053 | // Lock the scheduler. | ||
| 1054 | KScopedSchedulerLock sl(kernel); | ||
| 1055 | |||
| 1056 | // If we're waiting, notify our queue that we're available. | ||
| 1057 | if (GetState() == ThreadState::Waiting) { | ||
| 1058 | wait_queue->CancelWait(this, wait_result_, cancel_timer_task); | ||
| 1059 | } | ||
| 1020 | } | 1060 | } |
| 1021 | 1061 | ||
| 1022 | void KThread::SetState(ThreadState state) { | 1062 | void KThread::SetState(ThreadState state) { |
| @@ -1050,4 +1090,26 @@ s32 GetCurrentCoreId(KernelCore& kernel) { | |||
| 1050 | return GetCurrentThread(kernel).GetCurrentCore(); | 1090 | return GetCurrentThread(kernel).GetCurrentCore(); |
| 1051 | } | 1091 | } |
| 1052 | 1092 | ||
| 1093 | KScopedDisableDispatch::~KScopedDisableDispatch() { | ||
| 1094 | // If we are shutting down the kernel, none of this is relevant anymore. | ||
| 1095 | if (kernel.IsShuttingDown()) { | ||
| 1096 | return; | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | // Skip the reschedule if single-core, as dispatch tracking is disabled here. | ||
| 1100 | if (!Settings::values.use_multi_core.GetValue()) { | ||
| 1101 | return; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { | ||
| 1105 | auto scheduler = kernel.CurrentScheduler(); | ||
| 1106 | |||
| 1107 | if (scheduler) { | ||
| 1108 | scheduler->RescheduleCurrentCore(); | ||
| 1109 | } | ||
| 1110 | } else { | ||
| 1111 | GetCurrentThread(kernel).EnableDispatch(); | ||
| 1112 | } | ||
| 1113 | } | ||
| 1114 | |||
| 1053 | } // namespace Kernel | 1115 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index c77f44ad4..c8a08bd71 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -48,6 +48,7 @@ enum class ThreadType : u32 { | |||
| 48 | Kernel = 1, | 48 | Kernel = 1, |
| 49 | HighPriority = 2, | 49 | HighPriority = 2, |
| 50 | User = 3, | 50 | User = 3, |
| 51 | Dummy = 100, // Special thread type for emulation purposes only | ||
| 51 | }; | 52 | }; |
| 52 | DECLARE_ENUM_FLAG_OPERATORS(ThreadType); | 53 | DECLARE_ENUM_FLAG_OPERATORS(ThreadType); |
| 53 | 54 | ||
| @@ -161,8 +162,6 @@ public: | |||
| 161 | } | 162 | } |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | void Wakeup(); | ||
| 165 | |||
| 166 | void SetBasePriority(s32 value); | 165 | void SetBasePriority(s32 value); |
| 167 | 166 | ||
| 168 | [[nodiscard]] ResultCode Run(); | 167 | [[nodiscard]] ResultCode Run(); |
| @@ -197,13 +196,19 @@ public: | |||
| 197 | 196 | ||
| 198 | void Suspend(); | 197 | void Suspend(); |
| 199 | 198 | ||
| 200 | void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) { | 199 | constexpr void SetSyncedIndex(s32 index) { |
| 201 | synced_object = obj; | 200 | synced_index = index; |
| 201 | } | ||
| 202 | |||
| 203 | [[nodiscard]] constexpr s32 GetSyncedIndex() const { | ||
| 204 | return synced_index; | ||
| 205 | } | ||
| 206 | |||
| 207 | constexpr void SetWaitResult(ResultCode wait_res) { | ||
| 202 | wait_result = wait_res; | 208 | wait_result = wait_res; |
| 203 | } | 209 | } |
| 204 | 210 | ||
| 205 | [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const { | 211 | [[nodiscard]] constexpr ResultCode GetWaitResult() const { |
| 206 | *out = synced_object; | ||
| 207 | return wait_result; | 212 | return wait_result; |
| 208 | } | 213 | } |
| 209 | 214 | ||
| @@ -374,6 +379,8 @@ public: | |||
| 374 | 379 | ||
| 375 | [[nodiscard]] bool IsSignaled() const override; | 380 | [[nodiscard]] bool IsSignaled() const override; |
| 376 | 381 | ||
| 382 | void OnTimer(); | ||
| 383 | |||
| 377 | static void PostDestroy(uintptr_t arg); | 384 | static void PostDestroy(uintptr_t arg); |
| 378 | 385 | ||
| 379 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); | 386 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); |
| @@ -446,20 +453,39 @@ public: | |||
| 446 | return per_core_priority_queue_entry[core]; | 453 | return per_core_priority_queue_entry[core]; |
| 447 | } | 454 | } |
| 448 | 455 | ||
| 449 | void SetSleepingQueue(KThreadQueue* q) { | 456 | [[nodiscard]] bool IsKernelThread() const { |
| 450 | sleeping_queue = q; | 457 | return GetActiveCore() == 3; |
| 458 | } | ||
| 459 | |||
| 460 | [[nodiscard]] bool IsDispatchTrackingDisabled() const { | ||
| 461 | return is_single_core || IsKernelThread(); | ||
| 451 | } | 462 | } |
| 452 | 463 | ||
| 453 | [[nodiscard]] s32 GetDisableDispatchCount() const { | 464 | [[nodiscard]] s32 GetDisableDispatchCount() const { |
| 465 | if (IsDispatchTrackingDisabled()) { | ||
| 466 | // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. | ||
| 467 | return 1; | ||
| 468 | } | ||
| 469 | |||
| 454 | return this->GetStackParameters().disable_count; | 470 | return this->GetStackParameters().disable_count; |
| 455 | } | 471 | } |
| 456 | 472 | ||
| 457 | void DisableDispatch() { | 473 | void DisableDispatch() { |
| 474 | if (IsDispatchTrackingDisabled()) { | ||
| 475 | // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. | ||
| 476 | return; | ||
| 477 | } | ||
| 478 | |||
| 458 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0); | 479 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0); |
| 459 | this->GetStackParameters().disable_count++; | 480 | this->GetStackParameters().disable_count++; |
| 460 | } | 481 | } |
| 461 | 482 | ||
| 462 | void EnableDispatch() { | 483 | void EnableDispatch() { |
| 484 | if (IsDispatchTrackingDisabled()) { | ||
| 485 | // TODO(bunnei): Until kernel threads are emulated, we cannot enable/disable dispatch. | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | |||
| 463 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0); | 489 | ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0); |
| 464 | this->GetStackParameters().disable_count--; | 490 | this->GetStackParameters().disable_count--; |
| 465 | } | 491 | } |
| @@ -573,6 +599,15 @@ public: | |||
| 573 | address_key_value = val; | 599 | address_key_value = val; |
| 574 | } | 600 | } |
| 575 | 601 | ||
| 602 | void ClearWaitQueue() { | ||
| 603 | wait_queue = nullptr; | ||
| 604 | } | ||
| 605 | |||
| 606 | void BeginWait(KThreadQueue* queue); | ||
| 607 | void NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_); | ||
| 608 | void EndWait(ResultCode wait_result_); | ||
| 609 | void CancelWait(ResultCode wait_result_, bool cancel_timer_task); | ||
| 610 | |||
| 576 | [[nodiscard]] bool HasWaiters() const { | 611 | [[nodiscard]] bool HasWaiters() const { |
| 577 | return !waiter_list.empty(); | 612 | return !waiter_list.empty(); |
| 578 | } | 613 | } |
| @@ -667,7 +702,6 @@ private: | |||
| 667 | KAffinityMask physical_affinity_mask{}; | 702 | KAffinityMask physical_affinity_mask{}; |
| 668 | u64 thread_id{}; | 703 | u64 thread_id{}; |
| 669 | std::atomic<s64> cpu_time{}; | 704 | std::atomic<s64> cpu_time{}; |
| 670 | KSynchronizationObject* synced_object{}; | ||
| 671 | VAddr address_key{}; | 705 | VAddr address_key{}; |
| 672 | KProcess* parent{}; | 706 | KProcess* parent{}; |
| 673 | VAddr kernel_stack_top{}; | 707 | VAddr kernel_stack_top{}; |
| @@ -677,13 +711,14 @@ private: | |||
| 677 | s64 schedule_count{}; | 711 | s64 schedule_count{}; |
| 678 | s64 last_scheduled_tick{}; | 712 | s64 last_scheduled_tick{}; |
| 679 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; | 713 | std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; |
| 680 | KThreadQueue* sleeping_queue{}; | 714 | KThreadQueue* wait_queue{}; |
| 681 | WaiterList waiter_list{}; | 715 | WaiterList waiter_list{}; |
| 682 | WaiterList pinned_waiter_list{}; | 716 | WaiterList pinned_waiter_list{}; |
| 683 | KThread* lock_owner{}; | 717 | KThread* lock_owner{}; |
| 684 | u32 address_key_value{}; | 718 | u32 address_key_value{}; |
| 685 | u32 suspend_request_flags{}; | 719 | u32 suspend_request_flags{}; |
| 686 | u32 suspend_allowed_flags{}; | 720 | u32 suspend_allowed_flags{}; |
| 721 | s32 synced_index{}; | ||
| 687 | ResultCode wait_result{ResultSuccess}; | 722 | ResultCode wait_result{ResultSuccess}; |
| 688 | s32 base_priority{}; | 723 | s32 base_priority{}; |
| 689 | s32 physical_ideal_core_id{}; | 724 | s32 physical_ideal_core_id{}; |
| @@ -708,6 +743,7 @@ private: | |||
| 708 | 743 | ||
| 709 | // For emulation | 744 | // For emulation |
| 710 | std::shared_ptr<Common::Fiber> host_context{}; | 745 | std::shared_ptr<Common::Fiber> host_context{}; |
| 746 | bool is_single_core{}; | ||
| 711 | 747 | ||
| 712 | // For debugging | 748 | // For debugging |
| 713 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | 749 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| @@ -752,4 +788,20 @@ public: | |||
| 752 | } | 788 | } |
| 753 | }; | 789 | }; |
| 754 | 790 | ||
| 791 | class KScopedDisableDispatch { | ||
| 792 | public: | ||
| 793 | [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} { | ||
| 794 | // If we are shutting down the kernel, none of this is relevant anymore. | ||
| 795 | if (kernel.IsShuttingDown()) { | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | GetCurrentThread(kernel).DisableDispatch(); | ||
| 799 | } | ||
| 800 | |||
| 801 | ~KScopedDisableDispatch(); | ||
| 802 | |||
| 803 | private: | ||
| 804 | KernelCore& kernel; | ||
| 805 | }; | ||
| 806 | |||
| 755 | } // namespace Kernel | 807 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp new file mode 100644 index 000000000..d5248b547 --- /dev/null +++ b/src/core/hle/kernel/k_thread_queue.cpp | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 6 | #include "core/hle/kernel/kernel.h" | ||
| 7 | #include "core/hle/kernel/time_manager.h" | ||
| 8 | |||
| 9 | namespace Kernel { | ||
| 10 | |||
| 11 | void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread, | ||
| 12 | [[maybe_unused]] KSynchronizationObject* signaled_object, | ||
| 13 | [[maybe_unused]] ResultCode wait_result) {} | ||
| 14 | |||
| 15 | void KThreadQueue::EndWait(KThread* waiting_thread, ResultCode wait_result) { | ||
| 16 | // Set the thread's wait result. | ||
| 17 | waiting_thread->SetWaitResult(wait_result); | ||
| 18 | |||
| 19 | // Set the thread as runnable. | ||
| 20 | waiting_thread->SetState(ThreadState::Runnable); | ||
| 21 | |||
| 22 | // Clear the thread's wait queue. | ||
| 23 | waiting_thread->ClearWaitQueue(); | ||
| 24 | |||
| 25 | // Cancel the thread task. | ||
| 26 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | ||
| 27 | } | ||
| 28 | |||
| 29 | void KThreadQueue::CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 30 | bool cancel_timer_task) { | ||
| 31 | // Set the thread's wait result. | ||
| 32 | waiting_thread->SetWaitResult(wait_result); | ||
| 33 | |||
| 34 | // Set the thread as runnable. | ||
| 35 | waiting_thread->SetState(ThreadState::Runnable); | ||
| 36 | |||
| 37 | // Clear the thread's wait queue. | ||
| 38 | waiting_thread->ClearWaitQueue(); | ||
| 39 | |||
| 40 | // Cancel the thread task. | ||
| 41 | if (cancel_timer_task) { | ||
| 42 | kernel.TimeManager().UnscheduleTimeEvent(waiting_thread); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread, | ||
| 47 | [[maybe_unused]] ResultCode wait_result) {} | ||
| 48 | |||
| 49 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h index 35d471dc5..ccb718e49 100644 --- a/src/core/hle/kernel/k_thread_queue.h +++ b/src/core/hle/kernel/k_thread_queue.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/kernel/k_scheduler.h" | ||
| 7 | #include "core/hle/kernel/k_thread.h" | 8 | #include "core/hle/kernel/k_thread.h" |
| 8 | 9 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
| @@ -11,71 +12,24 @@ namespace Kernel { | |||
| 11 | class KThreadQueue { | 12 | class KThreadQueue { |
| 12 | public: | 13 | public: |
| 13 | explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} | 14 | explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {} |
| 15 | virtual ~KThreadQueue() = default; | ||
| 14 | 16 | ||
| 15 | bool IsEmpty() const { | 17 | virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object, |
| 16 | return wait_list.empty(); | 18 | ResultCode wait_result); |
| 17 | } | 19 | virtual void EndWait(KThread* waiting_thread, ResultCode wait_result); |
| 18 | 20 | virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, | |
| 19 | KThread::WaiterList::iterator begin() { | 21 | bool cancel_timer_task); |
| 20 | return wait_list.begin(); | ||
| 21 | } | ||
| 22 | KThread::WaiterList::iterator end() { | ||
| 23 | return wait_list.end(); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool SleepThread(KThread* t) { | ||
| 27 | KScopedSchedulerLock sl{kernel}; | ||
| 28 | |||
| 29 | // If the thread needs terminating, don't enqueue it. | ||
| 30 | if (t->IsTerminationRequested()) { | ||
| 31 | return false; | ||
| 32 | } | ||
| 33 | |||
| 34 | // Set the thread's queue and mark it as waiting. | ||
| 35 | t->SetSleepingQueue(this); | ||
| 36 | t->SetState(ThreadState::Waiting); | ||
| 37 | |||
| 38 | // Add the thread to the queue. | ||
| 39 | wait_list.push_back(*t); | ||
| 40 | |||
| 41 | return true; | ||
| 42 | } | ||
| 43 | |||
| 44 | void WakeupThread(KThread* t) { | ||
| 45 | KScopedSchedulerLock sl{kernel}; | ||
| 46 | |||
| 47 | // Remove the thread from the queue. | ||
| 48 | wait_list.erase(wait_list.iterator_to(*t)); | ||
| 49 | |||
| 50 | // Mark the thread as no longer sleeping. | ||
| 51 | t->SetState(ThreadState::Runnable); | ||
| 52 | t->SetSleepingQueue(nullptr); | ||
| 53 | } | ||
| 54 | |||
| 55 | KThread* WakeupFrontThread() { | ||
| 56 | KScopedSchedulerLock sl{kernel}; | ||
| 57 | |||
| 58 | if (wait_list.empty()) { | ||
| 59 | return nullptr; | ||
| 60 | } else { | ||
| 61 | // Remove the thread from the queue. | ||
| 62 | auto it = wait_list.begin(); | ||
| 63 | KThread* thread = std::addressof(*it); | ||
| 64 | wait_list.erase(it); | ||
| 65 | |||
| 66 | ASSERT(thread->GetState() == ThreadState::Waiting); | ||
| 67 | |||
| 68 | // Mark the thread as no longer sleeping. | ||
| 69 | thread->SetState(ThreadState::Runnable); | ||
| 70 | thread->SetSleepingQueue(nullptr); | ||
| 71 | |||
| 72 | return thread; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | 22 | ||
| 76 | private: | 23 | private: |
| 77 | KernelCore& kernel; | 24 | KernelCore& kernel; |
| 78 | KThread::WaiterList wait_list{}; | 25 | KThread::WaiterList wait_list{}; |
| 79 | }; | 26 | }; |
| 80 | 27 | ||
| 28 | class KThreadQueueWithoutEndWait : public KThreadQueue { | ||
| 29 | public: | ||
| 30 | explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {} | ||
| 31 | |||
| 32 | void EndWait(KThread* waiting_thread, ResultCode wait_result) override final; | ||
| 33 | }; | ||
| 34 | |||
| 81 | } // namespace Kernel | 35 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e42a6d36f..2e4e4cb1c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| 15 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 16 | #include "common/microprofile.h" | 16 | #include "common/microprofile.h" |
| 17 | #include "common/scope_exit.h" | ||
| 17 | #include "common/thread.h" | 18 | #include "common/thread.h" |
| 18 | #include "common/thread_worker.h" | 19 | #include "common/thread_worker.h" |
| 19 | #include "core/arm/arm_interface.h" | 20 | #include "core/arm/arm_interface.h" |
| @@ -83,12 +84,16 @@ struct KernelCore::Impl { | |||
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | void InitializeCores() { | 86 | void InitializeCores() { |
| 86 | for (auto& core : cores) { | 87 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { |
| 87 | core.Initialize(current_process->Is64BitProcess()); | 88 | cores[core_id].Initialize(current_process->Is64BitProcess()); |
| 89 | system.Memory().SetCurrentPageTable(*current_process, core_id); | ||
| 88 | } | 90 | } |
| 89 | } | 91 | } |
| 90 | 92 | ||
| 91 | void Shutdown() { | 93 | void Shutdown() { |
| 94 | is_shutting_down.store(true, std::memory_order_relaxed); | ||
| 95 | SCOPE_EXIT({ is_shutting_down.store(false, std::memory_order_relaxed); }); | ||
| 96 | |||
| 92 | process_list.clear(); | 97 | process_list.clear(); |
| 93 | 98 | ||
| 94 | // Close all open server ports. | 99 | // Close all open server ports. |
| @@ -123,15 +128,6 @@ struct KernelCore::Impl { | |||
| 123 | next_user_process_id = KProcess::ProcessIDMin; | 128 | next_user_process_id = KProcess::ProcessIDMin; |
| 124 | next_thread_id = 1; | 129 | next_thread_id = 1; |
| 125 | 130 | ||
| 126 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||
| 127 | if (suspend_threads[core_id]) { | ||
| 128 | suspend_threads[core_id]->Close(); | ||
| 129 | suspend_threads[core_id] = nullptr; | ||
| 130 | } | ||
| 131 | |||
| 132 | schedulers[core_id].reset(); | ||
| 133 | } | ||
| 134 | |||
| 135 | cores.clear(); | 131 | cores.clear(); |
| 136 | 132 | ||
| 137 | global_handle_table->Finalize(); | 133 | global_handle_table->Finalize(); |
| @@ -159,6 +155,16 @@ struct KernelCore::Impl { | |||
| 159 | CleanupObject(time_shared_mem); | 155 | CleanupObject(time_shared_mem); |
| 160 | CleanupObject(system_resource_limit); | 156 | CleanupObject(system_resource_limit); |
| 161 | 157 | ||
| 158 | for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { | ||
| 159 | if (suspend_threads[core_id]) { | ||
| 160 | suspend_threads[core_id]->Close(); | ||
| 161 | suspend_threads[core_id] = nullptr; | ||
| 162 | } | ||
| 163 | |||
| 164 | schedulers[core_id]->Finalize(); | ||
| 165 | schedulers[core_id].reset(); | ||
| 166 | } | ||
| 167 | |||
| 162 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others | 168 | // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others |
| 163 | next_host_thread_id = Core::Hardware::NUM_CPU_CORES; | 169 | next_host_thread_id = Core::Hardware::NUM_CPU_CORES; |
| 164 | 170 | ||
| @@ -245,13 +251,11 @@ struct KernelCore::Impl { | |||
| 245 | KScopedSchedulerLock lock(kernel); | 251 | KScopedSchedulerLock lock(kernel); |
| 246 | global_scheduler_context->PreemptThreads(); | 252 | global_scheduler_context->PreemptThreads(); |
| 247 | } | 253 | } |
| 248 | const auto time_interval = std::chrono::nanoseconds{ | 254 | const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; |
| 249 | Core::Timing::msToCycles(std::chrono::milliseconds(10))}; | ||
| 250 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | 255 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); |
| 251 | }); | 256 | }); |
| 252 | 257 | ||
| 253 | const auto time_interval = | 258 | const auto time_interval = std::chrono::nanoseconds{std::chrono::milliseconds(10)}; |
| 254 | std::chrono::nanoseconds{Core::Timing::msToCycles(std::chrono::milliseconds(10))}; | ||
| 255 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); | 259 | system.CoreTiming().ScheduleEvent(time_interval, preemption_event); |
| 256 | } | 260 | } |
| 257 | 261 | ||
| @@ -267,14 +271,6 @@ struct KernelCore::Impl { | |||
| 267 | 271 | ||
| 268 | void MakeCurrentProcess(KProcess* process) { | 272 | void MakeCurrentProcess(KProcess* process) { |
| 269 | current_process = process; | 273 | current_process = process; |
| 270 | if (process == nullptr) { | ||
| 271 | return; | ||
| 272 | } | ||
| 273 | |||
| 274 | const u32 core_id = GetCurrentHostThreadID(); | ||
| 275 | if (core_id < Core::Hardware::NUM_CPU_CORES) { | ||
| 276 | system.Memory().SetCurrentPageTable(*process, core_id); | ||
| 277 | } | ||
| 278 | } | 274 | } |
| 279 | 275 | ||
| 280 | static inline thread_local u32 host_thread_id = UINT32_MAX; | 276 | static inline thread_local u32 host_thread_id = UINT32_MAX; |
| @@ -300,15 +296,16 @@ struct KernelCore::Impl { | |||
| 300 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | 296 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time |
| 301 | KThread* GetHostDummyThread() { | 297 | KThread* GetHostDummyThread() { |
| 302 | auto make_thread = [this]() { | 298 | auto make_thread = [this]() { |
| 303 | std::unique_ptr<KThread> thread = std::make_unique<KThread>(system.Kernel()); | 299 | std::lock_guard lk(dummy_thread_lock); |
| 300 | auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel())); | ||
| 304 | KAutoObject::Create(thread.get()); | 301 | KAutoObject::Create(thread.get()); |
| 305 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); | 302 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); |
| 306 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); | 303 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); |
| 307 | return thread; | 304 | return thread.get(); |
| 308 | }; | 305 | }; |
| 309 | 306 | ||
| 310 | thread_local auto thread = make_thread(); | 307 | thread_local KThread* saved_thread = make_thread(); |
| 311 | return thread.get(); | 308 | return saved_thread; |
| 312 | } | 309 | } |
| 313 | 310 | ||
| 314 | /// Registers a CPU core thread by allocating a host thread ID for it | 311 | /// Registers a CPU core thread by allocating a host thread ID for it |
| @@ -343,7 +340,16 @@ struct KernelCore::Impl { | |||
| 343 | is_phantom_mode_for_singlecore = value; | 340 | is_phantom_mode_for_singlecore = value; |
| 344 | } | 341 | } |
| 345 | 342 | ||
| 343 | bool IsShuttingDown() const { | ||
| 344 | return is_shutting_down.load(std::memory_order_relaxed); | ||
| 345 | } | ||
| 346 | |||
| 346 | KThread* GetCurrentEmuThread() { | 347 | KThread* GetCurrentEmuThread() { |
| 348 | // If we are shutting down the kernel, none of this is relevant anymore. | ||
| 349 | if (IsShuttingDown()) { | ||
| 350 | return {}; | ||
| 351 | } | ||
| 352 | |||
| 347 | const auto thread_id = GetCurrentHostThreadID(); | 353 | const auto thread_id = GetCurrentHostThreadID(); |
| 348 | if (thread_id >= Core::Hardware::NUM_CPU_CORES) { | 354 | if (thread_id >= Core::Hardware::NUM_CPU_CORES) { |
| 349 | return GetHostDummyThread(); | 355 | return GetHostDummyThread(); |
| @@ -695,6 +701,12 @@ struct KernelCore::Impl { | |||
| 695 | return port; | 701 | return port; |
| 696 | } | 702 | } |
| 697 | 703 | ||
| 704 | std::mutex server_ports_lock; | ||
| 705 | std::mutex server_sessions_lock; | ||
| 706 | std::mutex registered_objects_lock; | ||
| 707 | std::mutex registered_in_use_objects_lock; | ||
| 708 | std::mutex dummy_thread_lock; | ||
| 709 | |||
| 698 | std::atomic<u32> next_object_id{0}; | 710 | std::atomic<u32> next_object_id{0}; |
| 699 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; | 711 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; |
| 700 | std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; | 712 | std::atomic<u64> next_user_process_id{KProcess::ProcessIDMin}; |
| @@ -725,10 +737,6 @@ struct KernelCore::Impl { | |||
| 725 | std::unordered_set<KServerSession*> server_sessions; | 737 | std::unordered_set<KServerSession*> server_sessions; |
| 726 | std::unordered_set<KAutoObject*> registered_objects; | 738 | std::unordered_set<KAutoObject*> registered_objects; |
| 727 | std::unordered_set<KAutoObject*> registered_in_use_objects; | 739 | std::unordered_set<KAutoObject*> registered_in_use_objects; |
| 728 | std::mutex server_ports_lock; | ||
| 729 | std::mutex server_sessions_lock; | ||
| 730 | std::mutex registered_objects_lock; | ||
| 731 | std::mutex registered_in_use_objects_lock; | ||
| 732 | 740 | ||
| 733 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | 741 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; |
| 734 | std::vector<Kernel::PhysicalCore> cores; | 742 | std::vector<Kernel::PhysicalCore> cores; |
| @@ -753,7 +761,11 @@ struct KernelCore::Impl { | |||
| 753 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 761 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 754 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 762 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 755 | 763 | ||
| 764 | // Specifically tracked to be automatically destroyed with kernel | ||
| 765 | std::vector<std::unique_ptr<KThread>> dummy_threads; | ||
| 766 | |||
| 756 | bool is_multicore{}; | 767 | bool is_multicore{}; |
| 768 | std::atomic_bool is_shutting_down{}; | ||
| 757 | bool is_phantom_mode_for_singlecore{}; | 769 | bool is_phantom_mode_for_singlecore{}; |
| 758 | u32 single_core_thread_id{}; | 770 | u32 single_core_thread_id{}; |
| 759 | 771 | ||
| @@ -839,16 +851,20 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { | |||
| 839 | return impl->cores[id]; | 851 | return impl->cores[id]; |
| 840 | } | 852 | } |
| 841 | 853 | ||
| 854 | size_t KernelCore::CurrentPhysicalCoreIndex() const { | ||
| 855 | const u32 core_id = impl->GetCurrentHostThreadID(); | ||
| 856 | if (core_id >= Core::Hardware::NUM_CPU_CORES) { | ||
| 857 | return Core::Hardware::NUM_CPU_CORES - 1; | ||
| 858 | } | ||
| 859 | return core_id; | ||
| 860 | } | ||
| 861 | |||
| 842 | Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { | 862 | Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { |
| 843 | u32 core_id = impl->GetCurrentHostThreadID(); | 863 | return impl->cores[CurrentPhysicalCoreIndex()]; |
| 844 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 845 | return impl->cores[core_id]; | ||
| 846 | } | 864 | } |
| 847 | 865 | ||
| 848 | const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { | 866 | const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { |
| 849 | u32 core_id = impl->GetCurrentHostThreadID(); | 867 | return impl->cores[CurrentPhysicalCoreIndex()]; |
| 850 | ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); | ||
| 851 | return impl->cores[core_id]; | ||
| 852 | } | 868 | } |
| 853 | 869 | ||
| 854 | Kernel::KScheduler* KernelCore::CurrentScheduler() { | 870 | Kernel::KScheduler* KernelCore::CurrentScheduler() { |
| @@ -1051,6 +1067,9 @@ void KernelCore::Suspend(bool in_suspention) { | |||
| 1051 | impl->suspend_threads[core_id]->SetState(state); | 1067 | impl->suspend_threads[core_id]->SetState(state); |
| 1052 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( | 1068 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( |
| 1053 | ThreadWaitReasonForDebugging::Suspended); | 1069 | ThreadWaitReasonForDebugging::Suspended); |
| 1070 | if (!should_suspend) { | ||
| 1071 | impl->suspend_threads[core_id]->DisableDispatch(); | ||
| 1072 | } | ||
| 1054 | } | 1073 | } |
| 1055 | } | 1074 | } |
| 1056 | } | 1075 | } |
| @@ -1059,19 +1078,21 @@ bool KernelCore::IsMulticore() const { | |||
| 1059 | return impl->is_multicore; | 1078 | return impl->is_multicore; |
| 1060 | } | 1079 | } |
| 1061 | 1080 | ||
| 1081 | bool KernelCore::IsShuttingDown() const { | ||
| 1082 | return impl->IsShuttingDown(); | ||
| 1083 | } | ||
| 1084 | |||
| 1062 | void KernelCore::ExceptionalExit() { | 1085 | void KernelCore::ExceptionalExit() { |
| 1063 | exception_exited = true; | 1086 | exception_exited = true; |
| 1064 | Suspend(true); | 1087 | Suspend(true); |
| 1065 | } | 1088 | } |
| 1066 | 1089 | ||
| 1067 | void KernelCore::EnterSVCProfile() { | 1090 | void KernelCore::EnterSVCProfile() { |
| 1068 | std::size_t core = impl->GetCurrentHostThreadID(); | 1091 | impl->svc_ticks[CurrentPhysicalCoreIndex()] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); |
| 1069 | impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); | ||
| 1070 | } | 1092 | } |
| 1071 | 1093 | ||
| 1072 | void KernelCore::ExitSVCProfile() { | 1094 | void KernelCore::ExitSVCProfile() { |
| 1073 | std::size_t core = impl->GetCurrentHostThreadID(); | 1095 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]); |
| 1074 | MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); | ||
| 1075 | } | 1096 | } |
| 1076 | 1097 | ||
| 1077 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { | 1098 | std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) { |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index d2ceae950..b9b423908 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -53,6 +53,7 @@ class KSharedMemoryInfo; | |||
| 53 | class KThread; | 53 | class KThread; |
| 54 | class KTransferMemory; | 54 | class KTransferMemory; |
| 55 | class KWritableEvent; | 55 | class KWritableEvent; |
| 56 | class KCodeMemory; | ||
| 56 | class PhysicalCore; | 57 | class PhysicalCore; |
| 57 | class ServiceThread; | 58 | class ServiceThread; |
| 58 | class Synchronization; | 59 | class Synchronization; |
| @@ -148,6 +149,9 @@ public: | |||
| 148 | /// Gets the an instance of the respective physical CPU core. | 149 | /// Gets the an instance of the respective physical CPU core. |
| 149 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; | 150 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; |
| 150 | 151 | ||
| 152 | /// Gets the current physical core index for the running host thread. | ||
| 153 | std::size_t CurrentPhysicalCoreIndex() const; | ||
| 154 | |||
| 151 | /// Gets the sole instance of the Scheduler at the current running core. | 155 | /// Gets the sole instance of the Scheduler at the current running core. |
| 152 | Kernel::KScheduler* CurrentScheduler(); | 156 | Kernel::KScheduler* CurrentScheduler(); |
| 153 | 157 | ||
| @@ -271,6 +275,8 @@ public: | |||
| 271 | 275 | ||
| 272 | bool IsMulticore() const; | 276 | bool IsMulticore() const; |
| 273 | 277 | ||
| 278 | bool IsShuttingDown() const; | ||
| 279 | |||
| 274 | void EnterSVCProfile(); | 280 | void EnterSVCProfile(); |
| 275 | 281 | ||
| 276 | void ExitSVCProfile(); | 282 | void ExitSVCProfile(); |
| @@ -326,6 +332,8 @@ public: | |||
| 326 | return slab_heap_container->transfer_memory; | 332 | return slab_heap_container->transfer_memory; |
| 327 | } else if constexpr (std::is_same_v<T, KWritableEvent>) { | 333 | } else if constexpr (std::is_same_v<T, KWritableEvent>) { |
| 328 | return slab_heap_container->writeable_event; | 334 | return slab_heap_container->writeable_event; |
| 335 | } else if constexpr (std::is_same_v<T, KCodeMemory>) { | ||
| 336 | return slab_heap_container->code_memory; | ||
| 329 | } | 337 | } |
| 330 | } | 338 | } |
| 331 | 339 | ||
| @@ -377,6 +385,7 @@ private: | |||
| 377 | KSlabHeap<KThread> thread; | 385 | KSlabHeap<KThread> thread; |
| 378 | KSlabHeap<KTransferMemory> transfer_memory; | 386 | KSlabHeap<KTransferMemory> transfer_memory; |
| 379 | KSlabHeap<KWritableEvent> writeable_event; | 387 | KSlabHeap<KWritableEvent> writeable_event; |
| 388 | KSlabHeap<KCodeMemory> code_memory; | ||
| 380 | }; | 389 | }; |
| 381 | 390 | ||
| 382 | std::unique_ptr<SlabHeapContainer> slab_heap_container; | 391 | std::unique_ptr<SlabHeapContainer> slab_heap_container; |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 6721b6276..03f3dec10 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -25,24 +25,27 @@ public: | |||
| 25 | void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); | 25 | void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); |
| 26 | 26 | ||
| 27 | private: | 27 | private: |
| 28 | std::vector<std::thread> threads; | 28 | std::vector<std::jthread> threads; |
| 29 | std::queue<std::function<void()>> requests; | 29 | std::queue<std::function<void()>> requests; |
| 30 | std::mutex queue_mutex; | 30 | std::mutex queue_mutex; |
| 31 | std::condition_variable condition; | 31 | std::condition_variable_any condition; |
| 32 | const std::string service_name; | 32 | const std::string service_name; |
| 33 | bool stop{}; | ||
| 34 | }; | 33 | }; |
| 35 | 34 | ||
| 36 | ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) | 35 | ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) |
| 37 | : service_name{name} { | 36 | : service_name{name} { |
| 38 | for (std::size_t i = 0; i < num_threads; ++i) | 37 | for (std::size_t i = 0; i < num_threads; ++i) { |
| 39 | threads.emplace_back([this, &kernel] { | 38 | threads.emplace_back([this, &kernel](std::stop_token stop_token) { |
| 40 | Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); | 39 | Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); |
| 41 | 40 | ||
| 42 | // Wait for first request before trying to acquire a render context | 41 | // Wait for first request before trying to acquire a render context |
| 43 | { | 42 | { |
| 44 | std::unique_lock lock{queue_mutex}; | 43 | std::unique_lock lock{queue_mutex}; |
| 45 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | 44 | condition.wait(lock, stop_token, [this] { return !requests.empty(); }); |
| 45 | } | ||
| 46 | |||
| 47 | if (stop_token.stop_requested()) { | ||
| 48 | return; | ||
| 46 | } | 49 | } |
| 47 | 50 | ||
| 48 | kernel.RegisterHostThread(); | 51 | kernel.RegisterHostThread(); |
| @@ -52,10 +55,16 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std | |||
| 52 | 55 | ||
| 53 | { | 56 | { |
| 54 | std::unique_lock lock{queue_mutex}; | 57 | std::unique_lock lock{queue_mutex}; |
| 55 | condition.wait(lock, [this] { return stop || !requests.empty(); }); | 58 | condition.wait(lock, stop_token, [this] { return !requests.empty(); }); |
| 56 | if (stop || requests.empty()) { | 59 | |
| 60 | if (stop_token.stop_requested()) { | ||
| 57 | return; | 61 | return; |
| 58 | } | 62 | } |
| 63 | |||
| 64 | if (requests.empty()) { | ||
| 65 | continue; | ||
| 66 | } | ||
| 67 | |||
| 59 | task = std::move(requests.front()); | 68 | task = std::move(requests.front()); |
| 60 | requests.pop(); | 69 | requests.pop(); |
| 61 | } | 70 | } |
| @@ -63,6 +72,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std | |||
| 63 | task(); | 72 | task(); |
| 64 | } | 73 | } |
| 65 | }); | 74 | }); |
| 75 | } | ||
| 66 | } | 76 | } |
| 67 | 77 | ||
| 68 | void ServiceThread::Impl::QueueSyncRequest(KSession& session, | 78 | void ServiceThread::Impl::QueueSyncRequest(KSession& session, |
| @@ -88,12 +98,9 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, | |||
| 88 | } | 98 | } |
| 89 | 99 | ||
| 90 | ServiceThread::Impl::~Impl() { | 100 | ServiceThread::Impl::~Impl() { |
| 91 | { | ||
| 92 | std::unique_lock lock{queue_mutex}; | ||
| 93 | stop = true; | ||
| 94 | } | ||
| 95 | condition.notify_all(); | 101 | condition.notify_all(); |
| 96 | for (std::thread& thread : threads) { | 102 | for (auto& thread : threads) { |
| 103 | thread.request_stop(); | ||
| 97 | thread.join(); | 104 | thread.join(); |
| 98 | } | 105 | } |
| 99 | } | 106 | } |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f9d99bc51..a9f7438ea 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 19 | #include "core/hle/kernel/k_client_port.h" | 19 | #include "core/hle/kernel/k_client_port.h" |
| 20 | #include "core/hle/kernel/k_client_session.h" | 20 | #include "core/hle/kernel/k_client_session.h" |
| 21 | #include "core/hle/kernel/k_code_memory.h" | ||
| 21 | #include "core/hle/kernel/k_event.h" | 22 | #include "core/hle/kernel/k_event.h" |
| 22 | #include "core/hle/kernel/k_handle_table.h" | 23 | #include "core/hle/kernel/k_handle_table.h" |
| 23 | #include "core/hle/kernel/k_memory_block.h" | 24 | #include "core/hle/kernel/k_memory_block.h" |
| @@ -31,6 +32,7 @@ | |||
| 31 | #include "core/hle/kernel/k_shared_memory.h" | 32 | #include "core/hle/kernel/k_shared_memory.h" |
| 32 | #include "core/hle/kernel/k_synchronization_object.h" | 33 | #include "core/hle/kernel/k_synchronization_object.h" |
| 33 | #include "core/hle/kernel/k_thread.h" | 34 | #include "core/hle/kernel/k_thread.h" |
| 35 | #include "core/hle/kernel/k_thread_queue.h" | ||
| 34 | #include "core/hle/kernel/k_transfer_memory.h" | 36 | #include "core/hle/kernel/k_transfer_memory.h" |
| 35 | #include "core/hle/kernel/k_writable_event.h" | 37 | #include "core/hle/kernel/k_writable_event.h" |
| 36 | #include "core/hle/kernel/kernel.h" | 38 | #include "core/hle/kernel/kernel.h" |
| @@ -307,26 +309,29 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, | |||
| 307 | 309 | ||
| 308 | /// Makes a blocking IPC call to an OS service. | 310 | /// Makes a blocking IPC call to an OS service. |
| 309 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | 311 | static ResultCode SendSyncRequest(Core::System& system, Handle handle) { |
| 310 | |||
| 311 | auto& kernel = system.Kernel(); | 312 | auto& kernel = system.Kernel(); |
| 312 | 313 | ||
| 314 | // Create the wait queue. | ||
| 315 | KThreadQueue wait_queue(kernel); | ||
| 316 | |||
| 317 | // Get the client session from its handle. | ||
| 318 | KScopedAutoObject session = | ||
| 319 | kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); | ||
| 320 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 321 | |||
| 322 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | ||
| 323 | |||
| 313 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); | 324 | auto thread = kernel.CurrentScheduler()->GetCurrentThread(); |
| 314 | { | 325 | { |
| 315 | KScopedSchedulerLock lock(kernel); | 326 | KScopedSchedulerLock lock(kernel); |
| 316 | thread->SetState(ThreadState::Waiting); | 327 | |
| 317 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | 328 | // This is a synchronous request, so we should wait for our request to complete. |
| 318 | 329 | GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue)); | |
| 319 | { | 330 | GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); |
| 320 | KScopedAutoObject session = | 331 | session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming()); |
| 321 | kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); | ||
| 322 | R_UNLESS(session.IsNotNull(), ResultInvalidHandle); | ||
| 323 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | ||
| 324 | session->SendSyncRequest(thread, system.Memory(), system.CoreTiming()); | ||
| 325 | } | ||
| 326 | } | 332 | } |
| 327 | 333 | ||
| 328 | KSynchronizationObject* dummy{}; | 334 | return thread->GetWaitResult(); |
| 329 | return thread->GetWaitResult(std::addressof(dummy)); | ||
| 330 | } | 335 | } |
| 331 | 336 | ||
| 332 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { | 337 | static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { |
| @@ -873,7 +878,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle | |||
| 873 | const u64 thread_ticks = current_thread->GetCpuTime(); | 878 | const u64 thread_ticks = current_thread->GetCpuTime(); |
| 874 | 879 | ||
| 875 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); | 880 | out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); |
| 876 | } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { | 881 | } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { |
| 877 | out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; | 882 | out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; |
| 878 | } | 883 | } |
| 879 | 884 | ||
| @@ -887,7 +892,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle | |||
| 887 | return ResultInvalidHandle; | 892 | return ResultInvalidHandle; |
| 888 | } | 893 | } |
| 889 | 894 | ||
| 890 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) { | 895 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && |
| 896 | info_sub_id != system.Kernel().CurrentPhysicalCoreIndex()) { | ||
| 891 | LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); | 897 | LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); |
| 892 | return ResultInvalidCombination; | 898 | return ResultInvalidCombination; |
| 893 | } | 899 | } |
| @@ -1169,6 +1175,8 @@ static u32 GetCurrentProcessorNumber32(Core::System& system) { | |||
| 1169 | return GetCurrentProcessorNumber(system); | 1175 | return GetCurrentProcessorNumber(system); |
| 1170 | } | 1176 | } |
| 1171 | 1177 | ||
| 1178 | namespace { | ||
| 1179 | |||
| 1172 | constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { | 1180 | constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { |
| 1173 | switch (perm) { | 1181 | switch (perm) { |
| 1174 | case Svc::MemoryPermission::Read: | 1182 | case Svc::MemoryPermission::Read: |
| @@ -1179,10 +1187,40 @@ constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) { | |||
| 1179 | } | 1187 | } |
| 1180 | } | 1188 | } |
| 1181 | 1189 | ||
| 1182 | constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { | 1190 | [[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) { |
| 1183 | return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; | 1191 | return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare; |
| 1184 | } | 1192 | } |
| 1185 | 1193 | ||
| 1194 | constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1195 | switch (perm) { | ||
| 1196 | case Svc::MemoryPermission::None: | ||
| 1197 | case Svc::MemoryPermission::Read: | ||
| 1198 | case Svc::MemoryPermission::ReadWrite: | ||
| 1199 | case Svc::MemoryPermission::ReadExecute: | ||
| 1200 | return true; | ||
| 1201 | default: | ||
| 1202 | return false; | ||
| 1203 | } | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1207 | return perm == Svc::MemoryPermission::ReadWrite; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1211 | return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1215 | return perm == Svc::MemoryPermission::None; | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) { | ||
| 1219 | return perm == Svc::MemoryPermission::None; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | } // Anonymous namespace | ||
| 1223 | |||
| 1186 | static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, | 1224 | static ResultCode MapSharedMemory(Core::System& system, Handle shmem_handle, VAddr address, |
| 1187 | u64 size, Svc::MemoryPermission map_perm) { | 1225 | u64 size, Svc::MemoryPermission map_perm) { |
| 1188 | LOG_TRACE(Kernel_SVC, | 1226 | LOG_TRACE(Kernel_SVC, |
| @@ -1262,6 +1300,223 @@ static ResultCode UnmapSharedMemory32(Core::System& system, Handle shmem_handle, | |||
| 1262 | return UnmapSharedMemory(system, shmem_handle, address, size); | 1300 | return UnmapSharedMemory(system, shmem_handle, address, size); |
| 1263 | } | 1301 | } |
| 1264 | 1302 | ||
| 1303 | static ResultCode SetProcessMemoryPermission(Core::System& system, Handle process_handle, | ||
| 1304 | VAddr address, u64 size, Svc::MemoryPermission perm) { | ||
| 1305 | LOG_TRACE(Kernel_SVC, | ||
| 1306 | "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", | ||
| 1307 | process_handle, address, size, perm); | ||
| 1308 | |||
| 1309 | // Validate the address/size. | ||
| 1310 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 1311 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1312 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1313 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1314 | |||
| 1315 | // Validate the memory permission. | ||
| 1316 | R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 1317 | |||
| 1318 | // Get the process from its handle. | ||
| 1319 | KScopedAutoObject process = | ||
| 1320 | system.CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); | ||
| 1321 | R_UNLESS(process.IsNotNull(), ResultInvalidHandle); | ||
| 1322 | |||
| 1323 | // Validate that the address is in range. | ||
| 1324 | auto& page_table = process->PageTable(); | ||
| 1325 | R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); | ||
| 1326 | |||
| 1327 | // Set the memory permission. | ||
| 1328 | return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, | ||
| 1332 | VAddr src_address, u64 size) { | ||
| 1333 | LOG_TRACE(Kernel_SVC, | ||
| 1334 | "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", | ||
| 1335 | dst_address, process_handle, src_address, size); | ||
| 1336 | |||
| 1337 | // Validate the address/size. | ||
| 1338 | R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); | ||
| 1339 | R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); | ||
| 1340 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1341 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1342 | R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); | ||
| 1343 | R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); | ||
| 1344 | |||
| 1345 | // Get the processes. | ||
| 1346 | KProcess* dst_process = system.CurrentProcess(); | ||
| 1347 | KScopedAutoObject src_process = | ||
| 1348 | dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); | ||
| 1349 | R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); | ||
| 1350 | |||
| 1351 | // Get the page tables. | ||
| 1352 | auto& dst_pt = dst_process->PageTable(); | ||
| 1353 | auto& src_pt = src_process->PageTable(); | ||
| 1354 | |||
| 1355 | // Validate that the mapping is in range. | ||
| 1356 | R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); | ||
| 1357 | R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), | ||
| 1358 | ResultInvalidMemoryRegion); | ||
| 1359 | |||
| 1360 | // Create a new page group. | ||
| 1361 | KMemoryInfo kBlockInfo = dst_pt.QueryInfo(dst_address); | ||
| 1362 | KPageLinkedList pg(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); | ||
| 1363 | |||
| 1364 | // Map the group. | ||
| 1365 | R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode, | ||
| 1366 | KMemoryPermission::UserReadWrite)); | ||
| 1367 | |||
| 1368 | return ResultSuccess; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, | ||
| 1372 | VAddr src_address, u64 size) { | ||
| 1373 | LOG_TRACE(Kernel_SVC, | ||
| 1374 | "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}", | ||
| 1375 | dst_address, process_handle, src_address, size); | ||
| 1376 | |||
| 1377 | // Validate the address/size. | ||
| 1378 | R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress); | ||
| 1379 | R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress); | ||
| 1380 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1381 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1382 | R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory); | ||
| 1383 | R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory); | ||
| 1384 | |||
| 1385 | // Get the processes. | ||
| 1386 | KProcess* dst_process = system.CurrentProcess(); | ||
| 1387 | KScopedAutoObject src_process = | ||
| 1388 | dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle); | ||
| 1389 | R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); | ||
| 1390 | |||
| 1391 | // Get the page tables. | ||
| 1392 | auto& dst_pt = dst_process->PageTable(); | ||
| 1393 | auto& src_pt = src_process->PageTable(); | ||
| 1394 | |||
| 1395 | // Validate that the mapping is in range. | ||
| 1396 | R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); | ||
| 1397 | R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode), | ||
| 1398 | ResultInvalidMemoryRegion); | ||
| 1399 | |||
| 1400 | // Unmap the memory. | ||
| 1401 | R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address)); | ||
| 1402 | |||
| 1403 | return ResultSuccess; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { | ||
| 1407 | LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}", | ||
| 1408 | static_cast<void*>(out), address, size); | ||
| 1409 | // Get kernel instance. | ||
| 1410 | auto& kernel = system.Kernel(); | ||
| 1411 | |||
| 1412 | // Validate address / size. | ||
| 1413 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 1414 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1415 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1416 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1417 | |||
| 1418 | // Create the code memory. | ||
| 1419 | |||
| 1420 | KCodeMemory* code_mem = KCodeMemory::Create(kernel); | ||
| 1421 | R_UNLESS(code_mem != nullptr, ResultOutOfResource); | ||
| 1422 | |||
| 1423 | // Verify that the region is in range. | ||
| 1424 | R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size), | ||
| 1425 | ResultInvalidCurrentMemory); | ||
| 1426 | |||
| 1427 | // Initialize the code memory. | ||
| 1428 | R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size)); | ||
| 1429 | |||
| 1430 | // Register the code memory. | ||
| 1431 | KCodeMemory::Register(kernel, code_mem); | ||
| 1432 | |||
| 1433 | // Add the code memory to the handle table. | ||
| 1434 | R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem)); | ||
| 1435 | |||
| 1436 | code_mem->Close(); | ||
| 1437 | |||
| 1438 | return ResultSuccess; | ||
| 1439 | } | ||
| 1440 | |||
| 1441 | static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation, | ||
| 1442 | VAddr address, size_t size, Svc::MemoryPermission perm) { | ||
| 1443 | |||
| 1444 | LOG_TRACE(Kernel_SVC, | ||
| 1445 | "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, " | ||
| 1446 | "permission=0x{:X}", | ||
| 1447 | code_memory_handle, operation, address, size, perm); | ||
| 1448 | |||
| 1449 | // Validate the address / size. | ||
| 1450 | R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress); | ||
| 1451 | R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); | ||
| 1452 | R_UNLESS(size > 0, ResultInvalidSize); | ||
| 1453 | R_UNLESS((address < address + size), ResultInvalidCurrentMemory); | ||
| 1454 | |||
| 1455 | // Get the code memory from its handle. | ||
| 1456 | KScopedAutoObject code_mem = | ||
| 1457 | system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle); | ||
| 1458 | R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle); | ||
| 1459 | |||
| 1460 | // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process. | ||
| 1461 | // This enables homebrew usage of these SVCs for JIT. | ||
| 1462 | |||
| 1463 | // Perform the operation. | ||
| 1464 | switch (static_cast<CodeMemoryOperation>(operation)) { | ||
| 1465 | case CodeMemoryOperation::Map: { | ||
| 1466 | // Check that the region is in range. | ||
| 1467 | R_UNLESS( | ||
| 1468 | system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), | ||
| 1469 | ResultInvalidMemoryRegion); | ||
| 1470 | |||
| 1471 | // Check the memory permission. | ||
| 1472 | R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 1473 | |||
| 1474 | // Map the memory. | ||
| 1475 | R_TRY(code_mem->Map(address, size)); | ||
| 1476 | } break; | ||
| 1477 | case CodeMemoryOperation::Unmap: { | ||
| 1478 | // Check that the region is in range. | ||
| 1479 | R_UNLESS( | ||
| 1480 | system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut), | ||
| 1481 | ResultInvalidMemoryRegion); | ||
| 1482 | |||
| 1483 | // Check the memory permission. | ||
| 1484 | R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 1485 | |||
| 1486 | // Unmap the memory. | ||
| 1487 | R_TRY(code_mem->Unmap(address, size)); | ||
| 1488 | } break; | ||
| 1489 | case CodeMemoryOperation::MapToOwner: { | ||
| 1490 | // Check that the region is in range. | ||
| 1491 | R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, | ||
| 1492 | KMemoryState::GeneratedCode), | ||
| 1493 | ResultInvalidMemoryRegion); | ||
| 1494 | |||
| 1495 | // Check the memory permission. | ||
| 1496 | R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 1497 | |||
| 1498 | // Map the memory to its owner. | ||
| 1499 | R_TRY(code_mem->MapToOwner(address, size, perm)); | ||
| 1500 | } break; | ||
| 1501 | case CodeMemoryOperation::UnmapFromOwner: { | ||
| 1502 | // Check that the region is in range. | ||
| 1503 | R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, | ||
| 1504 | KMemoryState::GeneratedCode), | ||
| 1505 | ResultInvalidMemoryRegion); | ||
| 1506 | |||
| 1507 | // Check the memory permission. | ||
| 1508 | R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission); | ||
| 1509 | |||
| 1510 | // Unmap the memory from its owner. | ||
| 1511 | R_TRY(code_mem->UnmapFromOwner(address, size)); | ||
| 1512 | } break; | ||
| 1513 | default: | ||
| 1514 | return ResultInvalidEnumValue; | ||
| 1515 | } | ||
| 1516 | |||
| 1517 | return ResultSuccess; | ||
| 1518 | } | ||
| 1519 | |||
| 1265 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, | 1520 | static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, |
| 1266 | VAddr page_info_address, Handle process_handle, | 1521 | VAddr page_info_address, Handle process_handle, |
| 1267 | VAddr address) { | 1522 | VAddr address) { |
| @@ -1459,10 +1714,14 @@ static void ExitProcess32(Core::System& system) { | |||
| 1459 | ExitProcess(system); | 1714 | ExitProcess(system); |
| 1460 | } | 1715 | } |
| 1461 | 1716 | ||
| 1462 | static constexpr bool IsValidVirtualCoreId(int32_t core_id) { | 1717 | namespace { |
| 1718 | |||
| 1719 | constexpr bool IsValidVirtualCoreId(int32_t core_id) { | ||
| 1463 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); | 1720 | return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES)); |
| 1464 | } | 1721 | } |
| 1465 | 1722 | ||
| 1723 | } // Anonymous namespace | ||
| 1724 | |||
| 1466 | /// Creates a new thread | 1725 | /// Creates a new thread |
| 1467 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, | 1726 | static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, |
| 1468 | VAddr stack_bottom, u32 priority, s32 core_id) { | 1727 | VAddr stack_bottom, u32 priority, s32 core_id) { |
| @@ -1846,7 +2105,9 @@ static ResultCode ResetSignal32(Core::System& system, Handle handle) { | |||
| 1846 | return ResetSignal(system, handle); | 2105 | return ResetSignal(system, handle); |
| 1847 | } | 2106 | } |
| 1848 | 2107 | ||
| 1849 | static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { | 2108 | namespace { |
| 2109 | |||
| 2110 | constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { | ||
| 1850 | switch (perm) { | 2111 | switch (perm) { |
| 1851 | case MemoryPermission::None: | 2112 | case MemoryPermission::None: |
| 1852 | case MemoryPermission::Read: | 2113 | case MemoryPermission::Read: |
| @@ -1857,6 +2118,8 @@ static constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) { | |||
| 1857 | } | 2118 | } |
| 1858 | } | 2119 | } |
| 1859 | 2120 | ||
| 2121 | } // Anonymous namespace | ||
| 2122 | |||
| 1860 | /// Creates a TransferMemory object | 2123 | /// Creates a TransferMemory object |
| 1861 | static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, | 2124 | static ResultCode CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size, |
| 1862 | MemoryPermission map_perm) { | 2125 | MemoryPermission map_perm) { |
| @@ -2548,8 +2811,8 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2548 | {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, | 2811 | {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, |
| 2549 | {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, | 2812 | {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, |
| 2550 | {0x4A, nullptr, "SetUnsafeLimit"}, | 2813 | {0x4A, nullptr, "SetUnsafeLimit"}, |
| 2551 | {0x4B, nullptr, "CreateCodeMemory"}, | 2814 | {0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"}, |
| 2552 | {0x4C, nullptr, "ControlCodeMemory"}, | 2815 | {0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"}, |
| 2553 | {0x4D, nullptr, "SleepSystem"}, | 2816 | {0x4D, nullptr, "SleepSystem"}, |
| 2554 | {0x4E, nullptr, "ReadWriteRegister"}, | 2817 | {0x4E, nullptr, "ReadWriteRegister"}, |
| 2555 | {0x4F, nullptr, "SetProcessActivity"}, | 2818 | {0x4F, nullptr, "SetProcessActivity"}, |
| @@ -2588,9 +2851,9 @@ static const FunctionDef SVC_Table_64[] = { | |||
| 2588 | {0x70, nullptr, "CreatePort"}, | 2851 | {0x70, nullptr, "CreatePort"}, |
| 2589 | {0x71, nullptr, "ManageNamedPort"}, | 2852 | {0x71, nullptr, "ManageNamedPort"}, |
| 2590 | {0x72, nullptr, "ConnectToPort"}, | 2853 | {0x72, nullptr, "ConnectToPort"}, |
| 2591 | {0x73, nullptr, "SetProcessMemoryPermission"}, | 2854 | {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"}, |
| 2592 | {0x74, nullptr, "MapProcessMemory"}, | 2855 | {0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"}, |
| 2593 | {0x75, nullptr, "UnmapProcessMemory"}, | 2856 | {0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"}, |
| 2594 | {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"}, | 2857 | {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"}, |
| 2595 | {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"}, | 2858 | {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"}, |
| 2596 | {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, | 2859 | {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"}, |
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 6e62e656f..86255fe6d 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -73,6 +73,23 @@ void SvcWrap64(Core::System& system) { | |||
| 73 | .raw); | 73 | .raw); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | // Used by MapProcessMemory and UnmapProcessMemory | ||
| 77 | template <ResultCode func(Core::System&, u64, u32, u64, u64)> | ||
| 78 | void SvcWrap64(Core::System& system) { | ||
| 79 | FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)), | ||
| 80 | Param(system, 2), Param(system, 3)) | ||
| 81 | .raw); | ||
| 82 | } | ||
| 83 | |||
| 84 | // Used by ControlCodeMemory | ||
| 85 | template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> | ||
| 86 | void SvcWrap64(Core::System& system) { | ||
| 87 | FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), | ||
| 88 | static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3), | ||
| 89 | static_cast<Svc::MemoryPermission>(Param(system, 4))) | ||
| 90 | .raw); | ||
| 91 | } | ||
| 92 | |||
| 76 | template <ResultCode func(Core::System&, u32*)> | 93 | template <ResultCode func(Core::System&, u32*)> |
| 77 | void SvcWrap64(Core::System& system) { | 94 | void SvcWrap64(Core::System& system) { |
| 78 | u32 param = 0; | 95 | u32 param = 0; |
| @@ -301,6 +318,16 @@ void SvcWrap64(Core::System& system) { | |||
| 301 | FuncReturn(system, retval); | 318 | FuncReturn(system, retval); |
| 302 | } | 319 | } |
| 303 | 320 | ||
| 321 | // Used by CreateCodeMemory | ||
| 322 | template <ResultCode func(Core::System&, Handle*, u64, u64)> | ||
| 323 | void SvcWrap64(Core::System& system) { | ||
| 324 | u32 param_1 = 0; | ||
| 325 | const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; | ||
| 326 | |||
| 327 | system.CurrentArmInterface().SetReg(1, param_1); | ||
| 328 | FuncReturn(system, retval); | ||
| 329 | } | ||
| 330 | |||
| 304 | template <ResultCode func(Core::System&, Handle*, u64, u32, u32)> | 331 | template <ResultCode func(Core::System&, Handle*, u64, u32, u32)> |
| 305 | void SvcWrap64(Core::System& system) { | 332 | void SvcWrap64(Core::System& system) { |
| 306 | u32 param_1 = 0; | 333 | u32 param_1 = 0; |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 8cd7279a3..aa985d820 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | 9 | #include "core/hle/kernel/k_thread.h" |
| 9 | #include "core/hle/kernel/time_manager.h" | 10 | #include "core/hle/kernel/time_manager.h" |
| 10 | 11 | ||
| @@ -15,7 +16,10 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { | |||
| 15 | Core::Timing::CreateEvent("Kernel::TimeManagerCallback", | 16 | Core::Timing::CreateEvent("Kernel::TimeManagerCallback", |
| 16 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | 17 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { |
| 17 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); | 18 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); |
| 18 | thread->Wakeup(); | 19 | { |
| 20 | KScopedSchedulerLock sl(system.Kernel()); | ||
| 21 | thread->OnTimer(); | ||
| 22 | } | ||
| 19 | }); | 23 | }); |
| 20 | } | 24 | } |
| 21 | 25 | ||
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index aee8d4f93..e60661fe1 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "core/hle/service/apm/apm_controller.h" | 30 | #include "core/hle/service/apm/apm_controller.h" |
| 31 | #include "core/hle/service/apm/apm_interface.h" | 31 | #include "core/hle/service/apm/apm_interface.h" |
| 32 | #include "core/hle/service/bcat/backend/backend.h" | 32 | #include "core/hle/service/bcat/backend/backend.h" |
| 33 | #include "core/hle/service/caps/caps.h" | ||
| 33 | #include "core/hle/service/filesystem/filesystem.h" | 34 | #include "core/hle/service/filesystem/filesystem.h" |
| 34 | #include "core/hle/service/ns/ns.h" | 35 | #include "core/hle/service/ns/ns.h" |
| 35 | #include "core/hle/service/nvflinger/nvflinger.h" | 36 | #include "core/hle/service/nvflinger/nvflinger.h" |
| @@ -298,7 +299,7 @@ ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nv | |||
| 298 | {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, | 299 | {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"}, |
| 299 | {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, | 300 | {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"}, |
| 300 | {110, nullptr, "SetApplicationAlbumUserData"}, | 301 | {110, nullptr, "SetApplicationAlbumUserData"}, |
| 301 | {120, nullptr, "SaveCurrentScreenshot"}, | 302 | {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"}, |
| 302 | {130, nullptr, "SetRecordVolumeMuted"}, | 303 | {130, nullptr, "SetRecordVolumeMuted"}, |
| 303 | {1000, nullptr, "GetDebugStorageChannel"}, | 304 | {1000, nullptr, "GetDebugStorageChannel"}, |
| 304 | }; | 305 | }; |
| @@ -579,6 +580,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo | |||
| 579 | rb.Push(ResultSuccess); | 580 | rb.Push(ResultSuccess); |
| 580 | } | 581 | } |
| 581 | 582 | ||
| 583 | void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) { | ||
| 584 | IPC::RequestParser rp{ctx}; | ||
| 585 | |||
| 586 | const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>(); | ||
| 587 | |||
| 588 | LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option); | ||
| 589 | |||
| 590 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 591 | rb.Push(ResultSuccess); | ||
| 592 | } | ||
| 593 | |||
| 582 | AppletMessageQueue::AppletMessageQueue(Core::System& system) | 594 | AppletMessageQueue::AppletMessageQueue(Core::System& system) |
| 583 | : service_context{system, "AppletMessageQueue"} { | 595 | : service_context{system, "AppletMessageQueue"} { |
| 584 | on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); | 596 | on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived"); |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 202d20757..2a578aea5 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -151,6 +151,7 @@ private: | |||
| 151 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); | 151 | void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); |
| 152 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); | 152 | void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); |
| 153 | void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); | 153 | void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx); |
| 154 | void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx); | ||
| 154 | 155 | ||
| 155 | enum class ScreenshotPermission : u32 { | 156 | enum class ScreenshotPermission : u32 { |
| 156 | Inherit = 0, | 157 | Inherit = 0, |
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 2721679c1..d073f2210 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp | |||
| @@ -10,6 +10,9 @@ | |||
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/frontend/applets/controller.h" | 12 | #include "core/frontend/applets/controller.h" |
| 13 | #include "core/hid/emulated_controller.h" | ||
| 14 | #include "core/hid/hid_core.h" | ||
| 15 | #include "core/hid/hid_types.h" | ||
| 13 | #include "core/hle/result.h" | 16 | #include "core/hle/result.h" |
| 14 | #include "core/hle/service/am/am.h" | 17 | #include "core/hle/service/am/am.h" |
| 15 | #include "core/hle/service/am/applets/applet_controller.h" | 18 | #include "core/hle/service/am/applets/applet_controller.h" |
| @@ -25,7 +28,7 @@ namespace Service::AM::Applets { | |||
| 25 | static Core::Frontend::ControllerParameters ConvertToFrontendParameters( | 28 | static Core::Frontend::ControllerParameters ConvertToFrontendParameters( |
| 26 | ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, | 29 | ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, |
| 27 | std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { | 30 | std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { |
| 28 | HID::Controller_NPad::NpadStyleSet npad_style_set; | 31 | Core::HID::NpadStyleTag npad_style_set; |
| 29 | npad_style_set.raw = private_arg.style_set; | 32 | npad_style_set.raw = private_arg.style_set; |
| 30 | 33 | ||
| 31 | return { | 34 | return { |
| @@ -243,19 +246,11 @@ void Controller::Execute() { | |||
| 243 | void Controller::ConfigurationComplete() { | 246 | void Controller::ConfigurationComplete() { |
| 244 | ControllerSupportResultInfo result_info{}; | 247 | ControllerSupportResultInfo result_info{}; |
| 245 | 248 | ||
| 246 | const auto& players = Settings::values.players.GetValue(); | ||
| 247 | |||
| 248 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. | 249 | // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. |
| 249 | // Otherwise, only count connected players from P1-P8. | 250 | // Otherwise, only count connected players from P1-P8. |
| 250 | result_info.player_count = | 251 | result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount(); |
| 251 | is_single_mode | 252 | |
| 252 | ? 1 | 253 | result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId()); |
| 253 | : static_cast<s8>(std::count_if(players.begin(), players.end() - 2, | ||
| 254 | [](const auto& player) { return player.connected; })); | ||
| 255 | |||
| 256 | result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance( | ||
| 257 | players.begin(), std::find_if(players.begin(), players.end(), | ||
| 258 | [](const auto& player) { return player.connected; }))); | ||
| 259 | 254 | ||
| 260 | result_info.result = 0; | 255 | result_info.result = 0; |
| 261 | 256 | ||
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h index 0a34c4fc0..1a832505e 100644 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/applets/applet_controller.h | |||
| @@ -16,6 +16,10 @@ namespace Core { | |||
| 16 | class System; | 16 | class System; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | namespace Core::HID { | ||
| 20 | enum class NpadStyleSet : u32; | ||
| 21 | } | ||
| 22 | |||
| 19 | namespace Service::AM::Applets { | 23 | namespace Service::AM::Applets { |
| 20 | 24 | ||
| 21 | using IdentificationColor = std::array<u8, 4>; | 25 | using IdentificationColor = std::array<u8, 4>; |
| @@ -52,7 +56,7 @@ struct ControllerSupportArgPrivate { | |||
| 52 | bool flag_1{}; | 56 | bool flag_1{}; |
| 53 | ControllerSupportMode mode{}; | 57 | ControllerSupportMode mode{}; |
| 54 | ControllerSupportCaller caller{}; | 58 | ControllerSupportCaller caller{}; |
| 55 | u32 style_set{}; | 59 | Core::HID::NpadStyleSet style_set{}; |
| 56 | u32 joy_hold_type{}; | 60 | u32 joy_hold_type{}; |
| 57 | }; | 61 | }; |
| 58 | static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, | 62 | static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, |
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7320b1c0f..134ac1ee2 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp | |||
| @@ -231,7 +231,7 @@ void AppletManager::SetDefaultAppletFrontendSet() { | |||
| 231 | void AppletManager::SetDefaultAppletsIfMissing() { | 231 | void AppletManager::SetDefaultAppletsIfMissing() { |
| 232 | if (frontend.controller == nullptr) { | 232 | if (frontend.controller == nullptr) { |
| 233 | frontend.controller = | 233 | frontend.controller = |
| 234 | std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager()); | 234 | std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | if (frontend.error == nullptr) { | 237 | if (frontend.error == nullptr) { |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 7da1f2969..981b6c996 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -96,7 +96,7 @@ private: | |||
| 96 | 96 | ||
| 97 | bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, | 97 | bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, |
| 98 | std::vector<opus_int16>& output, u64* out_performance_time) const { | 98 | std::vector<opus_int16>& output, u64* out_performance_time) const { |
| 99 | const auto start_time = std::chrono::high_resolution_clock::now(); | 99 | const auto start_time = std::chrono::steady_clock::now(); |
| 100 | const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); | 100 | const std::size_t raw_output_sz = output.size() * sizeof(opus_int16); |
| 101 | if (sizeof(OpusPacketHeader) > input.size()) { | 101 | if (sizeof(OpusPacketHeader) > input.size()) { |
| 102 | LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", | 102 | LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", |
| @@ -135,7 +135,7 @@ private: | |||
| 135 | return false; | 135 | return false; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | const auto end_time = std::chrono::high_resolution_clock::now() - start_time; | 138 | const auto end_time = std::chrono::steady_clock::now() - start_time; |
| 139 | sample_count = out_sample_count; | 139 | sample_count = out_sample_count; |
| 140 | consumed = static_cast<u32>(sizeof(OpusPacketHeader) + hdr.size); | 140 | consumed = static_cast<u32>(sizeof(OpusPacketHeader) + hdr.size); |
| 141 | if (out_performance_time != nullptr) { | 141 | if (out_performance_time != nullptr) { |
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index b18adcb9d..7254055e6 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h | |||
| @@ -24,7 +24,7 @@ enum class AlbumImageOrientation { | |||
| 24 | Orientation3 = 3, | 24 | Orientation3 = 3, |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | enum class AlbumReportOption { | 27 | enum class AlbumReportOption : s32 { |
| 28 | Disable = 0, | 28 | Disable = 0, |
| 29 | Enable = 1, | 29 | Enable = 1, |
| 30 | }; | 30 | }; |
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 68c9240ae..3c36f4085 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -17,10 +17,11 @@ namespace Service::Friend { | |||
| 17 | 17 | ||
| 18 | class IFriendService final : public ServiceFramework<IFriendService> { | 18 | class IFriendService final : public ServiceFramework<IFriendService> { |
| 19 | public: | 19 | public: |
| 20 | explicit IFriendService(Core::System& system_) : ServiceFramework{system_, "IFriendService"} { | 20 | explicit IFriendService(Core::System& system_) |
| 21 | : ServiceFramework{system_, "IFriendService"}, service_context{system, "IFriendService"} { | ||
| 21 | // clang-format off | 22 | // clang-format off |
| 22 | static const FunctionInfo functions[] = { | 23 | static const FunctionInfo functions[] = { |
| 23 | {0, nullptr, "GetCompletionEvent"}, | 24 | {0, &IFriendService::GetCompletionEvent, "GetCompletionEvent"}, |
| 24 | {1, nullptr, "Cancel"}, | 25 | {1, nullptr, "Cancel"}, |
| 25 | {10100, nullptr, "GetFriendListIds"}, | 26 | {10100, nullptr, "GetFriendListIds"}, |
| 26 | {10101, &IFriendService::GetFriendList, "GetFriendList"}, | 27 | {10101, &IFriendService::GetFriendList, "GetFriendList"}, |
| @@ -109,6 +110,12 @@ public: | |||
| 109 | // clang-format on | 110 | // clang-format on |
| 110 | 111 | ||
| 111 | RegisterHandlers(functions); | 112 | RegisterHandlers(functions); |
| 113 | |||
| 114 | completion_event = service_context.CreateEvent("IFriendService:CompletionEvent"); | ||
| 115 | } | ||
| 116 | |||
| 117 | ~IFriendService() override { | ||
| 118 | service_context.CloseEvent(completion_event); | ||
| 112 | } | 119 | } |
| 113 | 120 | ||
| 114 | private: | 121 | private: |
| @@ -129,6 +136,14 @@ private: | |||
| 129 | }; | 136 | }; |
| 130 | static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); | 137 | static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); |
| 131 | 138 | ||
| 139 | void GetCompletionEvent(Kernel::HLERequestContext& ctx) { | ||
| 140 | LOG_DEBUG(Service_Friend, "called"); | ||
| 141 | |||
| 142 | IPC::ResponseBuilder rb{ctx, 2, 1}; | ||
| 143 | rb.Push(ResultSuccess); | ||
| 144 | rb.PushCopyObjects(completion_event->GetReadableEvent()); | ||
| 145 | } | ||
| 146 | |||
| 132 | void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { | 147 | void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { |
| 133 | // This is safe to stub, as there should be no adverse consequences from reporting no | 148 | // This is safe to stub, as there should be no adverse consequences from reporting no |
| 134 | // blocked users. | 149 | // blocked users. |
| @@ -179,6 +194,10 @@ private: | |||
| 179 | rb.Push<u32>(0); // Friend count | 194 | rb.Push<u32>(0); // Friend count |
| 180 | // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId" | 195 | // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId" |
| 181 | } | 196 | } |
| 197 | |||
| 198 | KernelHelpers::ServiceContext service_context; | ||
| 199 | |||
| 200 | Kernel::KEvent* completion_event; | ||
| 182 | }; | 201 | }; |
| 183 | 202 | ||
| 184 | class INotificationService final : public ServiceFramework<INotificationService> { | 203 | class INotificationService final : public ServiceFramework<INotificationService> { |
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index a08dc9758..b24d469cf 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "core/hle/service/glue/bgtc.h" | 8 | #include "core/hle/service/glue/bgtc.h" |
| 9 | #include "core/hle/service/glue/ectx.h" | 9 | #include "core/hle/service/glue/ectx.h" |
| 10 | #include "core/hle/service/glue/glue.h" | 10 | #include "core/hle/service/glue/glue.h" |
| 11 | #include "core/hle/service/glue/notif.h" | ||
| 11 | 12 | ||
| 12 | namespace Service::Glue { | 13 | namespace Service::Glue { |
| 13 | 14 | ||
| @@ -24,6 +25,9 @@ void InstallInterfaces(Core::System& system) { | |||
| 24 | 25 | ||
| 25 | // Error Context | 26 | // Error Context |
| 26 | std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager()); | 27 | std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager()); |
| 28 | |||
| 29 | // Notification Services for application | ||
| 30 | std::make_shared<NOTIF_A>(system)->InstallAsService(system.ServiceManager()); | ||
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | } // namespace Service::Glue | 33 | } // namespace Service::Glue |
diff --git a/src/core/hle/service/glue/notif.cpp b/src/core/hle/service/glue/notif.cpp new file mode 100644 index 000000000..c559ec9df --- /dev/null +++ b/src/core/hle/service/glue/notif.cpp | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/ipc_helpers.h" | ||
| 6 | #include "core/hle/service/glue/notif.h" | ||
| 7 | |||
| 8 | namespace Service::Glue { | ||
| 9 | |||
| 10 | NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} { | ||
| 11 | // clang-format off | ||
| 12 | static const FunctionInfo functions[] = { | ||
| 13 | {500, nullptr, "RegisterAlarmSetting"}, | ||
| 14 | {510, nullptr, "UpdateAlarmSetting"}, | ||
| 15 | {520, &NOTIF_A::ListAlarmSettings, "ListAlarmSettings"}, | ||
| 16 | {530, nullptr, "LoadApplicationParameter"}, | ||
| 17 | {540, nullptr, "DeleteAlarmSetting"}, | ||
| 18 | {1000, &NOTIF_A::Initialize, "Initialize"}, | ||
| 19 | }; | ||
| 20 | // clang-format on | ||
| 21 | |||
| 22 | RegisterHandlers(functions); | ||
| 23 | } | ||
| 24 | |||
| 25 | NOTIF_A::~NOTIF_A() = default; | ||
| 26 | |||
| 27 | void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) { | ||
| 28 | // Returns an array of AlarmSetting | ||
| 29 | constexpr s32 alarm_count = 0; | ||
| 30 | |||
| 31 | LOG_WARNING(Service_NOTIF, "(STUBBED) called"); | ||
| 32 | |||
| 33 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 34 | rb.Push(ResultSuccess); | ||
| 35 | rb.Push(alarm_count); | ||
| 36 | } | ||
| 37 | |||
| 38 | void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) { | ||
| 39 | LOG_WARNING(Service_NOTIF, "(STUBBED) called"); | ||
| 40 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 41 | rb.Push(ResultSuccess); | ||
| 42 | } | ||
| 43 | |||
| 44 | } // namespace Service::Glue | ||
diff --git a/src/core/hle/service/glue/notif.h b/src/core/hle/service/glue/notif.h new file mode 100644 index 000000000..6ecf2015c --- /dev/null +++ b/src/core/hle/service/glue/notif.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Core { | ||
| 10 | class System; | ||
| 11 | } | ||
| 12 | |||
| 13 | namespace Service::Glue { | ||
| 14 | |||
| 15 | class NOTIF_A final : public ServiceFramework<NOTIF_A> { | ||
| 16 | public: | ||
| 17 | explicit NOTIF_A(Core::System& system_); | ||
| 18 | ~NOTIF_A() override; | ||
| 19 | |||
| 20 | private: | ||
| 21 | void ListAlarmSettings(Kernel::HLERequestContext& ctx); | ||
| 22 | void Initialize(Kernel::HLERequestContext& ctx); | ||
| 23 | }; | ||
| 24 | |||
| 25 | } // namespace Service::Glue | ||
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index bda6e2557..f0f3105dc 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp | |||
| @@ -4,13 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/settings.h" | 5 | #include "common/settings.h" |
| 6 | #include "core/core_timing.h" | 6 | #include "core/core_timing.h" |
| 7 | #include "core/hid/emulated_console.h" | ||
| 8 | #include "core/hid/hid_core.h" | ||
| 7 | #include "core/hle/service/hid/controllers/console_sixaxis.h" | 9 | #include "core/hle/service/hid/controllers/console_sixaxis.h" |
| 8 | 10 | ||
| 9 | namespace Service::HID { | 11 | namespace Service::HID { |
| 10 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; |
| 11 | 13 | ||
| 12 | Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) | 14 | Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) |
| 13 | : ControllerBase{system_} {} | 15 | : ControllerBase{hid_core_} { |
| 16 | console = hid_core.GetEmulatedConsole(); | ||
| 17 | } | ||
| 18 | |||
| 14 | Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; | 19 | Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; |
| 15 | 20 | ||
| 16 | void Controller_ConsoleSixAxis::OnInit() {} | 21 | void Controller_ConsoleSixAxis::OnInit() {} |
| @@ -19,44 +24,31 @@ void Controller_ConsoleSixAxis::OnRelease() {} | |||
| 19 | 24 | ||
| 20 | void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 25 | void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 21 | std::size_t size) { | 26 | std::size_t size) { |
| 22 | seven_six_axis.header.timestamp = core_timing.GetCPUTicks(); | ||
| 23 | seven_six_axis.header.total_entry_count = 17; | ||
| 24 | |||
| 25 | if (!IsControllerActivated() || !is_transfer_memory_set) { | 27 | if (!IsControllerActivated() || !is_transfer_memory_set) { |
| 26 | seven_six_axis.header.entry_count = 0; | 28 | seven_sixaxis_lifo.buffer_count = 0; |
| 27 | seven_six_axis.header.last_entry_index = 0; | 29 | seven_sixaxis_lifo.buffer_tail = 0; |
| 28 | return; | 30 | return; |
| 29 | } | 31 | } |
| 30 | seven_six_axis.header.entry_count = 16; | ||
| 31 | |||
| 32 | const auto& last_entry = | ||
| 33 | seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; | ||
| 34 | seven_six_axis.header.last_entry_index = (seven_six_axis.header.last_entry_index + 1) % 17; | ||
| 35 | auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; | ||
| 36 | 32 | ||
| 37 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 33 | const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; |
| 38 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 34 | next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; |
| 39 | 35 | ||
| 40 | // Try to read sixaxis sensor states | 36 | // Try to read sixaxis sensor states |
| 41 | MotionDevice motion_device{}; | 37 | const auto motion_status = console->GetMotion(); |
| 42 | const auto& device = motions[0]; | 38 | |
| 43 | if (device) { | 39 | console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; |
| 44 | std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation, | ||
| 45 | motion_device.orientation, motion_device.quaternion) = device->GetStatus(); | ||
| 46 | console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f; | ||
| 47 | } | ||
| 48 | 40 | ||
| 49 | cur_entry.accel = motion_device.accel; | 41 | next_seven_sixaxis_state.accel = motion_status.accel; |
| 50 | // Zero gyro values as they just mess up with the camera | 42 | // Zero gyro values as they just mess up with the camera |
| 51 | // Note: Probably a correct sensivity setting must be set | 43 | // Note: Probably a correct sensivity setting must be set |
| 52 | cur_entry.gyro = {}; | 44 | next_seven_sixaxis_state.gyro = {}; |
| 53 | cur_entry.quaternion = { | 45 | next_seven_sixaxis_state.quaternion = { |
| 54 | { | 46 | { |
| 55 | motion_device.quaternion.xyz.y, | 47 | motion_status.quaternion.xyz.y, |
| 56 | motion_device.quaternion.xyz.x, | 48 | motion_status.quaternion.xyz.x, |
| 57 | -motion_device.quaternion.w, | 49 | -motion_status.quaternion.w, |
| 58 | }, | 50 | }, |
| 59 | -motion_device.quaternion.xyz.z, | 51 | -motion_status.quaternion.xyz.z, |
| 60 | }; | 52 | }; |
| 61 | 53 | ||
| 62 | console_six_axis.sampling_number++; | 54 | console_six_axis.sampling_number++; |
| @@ -67,14 +59,8 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti | |||
| 67 | // Update console six axis shared memory | 59 | // Update console six axis shared memory |
| 68 | std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); | 60 | std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); |
| 69 | // Update seven six axis transfer memory | 61 | // Update seven six axis transfer memory |
| 70 | std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); | 62 | seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); |
| 71 | } | 63 | std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); |
| 72 | |||
| 73 | void Controller_ConsoleSixAxis::OnLoadInputDevices() { | ||
| 74 | const auto player = Settings::values.players.GetValue()[0]; | ||
| 75 | std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, | ||
| 76 | player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(), | ||
| 77 | Input::CreateDevice<Input::MotionDevice>); | ||
| 78 | } | 64 | } |
| 79 | 65 | ||
| 80 | void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { | 66 | void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { |
| @@ -83,8 +69,7 @@ void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { | |||
| 83 | } | 69 | } |
| 84 | 70 | ||
| 85 | void Controller_ConsoleSixAxis::ResetTimestamp() { | 71 | void Controller_ConsoleSixAxis::ResetTimestamp() { |
| 86 | auto& cur_entry = seven_six_axis.sevensixaxis_states[seven_six_axis.header.last_entry_index]; | 72 | seven_sixaxis_lifo.buffer_count = 0; |
| 87 | cur_entry.sampling_number = 0; | 73 | seven_sixaxis_lifo.buffer_tail = 0; |
| 88 | cur_entry.sampling_number2 = 0; | ||
| 89 | } | 74 | } |
| 90 | } // namespace Service::HID | 75 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index fd8a427af..279241858 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h | |||
| @@ -5,16 +5,21 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | 8 | |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/quaternion.h" | 10 | #include "common/quaternion.h" |
| 11 | #include "core/frontend/input.h" | 11 | #include "core/hid/hid_types.h" |
| 12 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 14 | |||
| 15 | namespace Core::HID { | ||
| 16 | class EmulatedConsole; | ||
| 17 | } // namespace Core::HID | ||
| 13 | 18 | ||
| 14 | namespace Service::HID { | 19 | namespace Service::HID { |
| 15 | class Controller_ConsoleSixAxis final : public ControllerBase { | 20 | class Controller_ConsoleSixAxis final : public ControllerBase { |
| 16 | public: | 21 | public: |
| 17 | explicit Controller_ConsoleSixAxis(Core::System& system_); | 22 | explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); |
| 18 | ~Controller_ConsoleSixAxis() override; | 23 | ~Controller_ConsoleSixAxis() override; |
| 19 | 24 | ||
| 20 | // Called when the controller is initialized | 25 | // Called when the controller is initialized |
| @@ -26,9 +31,6 @@ public: | |||
| 26 | // When the controller is requesting an update for the shared memory | 31 | // When the controller is requesting an update for the shared memory |
| 27 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; | 32 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; |
| 28 | 33 | ||
| 29 | // Called when input devices should be loaded | ||
| 30 | void OnLoadInputDevices() override; | ||
| 31 | |||
| 32 | // Called on InitializeSevenSixAxisSensor | 34 | // Called on InitializeSevenSixAxisSensor |
| 33 | void SetTransferMemoryPointer(u8* t_mem); | 35 | void SetTransferMemoryPointer(u8* t_mem); |
| 34 | 36 | ||
| @@ -38,43 +40,31 @@ public: | |||
| 38 | private: | 40 | private: |
| 39 | struct SevenSixAxisState { | 41 | struct SevenSixAxisState { |
| 40 | INSERT_PADDING_WORDS(4); // unused | 42 | INSERT_PADDING_WORDS(4); // unused |
| 41 | s64_le sampling_number{}; | 43 | s64 sampling_number{}; |
| 42 | s64_le sampling_number2{}; | ||
| 43 | u64 unknown{}; | 44 | u64 unknown{}; |
| 44 | Common::Vec3f accel{}; | 45 | Common::Vec3f accel{}; |
| 45 | Common::Vec3f gyro{}; | 46 | Common::Vec3f gyro{}; |
| 46 | Common::Quaternion<f32> quaternion{}; | 47 | Common::Quaternion<f32> quaternion{}; |
| 47 | }; | 48 | }; |
| 48 | static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); | 49 | static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); |
| 49 | |||
| 50 | struct SevenSixAxisMemory { | ||
| 51 | CommonHeader header{}; | ||
| 52 | std::array<SevenSixAxisState, 0x21> sevensixaxis_states{}; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); | ||
| 55 | 50 | ||
| 51 | // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat | ||
| 56 | struct ConsoleSharedMemory { | 52 | struct ConsoleSharedMemory { |
| 57 | u64_le sampling_number{}; | 53 | u64 sampling_number{}; |
| 58 | bool is_seven_six_axis_sensor_at_rest{}; | 54 | bool is_seven_six_axis_sensor_at_rest{}; |
| 55 | INSERT_PADDING_BYTES(4); // padding | ||
| 59 | f32 verticalization_error{}; | 56 | f32 verticalization_error{}; |
| 60 | Common::Vec3f gyro_bias{}; | 57 | Common::Vec3f gyro_bias{}; |
| 61 | }; | 58 | }; |
| 62 | static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); | 59 | static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); |
| 63 | 60 | ||
| 64 | struct MotionDevice { | 61 | Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; |
| 65 | Common::Vec3f accel; | 62 | static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); |
| 66 | Common::Vec3f gyro; | ||
| 67 | Common::Vec3f rotation; | ||
| 68 | std::array<Common::Vec3f, 3> orientation; | ||
| 69 | Common::Quaternion<f32> quaternion; | ||
| 70 | }; | ||
| 71 | 63 | ||
| 72 | using MotionArray = | 64 | Core::HID::EmulatedConsole* console; |
| 73 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>; | ||
| 74 | MotionArray motions; | ||
| 75 | u8* transfer_memory = nullptr; | 65 | u8* transfer_memory = nullptr; |
| 76 | bool is_transfer_memory_set = false; | 66 | bool is_transfer_memory_set = false; |
| 77 | ConsoleSharedMemory console_six_axis{}; | 67 | ConsoleSharedMemory console_six_axis{}; |
| 78 | SevenSixAxisMemory seven_six_axis{}; | 68 | SevenSixAxisState next_seven_sixaxis_state{}; |
| 79 | }; | 69 | }; |
| 80 | } // namespace Service::HID | 70 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 9d1e6db6a..788ae9ae7 100644 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp | |||
| @@ -6,12 +6,12 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::HID { | 7 | namespace Service::HID { |
| 8 | 8 | ||
| 9 | ControllerBase::ControllerBase(Core::System& system_) : system(system_) {} | 9 | ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} |
| 10 | ControllerBase::~ControllerBase() = default; | 10 | ControllerBase::~ControllerBase() = default; |
| 11 | 11 | ||
| 12 | void ControllerBase::ActivateController() { | 12 | void ControllerBase::ActivateController() { |
| 13 | if (is_activated) { | 13 | if (is_activated) { |
| 14 | OnRelease(); | 14 | return; |
| 15 | } | 15 | } |
| 16 | is_activated = true; | 16 | is_activated = true; |
| 17 | OnInit(); | 17 | OnInit(); |
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 1556fb08e..7450eb20a 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h | |||
| @@ -11,14 +11,14 @@ namespace Core::Timing { | |||
| 11 | class CoreTiming; | 11 | class CoreTiming; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | namespace Core { | 14 | namespace Core::HID { |
| 15 | class System; | 15 | class HIDCore; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | namespace Service::HID { | 18 | namespace Service::HID { |
| 19 | class ControllerBase { | 19 | class ControllerBase { |
| 20 | public: | 20 | public: |
| 21 | explicit ControllerBase(Core::System& system_); | 21 | explicit ControllerBase(Core::HID::HIDCore& hid_core_); |
| 22 | virtual ~ControllerBase(); | 22 | virtual ~ControllerBase(); |
| 23 | 23 | ||
| 24 | // Called when the controller is initialized | 24 | // Called when the controller is initialized |
| @@ -35,26 +35,17 @@ public: | |||
| 35 | virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 35 | virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 36 | std::size_t size) {} | 36 | std::size_t size) {} |
| 37 | 37 | ||
| 38 | // Called when input devices should be loaded | ||
| 39 | virtual void OnLoadInputDevices() = 0; | ||
| 40 | |||
| 41 | void ActivateController(); | 38 | void ActivateController(); |
| 42 | 39 | ||
| 43 | void DeactivateController(); | 40 | void DeactivateController(); |
| 44 | 41 | ||
| 45 | bool IsControllerActivated() const; | 42 | bool IsControllerActivated() const; |
| 46 | 43 | ||
| 44 | static const std::size_t hid_entry_count = 17; | ||
| 45 | |||
| 47 | protected: | 46 | protected: |
| 48 | bool is_activated{false}; | 47 | bool is_activated{false}; |
| 49 | 48 | ||
| 50 | struct CommonHeader { | 49 | Core::HID::HIDCore& hid_core; |
| 51 | s64_le timestamp; | ||
| 52 | s64_le total_entry_count; | ||
| 53 | s64_le last_entry_index; | ||
| 54 | s64_le entry_count; | ||
| 55 | }; | ||
| 56 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||
| 57 | |||
| 58 | Core::System& system; | ||
| 59 | }; | 50 | }; |
| 60 | } // namespace Service::HID | 51 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index d439b8fb0..6a6fb9cab 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -6,15 +6,19 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/hid/emulated_controller.h" | ||
| 10 | #include "core/hid/hid_core.h" | ||
| 11 | #include "core/hid/hid_types.h" | ||
| 9 | #include "core/hle/service/hid/controllers/debug_pad.h" | 12 | #include "core/hle/service/hid/controllers/debug_pad.h" |
| 10 | 13 | ||
| 11 | namespace Service::HID { | 14 | namespace Service::HID { |
| 15 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; | ||
| 12 | 16 | ||
| 13 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | 17 | Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) |
| 14 | [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | 18 | : ControllerBase{hid_core_} { |
| 15 | enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; | 19 | controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); |
| 20 | } | ||
| 16 | 21 | ||
| 17 | Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {} | ||
| 18 | Controller_DebugPad::~Controller_DebugPad() = default; | 22 | Controller_DebugPad::~Controller_DebugPad() = default; |
| 19 | 23 | ||
| 20 | void Controller_DebugPad::OnInit() {} | 24 | void Controller_DebugPad::OnInit() {} |
| @@ -23,63 +27,29 @@ void Controller_DebugPad::OnRelease() {} | |||
| 23 | 27 | ||
| 24 | void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 28 | void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 25 | std::size_t size) { | 29 | std::size_t size) { |
| 26 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | ||
| 27 | shared_memory.header.total_entry_count = 17; | ||
| 28 | |||
| 29 | if (!IsControllerActivated()) { | 30 | if (!IsControllerActivated()) { |
| 30 | shared_memory.header.entry_count = 0; | 31 | debug_pad_lifo.buffer_count = 0; |
| 31 | shared_memory.header.last_entry_index = 0; | 32 | debug_pad_lifo.buffer_tail = 0; |
| 33 | std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); | ||
| 32 | return; | 34 | return; |
| 33 | } | 35 | } |
| 34 | shared_memory.header.entry_count = 16; | ||
| 35 | 36 | ||
| 36 | const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | 37 | const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; |
| 37 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | 38 | next_state.sampling_number = last_entry.sampling_number + 1; |
| 38 | auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 39 | |||
| 40 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 41 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 42 | 39 | ||
| 43 | if (Settings::values.debug_pad_enabled) { | 40 | if (Settings::values.debug_pad_enabled) { |
| 44 | cur_entry.attribute.connected.Assign(1); | 41 | next_state.attribute.connected.Assign(1); |
| 45 | auto& pad = cur_entry.pad_state; | ||
| 46 | 42 | ||
| 47 | using namespace Settings::NativeButton; | 43 | const auto& button_state = controller->GetDebugPadButtons(); |
| 48 | pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); | 44 | const auto& stick_state = controller->GetSticks(); |
| 49 | pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 50 | pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 51 | pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 52 | pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 53 | pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 54 | pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 55 | pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 56 | pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 57 | pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 58 | pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 59 | pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 60 | pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 61 | pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 62 | 45 | ||
| 63 | const auto [stick_l_x_f, stick_l_y_f] = | 46 | next_state.pad_state = button_state; |
| 64 | analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | 47 | next_state.l_stick = stick_state.left; |
| 65 | const auto [stick_r_x_f, stick_r_y_f] = | 48 | next_state.r_stick = stick_state.right; |
| 66 | analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 67 | cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 68 | cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 69 | cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 70 | cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 71 | } | 49 | } |
| 72 | 50 | ||
| 73 | std::memcpy(data, &shared_memory, sizeof(SharedMemory)); | 51 | debug_pad_lifo.WriteNextEntry(next_state); |
| 52 | std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); | ||
| 74 | } | 53 | } |
| 75 | 54 | ||
| 76 | void Controller_DebugPad::OnLoadInputDevices() { | ||
| 77 | std::transform(Settings::values.debug_pad_buttons.begin(), | ||
| 78 | Settings::values.debug_pad_buttons.begin() + | ||
| 79 | Settings::NativeButton::NUM_BUTTONS_HID, | ||
| 80 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 81 | std::transform(Settings::values.debug_pad_analogs.begin(), | ||
| 82 | Settings::values.debug_pad_analogs.end(), analogs.begin(), | ||
| 83 | Input::CreateDevice<Input::AnalogDevice>); | ||
| 84 | } | ||
| 85 | } // namespace Service::HID | 55 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 1b1645184..afe374fc2 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h | |||
| @@ -8,15 +8,20 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/settings.h" | ||
| 12 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 13 | #include "core/frontend/input.h" | ||
| 14 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 14 | |||
| 15 | namespace Core::HID { | ||
| 16 | class EmulatedController; | ||
| 17 | struct DebugPadButton; | ||
| 18 | struct AnalogStickState; | ||
| 19 | } // namespace Core::HID | ||
| 15 | 20 | ||
| 16 | namespace Service::HID { | 21 | namespace Service::HID { |
| 17 | class Controller_DebugPad final : public ControllerBase { | 22 | class Controller_DebugPad final : public ControllerBase { |
| 18 | public: | 23 | public: |
| 19 | explicit Controller_DebugPad(Core::System& system_); | 24 | explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); |
| 20 | ~Controller_DebugPad() override; | 25 | ~Controller_DebugPad() override; |
| 21 | 26 | ||
| 22 | // Called when the controller is initialized | 27 | // Called when the controller is initialized |
| @@ -28,66 +33,31 @@ public: | |||
| 28 | // When the controller is requesting an update for the shared memory | 33 | // When the controller is requesting an update for the shared memory |
| 29 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 34 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 30 | 35 | ||
| 31 | // Called when input devices should be loaded | ||
| 32 | void OnLoadInputDevices() override; | ||
| 33 | |||
| 34 | private: | 36 | private: |
| 35 | struct AnalogStick { | 37 | // This is nn::hid::DebugPadAttribute |
| 36 | s32_le x; | 38 | struct DebugPadAttribute { |
| 37 | s32_le y; | ||
| 38 | }; | ||
| 39 | static_assert(sizeof(AnalogStick) == 0x8); | ||
| 40 | |||
| 41 | struct PadState { | ||
| 42 | union { | ||
| 43 | u32_le raw{}; | ||
| 44 | BitField<0, 1, u32> a; | ||
| 45 | BitField<1, 1, u32> b; | ||
| 46 | BitField<2, 1, u32> x; | ||
| 47 | BitField<3, 1, u32> y; | ||
| 48 | BitField<4, 1, u32> l; | ||
| 49 | BitField<5, 1, u32> r; | ||
| 50 | BitField<6, 1, u32> zl; | ||
| 51 | BitField<7, 1, u32> zr; | ||
| 52 | BitField<8, 1, u32> plus; | ||
| 53 | BitField<9, 1, u32> minus; | ||
| 54 | BitField<10, 1, u32> d_left; | ||
| 55 | BitField<11, 1, u32> d_up; | ||
| 56 | BitField<12, 1, u32> d_right; | ||
| 57 | BitField<13, 1, u32> d_down; | ||
| 58 | }; | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); | ||
| 61 | |||
| 62 | struct Attributes { | ||
| 63 | union { | 39 | union { |
| 64 | u32_le raw{}; | 40 | u32 raw{}; |
| 65 | BitField<0, 1, u32> connected; | 41 | BitField<0, 1, u32> connected; |
| 66 | }; | 42 | }; |
| 67 | }; | 43 | }; |
| 68 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | 44 | static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); |
| 69 | 45 | ||
| 70 | struct PadStates { | 46 | // This is nn::hid::DebugPadState |
| 71 | s64_le sampling_number; | 47 | struct DebugPadState { |
| 72 | s64_le sampling_number2; | 48 | s64 sampling_number; |
| 73 | Attributes attribute; | 49 | DebugPadAttribute attribute; |
| 74 | PadState pad_state; | 50 | Core::HID::DebugPadButton pad_state; |
| 75 | AnalogStick r_stick; | 51 | Core::HID::AnalogStickState r_stick; |
| 76 | AnalogStick l_stick; | 52 | Core::HID::AnalogStickState l_stick; |
| 77 | }; | 53 | }; |
| 78 | static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); | 54 | static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); |
| 79 | 55 | ||
| 80 | struct SharedMemory { | 56 | // This is nn::hid::detail::DebugPadLifo |
| 81 | CommonHeader header; | 57 | Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{}; |
| 82 | std::array<PadStates, 17> pad_states; | 58 | static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); |
| 83 | INSERT_PADDING_BYTES(0x138); | 59 | DebugPadState next_state{}; |
| 84 | }; | ||
| 85 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | ||
| 86 | SharedMemory shared_memory{}; | ||
| 87 | 60 | ||
| 88 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> | 61 | Core::HID::EmulatedController* controller; |
| 89 | buttons; | ||
| 90 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> | ||
| 91 | analogs; | ||
| 92 | }; | 62 | }; |
| 93 | } // namespace Service::HID | 63 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 764abb5b6..fe895c4f6 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/frontend/emu_window.h" | 9 | #include "core/frontend/emu_window.h" |
| 10 | #include "core/hid/hid_core.h" | ||
| 10 | #include "core/hle/service/hid/controllers/gesture.h" | 11 | #include "core/hle/service/hid/controllers/gesture.h" |
| 11 | 12 | ||
| 12 | namespace Service::HID { | 13 | namespace Service::HID { |
| @@ -23,16 +24,14 @@ constexpr f32 Square(s32 num) { | |||
| 23 | return static_cast<f32>(num * num); | 24 | return static_cast<f32>(num * num); |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} | 27 | Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { |
| 28 | console = hid_core.GetEmulatedConsole(); | ||
| 29 | } | ||
| 27 | Controller_Gesture::~Controller_Gesture() = default; | 30 | Controller_Gesture::~Controller_Gesture() = default; |
| 28 | 31 | ||
| 29 | void Controller_Gesture::OnInit() { | 32 | void Controller_Gesture::OnInit() { |
| 30 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | 33 | gesture_lifo.buffer_count = 0; |
| 31 | mouse_finger_id[id] = MAX_POINTS; | 34 | gesture_lifo.buffer_tail = 0; |
| 32 | keyboard_finger_id[id] = MAX_POINTS; | ||
| 33 | udp_finger_id[id] = MAX_POINTS; | ||
| 34 | } | ||
| 35 | shared_memory.header.entry_count = 0; | ||
| 36 | force_update = true; | 35 | force_update = true; |
| 37 | } | 36 | } |
| 38 | 37 | ||
| @@ -40,50 +39,38 @@ void Controller_Gesture::OnRelease() {} | |||
| 40 | 39 | ||
| 41 | void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 40 | void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 42 | std::size_t size) { | 41 | std::size_t size) { |
| 43 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | ||
| 44 | shared_memory.header.total_entry_count = 17; | ||
| 45 | |||
| 46 | if (!IsControllerActivated()) { | 42 | if (!IsControllerActivated()) { |
| 47 | shared_memory.header.entry_count = 0; | 43 | gesture_lifo.buffer_count = 0; |
| 48 | shared_memory.header.last_entry_index = 0; | 44 | gesture_lifo.buffer_tail = 0; |
| 45 | std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); | ||
| 49 | return; | 46 | return; |
| 50 | } | 47 | } |
| 51 | 48 | ||
| 52 | ReadTouchInput(); | 49 | ReadTouchInput(); |
| 53 | 50 | ||
| 54 | GestureProperties gesture = GetGestureProperties(); | 51 | GestureProperties gesture = GetGestureProperties(); |
| 55 | f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / | 52 | f32 time_difference = |
| 56 | (1000 * 1000 * 1000); | 53 | static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); |
| 57 | 54 | ||
| 58 | // Only update if necesary | 55 | // Only update if necesary |
| 59 | if (!ShouldUpdateGesture(gesture, time_difference)) { | 56 | if (!ShouldUpdateGesture(gesture, time_difference)) { |
| 60 | return; | 57 | return; |
| 61 | } | 58 | } |
| 62 | 59 | ||
| 63 | last_update_timestamp = shared_memory.header.timestamp; | 60 | last_update_timestamp = gesture_lifo.timestamp; |
| 64 | UpdateGestureSharedMemory(data, size, gesture, time_difference); | 61 | UpdateGestureSharedMemory(data, size, gesture, time_difference); |
| 65 | } | 62 | } |
| 66 | 63 | ||
| 67 | void Controller_Gesture::ReadTouchInput() { | 64 | void Controller_Gesture::ReadTouchInput() { |
| 68 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 65 | const auto touch_status = console->GetTouch(); |
| 69 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 66 | for (std::size_t id = 0; id < fingers.size(); ++id) { |
| 70 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 67 | fingers[id] = touch_status[id]; |
| 71 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); | ||
| 72 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); | ||
| 73 | } | ||
| 74 | |||
| 75 | if (Settings::values.use_touch_from_button) { | ||
| 76 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); | ||
| 77 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | ||
| 78 | keyboard_finger_id[id] = | ||
| 79 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | ||
| 80 | } | ||
| 81 | } | 68 | } |
| 82 | } | 69 | } |
| 83 | 70 | ||
| 84 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | 71 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, |
| 85 | f32 time_difference) { | 72 | f32 time_difference) { |
| 86 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 73 | const auto& last_entry = GetLastGestureEntry(); |
| 87 | if (force_update) { | 74 | if (force_update) { |
| 88 | force_update = false; | 75 | force_update = false; |
| 89 | return true; | 76 | return true; |
| @@ -97,7 +84,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 97 | } | 84 | } |
| 98 | 85 | ||
| 99 | // Update on press and hold event after 0.5 seconds | 86 | // Update on press and hold event after 0.5 seconds |
| 100 | if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && | 87 | if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && |
| 101 | time_difference > press_delay) { | 88 | time_difference > press_delay) { |
| 102 | return enable_press_and_tap; | 89 | return enable_press_and_tap; |
| 103 | } | 90 | } |
| @@ -108,27 +95,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 108 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | 95 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, |
| 109 | GestureProperties& gesture, | 96 | GestureProperties& gesture, |
| 110 | f32 time_difference) { | 97 | f32 time_difference) { |
| 111 | TouchType type = TouchType::Idle; | 98 | GestureType type = GestureType::Idle; |
| 112 | Attribute attributes{}; | 99 | GestureAttribute attributes{}; |
| 113 | 100 | ||
| 114 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 101 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 115 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 116 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 117 | 102 | ||
| 118 | if (shared_memory.header.entry_count < 16) { | 103 | // Reset next state to default |
| 119 | shared_memory.header.entry_count++; | 104 | next_state.sampling_number = last_entry.sampling_number + 1; |
| 120 | } | 105 | next_state.delta = {}; |
| 121 | 106 | next_state.vel_x = 0; | |
| 122 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 107 | next_state.vel_y = 0; |
| 123 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 108 | next_state.direction = GestureDirection::None; |
| 124 | 109 | next_state.rotation_angle = 0; | |
| 125 | // Reset values to default | 110 | next_state.scale = 0; |
| 126 | cur_entry.delta = {}; | ||
| 127 | cur_entry.vel_x = 0; | ||
| 128 | cur_entry.vel_y = 0; | ||
| 129 | cur_entry.direction = Direction::None; | ||
| 130 | cur_entry.rotation_angle = 0; | ||
| 131 | cur_entry.scale = 0; | ||
| 132 | 111 | ||
| 133 | if (gesture.active_points > 0) { | 112 | if (gesture.active_points > 0) { |
| 134 | if (last_gesture.active_points == 0) { | 113 | if (last_gesture.active_points == 0) { |
| @@ -141,46 +120,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | |||
| 141 | } | 120 | } |
| 142 | 121 | ||
| 143 | // Apply attributes | 122 | // Apply attributes |
| 144 | cur_entry.detection_count = gesture.detection_count; | 123 | next_state.detection_count = gesture.detection_count; |
| 145 | cur_entry.type = type; | 124 | next_state.type = type; |
| 146 | cur_entry.attributes = attributes; | 125 | next_state.attributes = attributes; |
| 147 | cur_entry.pos = gesture.mid_point; | 126 | next_state.pos = gesture.mid_point; |
| 148 | cur_entry.point_count = static_cast<s32>(gesture.active_points); | 127 | next_state.point_count = static_cast<s32>(gesture.active_points); |
| 149 | cur_entry.points = gesture.points; | 128 | next_state.points = gesture.points; |
| 150 | last_gesture = gesture; | 129 | last_gesture = gesture; |
| 151 | 130 | ||
| 152 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 131 | gesture_lifo.WriteNextEntry(next_state); |
| 132 | std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); | ||
| 153 | } | 133 | } |
| 154 | 134 | ||
| 155 | void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, | 135 | void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, |
| 156 | Attribute& attributes) { | 136 | GestureAttribute& attributes) { |
| 157 | const auto& last_entry = GetLastGestureEntry(); | 137 | const auto& last_entry = GetLastGestureEntry(); |
| 158 | 138 | ||
| 159 | gesture.detection_count++; | 139 | gesture.detection_count++; |
| 160 | type = TouchType::Touch; | 140 | type = GestureType::Touch; |
| 161 | 141 | ||
| 162 | // New touch after cancel is not considered new | 142 | // New touch after cancel is not considered new |
| 163 | if (last_entry.type != TouchType::Cancel) { | 143 | if (last_entry.type != GestureType::Cancel) { |
| 164 | attributes.is_new_touch.Assign(1); | 144 | attributes.is_new_touch.Assign(1); |
| 165 | enable_press_and_tap = true; | 145 | enable_press_and_tap = true; |
| 166 | } | 146 | } |
| 167 | } | 147 | } |
| 168 | 148 | ||
| 169 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, | 149 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, |
| 170 | f32 time_difference) { | 150 | f32 time_difference) { |
| 171 | const auto& last_entry = GetLastGestureEntry(); | 151 | const auto& last_entry = GetLastGestureEntry(); |
| 172 | 152 | ||
| 173 | // Promote to pan type if touch moved | 153 | // Promote to pan type if touch moved |
| 174 | for (size_t id = 0; id < MAX_POINTS; id++) { | 154 | for (size_t id = 0; id < MAX_POINTS; id++) { |
| 175 | if (gesture.points[id] != last_gesture.points[id]) { | 155 | if (gesture.points[id] != last_gesture.points[id]) { |
| 176 | type = TouchType::Pan; | 156 | type = GestureType::Pan; |
| 177 | break; | 157 | break; |
| 178 | } | 158 | } |
| 179 | } | 159 | } |
| 180 | 160 | ||
| 181 | // Number of fingers changed cancel the last event and clear data | 161 | // Number of fingers changed cancel the last event and clear data |
| 182 | if (gesture.active_points != last_gesture.active_points) { | 162 | if (gesture.active_points != last_gesture.active_points) { |
| 183 | type = TouchType::Cancel; | 163 | type = GestureType::Cancel; |
| 184 | enable_press_and_tap = false; | 164 | enable_press_and_tap = false; |
| 185 | gesture.active_points = 0; | 165 | gesture.active_points = 0; |
| 186 | gesture.mid_point = {}; | 166 | gesture.mid_point = {}; |
| @@ -189,41 +169,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch | |||
| 189 | } | 169 | } |
| 190 | 170 | ||
| 191 | // Calculate extra parameters of panning | 171 | // Calculate extra parameters of panning |
| 192 | if (type == TouchType::Pan) { | 172 | if (type == GestureType::Pan) { |
| 193 | UpdatePanEvent(gesture, last_gesture, type, time_difference); | 173 | UpdatePanEvent(gesture, last_gesture, type, time_difference); |
| 194 | return; | 174 | return; |
| 195 | } | 175 | } |
| 196 | 176 | ||
| 197 | // Promote to press type | 177 | // Promote to press type |
| 198 | if (last_entry.type == TouchType::Touch) { | 178 | if (last_entry.type == GestureType::Touch) { |
| 199 | type = TouchType::Press; | 179 | type = GestureType::Press; |
| 200 | } | 180 | } |
| 201 | } | 181 | } |
| 202 | 182 | ||
| 203 | void Controller_Gesture::EndGesture(GestureProperties& gesture, | 183 | void Controller_Gesture::EndGesture(GestureProperties& gesture, |
| 204 | GestureProperties& last_gesture_props, TouchType& type, | 184 | GestureProperties& last_gesture_props, GestureType& type, |
| 205 | Attribute& attributes, f32 time_difference) { | 185 | GestureAttribute& attributes, f32 time_difference) { |
| 206 | const auto& last_entry = GetLastGestureEntry(); | 186 | const auto& last_entry = GetLastGestureEntry(); |
| 207 | 187 | ||
| 208 | if (last_gesture_props.active_points != 0) { | 188 | if (last_gesture_props.active_points != 0) { |
| 209 | switch (last_entry.type) { | 189 | switch (last_entry.type) { |
| 210 | case TouchType::Touch: | 190 | case GestureType::Touch: |
| 211 | if (enable_press_and_tap) { | 191 | if (enable_press_and_tap) { |
| 212 | SetTapEvent(gesture, last_gesture_props, type, attributes); | 192 | SetTapEvent(gesture, last_gesture_props, type, attributes); |
| 213 | return; | 193 | return; |
| 214 | } | 194 | } |
| 215 | type = TouchType::Cancel; | 195 | type = GestureType::Cancel; |
| 216 | force_update = true; | 196 | force_update = true; |
| 217 | break; | 197 | break; |
| 218 | case TouchType::Press: | 198 | case GestureType::Press: |
| 219 | case TouchType::Tap: | 199 | case GestureType::Tap: |
| 220 | case TouchType::Swipe: | 200 | case GestureType::Swipe: |
| 221 | case TouchType::Pinch: | 201 | case GestureType::Pinch: |
| 222 | case TouchType::Rotate: | 202 | case GestureType::Rotate: |
| 223 | type = TouchType::Complete; | 203 | type = GestureType::Complete; |
| 224 | force_update = true; | 204 | force_update = true; |
| 225 | break; | 205 | break; |
| 226 | case TouchType::Pan: | 206 | case GestureType::Pan: |
| 227 | EndPanEvent(gesture, last_gesture_props, type, time_difference); | 207 | EndPanEvent(gesture, last_gesture_props, type, time_difference); |
| 228 | break; | 208 | break; |
| 229 | default: | 209 | default: |
| @@ -231,15 +211,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, | |||
| 231 | } | 211 | } |
| 232 | return; | 212 | return; |
| 233 | } | 213 | } |
| 234 | if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { | 214 | if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { |
| 235 | gesture.detection_count++; | 215 | gesture.detection_count++; |
| 236 | } | 216 | } |
| 237 | } | 217 | } |
| 238 | 218 | ||
| 239 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, | 219 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, |
| 240 | GestureProperties& last_gesture_props, TouchType& type, | 220 | GestureProperties& last_gesture_props, GestureType& type, |
| 241 | Attribute& attributes) { | 221 | GestureAttribute& attributes) { |
| 242 | type = TouchType::Tap; | 222 | type = GestureType::Tap; |
| 243 | gesture = last_gesture_props; | 223 | gesture = last_gesture_props; |
| 244 | force_update = true; | 224 | force_update = true; |
| 245 | f32 tap_time_difference = | 225 | f32 tap_time_difference = |
| @@ -251,44 +231,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, | |||
| 251 | } | 231 | } |
| 252 | 232 | ||
| 253 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, | 233 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, |
| 254 | GestureProperties& last_gesture_props, TouchType& type, | 234 | GestureProperties& last_gesture_props, GestureType& type, |
| 255 | f32 time_difference) { | 235 | f32 time_difference) { |
| 256 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 257 | const auto& last_entry = GetLastGestureEntry(); | 236 | const auto& last_entry = GetLastGestureEntry(); |
| 258 | 237 | ||
| 259 | cur_entry.delta = gesture.mid_point - last_entry.pos; | 238 | next_state.delta = gesture.mid_point - last_entry.pos; |
| 260 | cur_entry.vel_x = static_cast<f32>(cur_entry.delta.x) / time_difference; | 239 | next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; |
| 261 | cur_entry.vel_y = static_cast<f32>(cur_entry.delta.y) / time_difference; | 240 | next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; |
| 262 | last_pan_time_difference = time_difference; | 241 | last_pan_time_difference = time_difference; |
| 263 | 242 | ||
| 264 | // Promote to pinch type | 243 | // Promote to pinch type |
| 265 | if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > | 244 | if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > |
| 266 | pinch_threshold) { | 245 | pinch_threshold) { |
| 267 | type = TouchType::Pinch; | 246 | type = GestureType::Pinch; |
| 268 | cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; | 247 | next_state.scale = gesture.average_distance / last_gesture_props.average_distance; |
| 269 | } | 248 | } |
| 270 | 249 | ||
| 271 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / | 250 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / |
| 272 | (1 + (gesture.angle * last_gesture_props.angle))); | 251 | (1 + (gesture.angle * last_gesture_props.angle))); |
| 273 | // Promote to rotate type | 252 | // Promote to rotate type |
| 274 | if (std::abs(angle_between_two_lines) > angle_threshold) { | 253 | if (std::abs(angle_between_two_lines) > angle_threshold) { |
| 275 | type = TouchType::Rotate; | 254 | type = GestureType::Rotate; |
| 276 | cur_entry.scale = 0; | 255 | next_state.scale = 0; |
| 277 | cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; | 256 | next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; |
| 278 | } | 257 | } |
| 279 | } | 258 | } |
| 280 | 259 | ||
| 281 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, | 260 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, |
| 282 | GestureProperties& last_gesture_props, TouchType& type, | 261 | GestureProperties& last_gesture_props, GestureType& type, |
| 283 | f32 time_difference) { | 262 | f32 time_difference) { |
| 284 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 285 | const auto& last_entry = GetLastGestureEntry(); | 263 | const auto& last_entry = GetLastGestureEntry(); |
| 286 | cur_entry.vel_x = | 264 | next_state.vel_x = |
| 287 | static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); | 265 | static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); |
| 288 | cur_entry.vel_y = | 266 | next_state.vel_y = |
| 289 | static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); | 267 | static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); |
| 290 | const f32 curr_vel = | 268 | const f32 curr_vel = |
| 291 | std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); | 269 | std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); |
| 292 | 270 | ||
| 293 | // Set swipe event with parameters | 271 | // Set swipe event with parameters |
| 294 | if (curr_vel > swipe_threshold) { | 272 | if (curr_vel > swipe_threshold) { |
| @@ -297,105 +275,50 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, | |||
| 297 | } | 275 | } |
| 298 | 276 | ||
| 299 | // End panning without swipe | 277 | // End panning without swipe |
| 300 | type = TouchType::Complete; | 278 | type = GestureType::Complete; |
| 301 | cur_entry.vel_x = 0; | 279 | next_state.vel_x = 0; |
| 302 | cur_entry.vel_y = 0; | 280 | next_state.vel_y = 0; |
| 303 | force_update = true; | 281 | force_update = true; |
| 304 | } | 282 | } |
| 305 | 283 | ||
| 306 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, | 284 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, |
| 307 | GestureProperties& last_gesture_props, TouchType& type) { | 285 | GestureProperties& last_gesture_props, GestureType& type) { |
| 308 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 309 | const auto& last_entry = GetLastGestureEntry(); | 286 | const auto& last_entry = GetLastGestureEntry(); |
| 310 | 287 | ||
| 311 | type = TouchType::Swipe; | 288 | type = GestureType::Swipe; |
| 312 | gesture = last_gesture_props; | 289 | gesture = last_gesture_props; |
| 313 | force_update = true; | 290 | force_update = true; |
| 314 | cur_entry.delta = last_entry.delta; | 291 | next_state.delta = last_entry.delta; |
| 315 | 292 | ||
| 316 | if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { | 293 | if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { |
| 317 | if (cur_entry.delta.x > 0) { | 294 | if (next_state.delta.x > 0) { |
| 318 | cur_entry.direction = Direction::Right; | 295 | next_state.direction = GestureDirection::Right; |
| 319 | return; | 296 | return; |
| 320 | } | 297 | } |
| 321 | cur_entry.direction = Direction::Left; | 298 | next_state.direction = GestureDirection::Left; |
| 322 | return; | 299 | return; |
| 323 | } | 300 | } |
| 324 | if (cur_entry.delta.y > 0) { | 301 | if (next_state.delta.y > 0) { |
| 325 | cur_entry.direction = Direction::Down; | 302 | next_state.direction = GestureDirection::Down; |
| 326 | return; | 303 | return; |
| 327 | } | 304 | } |
| 328 | cur_entry.direction = Direction::Up; | 305 | next_state.direction = GestureDirection::Up; |
| 329 | } | ||
| 330 | |||
| 331 | void Controller_Gesture::OnLoadInputDevices() { | ||
| 332 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | ||
| 333 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | ||
| 334 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | ||
| 335 | } | ||
| 336 | |||
| 337 | std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const { | ||
| 338 | // Dont assign any touch input to a point if disabled | ||
| 339 | if (!Settings::values.touchscreen.enabled) { | ||
| 340 | return std::nullopt; | ||
| 341 | } | ||
| 342 | std::size_t first_free_id = 0; | ||
| 343 | while (first_free_id < MAX_POINTS) { | ||
| 344 | if (!fingers[first_free_id].pressed) { | ||
| 345 | return first_free_id; | ||
| 346 | } else { | ||
| 347 | first_free_id++; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | return std::nullopt; | ||
| 351 | } | ||
| 352 | |||
| 353 | Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { | ||
| 354 | return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 355 | } | 306 | } |
| 356 | 307 | ||
| 357 | const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { | 308 | const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { |
| 358 | return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | 309 | return gesture_lifo.ReadCurrentEntry().state; |
| 359 | } | ||
| 360 | |||
| 361 | std::size_t Controller_Gesture::UpdateTouchInputEvent( | ||
| 362 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 363 | const auto& [x, y, pressed] = touch_input; | ||
| 364 | if (finger_id > MAX_POINTS) { | ||
| 365 | LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||
| 366 | return MAX_POINTS; | ||
| 367 | } | ||
| 368 | if (pressed) { | ||
| 369 | if (finger_id == MAX_POINTS) { | ||
| 370 | const auto first_free_id = GetUnusedFingerID(); | ||
| 371 | if (!first_free_id) { | ||
| 372 | // Invalid finger id do nothing | ||
| 373 | return MAX_POINTS; | ||
| 374 | } | ||
| 375 | finger_id = first_free_id.value(); | ||
| 376 | fingers[finger_id].pressed = true; | ||
| 377 | } | ||
| 378 | fingers[finger_id].pos = {x, y}; | ||
| 379 | return finger_id; | ||
| 380 | } | ||
| 381 | |||
| 382 | if (finger_id != MAX_POINTS) { | ||
| 383 | fingers[finger_id].pressed = false; | ||
| 384 | } | ||
| 385 | |||
| 386 | return MAX_POINTS; | ||
| 387 | } | 310 | } |
| 388 | 311 | ||
| 389 | Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { | 312 | Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { |
| 390 | GestureProperties gesture; | 313 | GestureProperties gesture; |
| 391 | std::array<Finger, MAX_POINTS> active_fingers; | 314 | std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; |
| 392 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | 315 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), |
| 393 | [](const auto& finger) { return finger.pressed; }); | 316 | [](const auto& finger) { return finger.pressed; }); |
| 394 | gesture.active_points = | 317 | gesture.active_points = |
| 395 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | 318 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); |
| 396 | 319 | ||
| 397 | for (size_t id = 0; id < gesture.active_points; ++id) { | 320 | for (size_t id = 0; id < gesture.active_points; ++id) { |
| 398 | const auto& [active_x, active_y] = active_fingers[id].pos; | 321 | const auto& [active_x, active_y] = active_fingers[id].position; |
| 399 | gesture.points[id] = { | 322 | gesture.points[id] = { |
| 400 | .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), | 323 | .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), |
| 401 | .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), | 324 | .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7e7ae6625..0936a3fa3 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -8,13 +8,14 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/point.h" | 10 | #include "common/point.h" |
| 11 | #include "core/frontend/input.h" | 11 | #include "core/hid/emulated_console.h" |
| 12 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 13 | 14 | ||
| 14 | namespace Service::HID { | 15 | namespace Service::HID { |
| 15 | class Controller_Gesture final : public ControllerBase { | 16 | class Controller_Gesture final : public ControllerBase { |
| 16 | public: | 17 | public: |
| 17 | explicit Controller_Gesture(Core::System& system_); | 18 | explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); |
| 18 | ~Controller_Gesture() override; | 19 | ~Controller_Gesture() override; |
| 19 | 20 | ||
| 20 | // Called when the controller is initialized | 21 | // Called when the controller is initialized |
| @@ -26,14 +27,12 @@ public: | |||
| 26 | // When the controller is requesting an update for the shared memory | 27 | // When the controller is requesting an update for the shared memory |
| 27 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; | 28 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; |
| 28 | 29 | ||
| 29 | // Called when input devices should be loaded | ||
| 30 | void OnLoadInputDevices() override; | ||
| 31 | |||
| 32 | private: | 30 | private: |
| 33 | static constexpr size_t MAX_FINGERS = 16; | 31 | static constexpr size_t MAX_FINGERS = 16; |
| 34 | static constexpr size_t MAX_POINTS = 4; | 32 | static constexpr size_t MAX_POINTS = 4; |
| 35 | 33 | ||
| 36 | enum class TouchType : u32 { | 34 | // This is nn::hid::GestureType |
| 35 | enum class GestureType : u32 { | ||
| 37 | Idle, // Nothing touching the screen | 36 | Idle, // Nothing touching the screen |
| 38 | Complete, // Set at the end of a touch event | 37 | Complete, // Set at the end of a touch event |
| 39 | Cancel, // Set when the number of fingers change | 38 | Cancel, // Set when the number of fingers change |
| @@ -46,7 +45,8 @@ private: | |||
| 46 | Rotate, // All points rotating from the midpoint | 45 | Rotate, // All points rotating from the midpoint |
| 47 | }; | 46 | }; |
| 48 | 47 | ||
| 49 | enum class Direction : u32 { | 48 | // This is nn::hid::GestureDirection |
| 49 | enum class GestureDirection : u32 { | ||
| 50 | None, | 50 | None, |
| 51 | Left, | 51 | Left, |
| 52 | Up, | 52 | Up, |
| @@ -54,51 +54,41 @@ private: | |||
| 54 | Down, | 54 | Down, |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | struct Attribute { | 57 | // This is nn::hid::GestureAttribute |
| 58 | struct GestureAttribute { | ||
| 58 | union { | 59 | union { |
| 59 | u32_le raw{}; | 60 | u32 raw{}; |
| 60 | 61 | ||
| 61 | BitField<4, 1, u32> is_new_touch; | 62 | BitField<4, 1, u32> is_new_touch; |
| 62 | BitField<8, 1, u32> is_double_tap; | 63 | BitField<8, 1, u32> is_double_tap; |
| 63 | }; | 64 | }; |
| 64 | }; | 65 | }; |
| 65 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); | 66 | static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); |
| 66 | 67 | ||
| 68 | // This is nn::hid::GestureState | ||
| 67 | struct GestureState { | 69 | struct GestureState { |
| 68 | s64_le sampling_number; | 70 | s64 sampling_number; |
| 69 | s64_le sampling_number2; | 71 | s64 detection_count; |
| 70 | s64_le detection_count; | 72 | GestureType type; |
| 71 | TouchType type; | 73 | GestureDirection direction; |
| 72 | Direction direction; | 74 | Common::Point<s32> pos; |
| 73 | Common::Point<s32_le> pos; | 75 | Common::Point<s32> delta; |
| 74 | Common::Point<s32_le> delta; | ||
| 75 | f32 vel_x; | 76 | f32 vel_x; |
| 76 | f32 vel_y; | 77 | f32 vel_y; |
| 77 | Attribute attributes; | 78 | GestureAttribute attributes; |
| 78 | f32 scale; | 79 | f32 scale; |
| 79 | f32 rotation_angle; | 80 | f32 rotation_angle; |
| 80 | s32_le point_count; | 81 | s32 point_count; |
| 81 | std::array<Common::Point<s32_le>, 4> points; | 82 | std::array<Common::Point<s32>, 4> points; |
| 82 | }; | ||
| 83 | static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); | ||
| 84 | |||
| 85 | struct SharedMemory { | ||
| 86 | CommonHeader header; | ||
| 87 | std::array<GestureState, 17> gesture_states; | ||
| 88 | }; | ||
| 89 | static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); | ||
| 90 | |||
| 91 | struct Finger { | ||
| 92 | Common::Point<f32> pos{}; | ||
| 93 | bool pressed{}; | ||
| 94 | }; | 83 | }; |
| 84 | static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); | ||
| 95 | 85 | ||
| 96 | struct GestureProperties { | 86 | struct GestureProperties { |
| 97 | std::array<Common::Point<s32_le>, MAX_POINTS> points{}; | 87 | std::array<Common::Point<s32>, MAX_POINTS> points{}; |
| 98 | std::size_t active_points{}; | 88 | std::size_t active_points{}; |
| 99 | Common::Point<s32_le> mid_point{}; | 89 | Common::Point<s32> mid_point{}; |
| 100 | s64_le detection_count{}; | 90 | s64 detection_count{}; |
| 101 | u64_le delta_time{}; | 91 | u64 delta_time{}; |
| 102 | f32 average_distance{}; | 92 | f32 average_distance{}; |
| 103 | f32 angle{}; | 93 | f32 angle{}; |
| 104 | }; | 94 | }; |
| @@ -114,61 +104,48 @@ private: | |||
| 114 | f32 time_difference); | 104 | f32 time_difference); |
| 115 | 105 | ||
| 116 | // Initializes new gesture | 106 | // Initializes new gesture |
| 117 | void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); | 107 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); |
| 118 | 108 | ||
| 119 | // Updates existing gesture state | 109 | // Updates existing gesture state |
| 120 | void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); | 110 | void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); |
| 121 | 111 | ||
| 122 | // Terminates exiting gesture | 112 | // Terminates exiting gesture |
| 123 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, | 113 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 124 | TouchType& type, Attribute& attributes, f32 time_difference); | 114 | GestureType& type, GestureAttribute& attributes, f32 time_difference); |
| 125 | 115 | ||
| 126 | // Set current event to a tap event | 116 | // Set current event to a tap event |
| 127 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 117 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 128 | TouchType& type, Attribute& attributes); | 118 | GestureType& type, GestureAttribute& attributes); |
| 129 | 119 | ||
| 130 | // Calculates and set the extra parameters related to a pan event | 120 | // Calculates and set the extra parameters related to a pan event |
| 131 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 121 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 132 | TouchType& type, f32 time_difference); | 122 | GestureType& type, f32 time_difference); |
| 133 | 123 | ||
| 134 | // Terminates the pan event | 124 | // Terminates the pan event |
| 135 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 125 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 136 | TouchType& type, f32 time_difference); | 126 | GestureType& type, f32 time_difference); |
| 137 | 127 | ||
| 138 | // Set current event to a swipe event | 128 | // Set current event to a swipe event |
| 139 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 129 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 140 | TouchType& type); | 130 | GestureType& type); |
| 141 | |||
| 142 | // Returns an unused finger id, if there is no fingers available std::nullopt is returned. | ||
| 143 | [[nodiscard]] std::optional<size_t> GetUnusedFingerID() const; | ||
| 144 | 131 | ||
| 145 | // Retrieves the last gesture entry, as indicated by shared memory indices. | 132 | // Retrieves the last gesture entry, as indicated by shared memory indices. |
| 146 | [[nodiscard]] GestureState& GetLastGestureEntry(); | ||
| 147 | [[nodiscard]] const GestureState& GetLastGestureEntry() const; | 133 | [[nodiscard]] const GestureState& GetLastGestureEntry() const; |
| 148 | 134 | ||
| 149 | /** | ||
| 150 | * If the touch is new it tries to assign a new finger id, if there is no fingers available no | ||
| 151 | * changes will be made. Updates the coordinates if the finger id it's already set. If the touch | ||
| 152 | * ends delays the output by one frame to set the end_touch flag before finally freeing the | ||
| 153 | * finger id | ||
| 154 | */ | ||
| 155 | size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 156 | size_t finger_id); | ||
| 157 | |||
| 158 | // Returns the average distance, angle and middle point of the active fingers | 135 | // Returns the average distance, angle and middle point of the active fingers |
| 159 | GestureProperties GetGestureProperties(); | 136 | GestureProperties GetGestureProperties(); |
| 160 | 137 | ||
| 161 | SharedMemory shared_memory{}; | 138 | // This is nn::hid::detail::GestureLifo |
| 162 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; | 139 | Lifo<GestureState, hid_entry_count> gesture_lifo{}; |
| 163 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | 140 | static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); |
| 164 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 141 | GestureState next_state{}; |
| 165 | std::array<size_t, MAX_FINGERS> mouse_finger_id{}; | 142 | |
| 166 | std::array<size_t, MAX_FINGERS> keyboard_finger_id{}; | 143 | Core::HID::EmulatedConsole* console; |
| 167 | std::array<size_t, MAX_FINGERS> udp_finger_id{}; | 144 | |
| 168 | std::array<Finger, MAX_POINTS> fingers{}; | 145 | std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; |
| 169 | GestureProperties last_gesture{}; | 146 | GestureProperties last_gesture{}; |
| 170 | s64_le last_update_timestamp{}; | 147 | s64 last_update_timestamp{}; |
| 171 | s64_le last_tap_timestamp{}; | 148 | s64 last_tap_timestamp{}; |
| 172 | f32 last_pan_time_difference{}; | 149 | f32 last_pan_time_difference{}; |
| 173 | bool force_update{false}; | 150 | bool force_update{false}; |
| 174 | bool enable_press_and_tap{false}; | 151 | bool enable_press_and_tap{false}; |
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index c6c620008..9588a6910 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp | |||
| @@ -6,13 +6,18 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/hid/emulated_devices.h" | ||
| 10 | #include "core/hid/hid_core.h" | ||
| 9 | #include "core/hle/service/hid/controllers/keyboard.h" | 11 | #include "core/hle/service/hid/controllers/keyboard.h" |
| 10 | 12 | ||
| 11 | namespace Service::HID { | 13 | namespace Service::HID { |
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; | 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; |
| 13 | constexpr u8 KEYS_PER_BYTE = 8; | ||
| 14 | 15 | ||
| 15 | Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {} | 16 | Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) |
| 17 | : ControllerBase{hid_core_} { | ||
| 18 | emulated_devices = hid_core.GetEmulatedDevices(); | ||
| 19 | } | ||
| 20 | |||
| 16 | Controller_Keyboard::~Controller_Keyboard() = default; | 21 | Controller_Keyboard::~Controller_Keyboard() = default; |
| 17 | 22 | ||
| 18 | void Controller_Keyboard::OnInit() {} | 23 | void Controller_Keyboard::OnInit() {} |
| @@ -21,51 +26,27 @@ void Controller_Keyboard::OnRelease() {} | |||
| 21 | 26 | ||
| 22 | void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 27 | void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 23 | std::size_t size) { | 28 | std::size_t size) { |
| 24 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | ||
| 25 | shared_memory.header.total_entry_count = 17; | ||
| 26 | |||
| 27 | if (!IsControllerActivated()) { | 29 | if (!IsControllerActivated()) { |
| 28 | shared_memory.header.entry_count = 0; | 30 | keyboard_lifo.buffer_count = 0; |
| 29 | shared_memory.header.last_entry_index = 0; | 31 | keyboard_lifo.buffer_tail = 0; |
| 32 | std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); | ||
| 30 | return; | 33 | return; |
| 31 | } | 34 | } |
| 32 | shared_memory.header.entry_count = 16; | ||
| 33 | |||
| 34 | const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 35 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 36 | auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; | ||
| 37 | 35 | ||
| 38 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 36 | const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; |
| 39 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 37 | next_state.sampling_number = last_entry.sampling_number + 1; |
| 40 | 38 | ||
| 41 | cur_entry.key.fill(0); | ||
| 42 | if (Settings::values.keyboard_enabled) { | 39 | if (Settings::values.keyboard_enabled) { |
| 43 | for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { | 40 | const auto& keyboard_state = emulated_devices->GetKeyboard(); |
| 44 | auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; | 41 | const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier(); |
| 45 | entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); | ||
| 46 | } | ||
| 47 | 42 | ||
| 48 | using namespace Settings::NativeKeyboard; | 43 | next_state.key = keyboard_state; |
| 49 | 44 | next_state.modifier = keyboard_modifier_state; | |
| 50 | // TODO: Assign the correct key to all modifiers | 45 | next_state.attribute.is_connected.Assign(1); |
| 51 | cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus()); | ||
| 52 | cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus()); | ||
| 53 | cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus()); | ||
| 54 | cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus()); | ||
| 55 | cur_entry.modifier.gui.Assign(0); | ||
| 56 | cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus()); | ||
| 57 | cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus()); | ||
| 58 | cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus()); | ||
| 59 | cur_entry.modifier.katakana.Assign(0); | ||
| 60 | cur_entry.modifier.hiragana.Assign(0); | ||
| 61 | } | 46 | } |
| 62 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | ||
| 63 | } | ||
| 64 | 47 | ||
| 65 | void Controller_Keyboard::OnLoadInputDevices() { | 48 | keyboard_lifo.WriteNextEntry(next_state); |
| 66 | std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), | 49 | std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); |
| 67 | keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 68 | std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), | ||
| 69 | keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 70 | } | 50 | } |
| 51 | |||
| 71 | } // namespace Service::HID | 52 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 172a80e9c..cf62d3896 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h | |||
| @@ -8,15 +8,20 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/settings.h" | ||
| 12 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 13 | #include "core/frontend/input.h" | ||
| 14 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 14 | |||
| 15 | namespace Core::HID { | ||
| 16 | class EmulatedDevices; | ||
| 17 | struct KeyboardModifier; | ||
| 18 | struct KeyboardKey; | ||
| 19 | } // namespace Core::HID | ||
| 15 | 20 | ||
| 16 | namespace Service::HID { | 21 | namespace Service::HID { |
| 17 | class Controller_Keyboard final : public ControllerBase { | 22 | class Controller_Keyboard final : public ControllerBase { |
| 18 | public: | 23 | public: |
| 19 | explicit Controller_Keyboard(Core::System& system_); | 24 | explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); |
| 20 | ~Controller_Keyboard() override; | 25 | ~Controller_Keyboard() override; |
| 21 | 26 | ||
| 22 | // Called when the controller is initialized | 27 | // Called when the controller is initialized |
| @@ -28,47 +33,21 @@ public: | |||
| 28 | // When the controller is requesting an update for the shared memory | 33 | // When the controller is requesting an update for the shared memory |
| 29 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 34 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 30 | 35 | ||
| 31 | // Called when input devices should be loaded | ||
| 32 | void OnLoadInputDevices() override; | ||
| 33 | |||
| 34 | private: | 36 | private: |
| 35 | struct Modifiers { | 37 | // This is nn::hid::detail::KeyboardState |
| 36 | union { | ||
| 37 | u32_le raw{}; | ||
| 38 | BitField<0, 1, u32> control; | ||
| 39 | BitField<1, 1, u32> shift; | ||
| 40 | BitField<2, 1, u32> left_alt; | ||
| 41 | BitField<3, 1, u32> right_alt; | ||
| 42 | BitField<4, 1, u32> gui; | ||
| 43 | BitField<8, 1, u32> caps_lock; | ||
| 44 | BitField<9, 1, u32> scroll_lock; | ||
| 45 | BitField<10, 1, u32> num_lock; | ||
| 46 | BitField<11, 1, u32> katakana; | ||
| 47 | BitField<12, 1, u32> hiragana; | ||
| 48 | }; | ||
| 49 | }; | ||
| 50 | static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size"); | ||
| 51 | |||
| 52 | struct KeyboardState { | 38 | struct KeyboardState { |
| 53 | s64_le sampling_number; | 39 | s64 sampling_number; |
| 54 | s64_le sampling_number2; | 40 | Core::HID::KeyboardModifier modifier; |
| 55 | 41 | Core::HID::KeyboardAttribute attribute; | |
| 56 | Modifiers modifier; | 42 | Core::HID::KeyboardKey key; |
| 57 | std::array<u8, 32> key; | ||
| 58 | }; | 43 | }; |
| 59 | static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); | 44 | static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); |
| 60 | 45 | ||
| 61 | struct SharedMemory { | 46 | // This is nn::hid::detail::KeyboardLifo |
| 62 | CommonHeader header; | 47 | Lifo<KeyboardState, hid_entry_count> keyboard_lifo{}; |
| 63 | std::array<KeyboardState, 17> pad_states; | 48 | static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); |
| 64 | INSERT_PADDING_BYTES(0x28); | 49 | KeyboardState next_state{}; |
| 65 | }; | ||
| 66 | static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); | ||
| 67 | SharedMemory shared_memory{}; | ||
| 68 | 50 | ||
| 69 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys> | 51 | Core::HID::EmulatedDevices* emulated_devices; |
| 70 | keyboard_keys; | ||
| 71 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods> | ||
| 72 | keyboard_mods; | ||
| 73 | }; | 52 | }; |
| 74 | } // namespace Service::HID | 53 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 544a71948..ba79888ae 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp | |||
| @@ -6,12 +6,17 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/frontend/emu_window.h" | 8 | #include "core/frontend/emu_window.h" |
| 9 | #include "core/hid/emulated_devices.h" | ||
| 10 | #include "core/hid/hid_core.h" | ||
| 9 | #include "core/hle/service/hid/controllers/mouse.h" | 11 | #include "core/hle/service/hid/controllers/mouse.h" |
| 10 | 12 | ||
| 11 | namespace Service::HID { | 13 | namespace Service::HID { |
| 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; | 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; |
| 13 | 15 | ||
| 14 | Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {} | 16 | Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { |
| 17 | emulated_devices = hid_core.GetEmulatedDevices(); | ||
| 18 | } | ||
| 19 | |||
| 15 | Controller_Mouse::~Controller_Mouse() = default; | 20 | Controller_Mouse::~Controller_Mouse() = default; |
| 16 | 21 | ||
| 17 | void Controller_Mouse::OnInit() {} | 22 | void Controller_Mouse::OnInit() {} |
| @@ -19,50 +24,35 @@ void Controller_Mouse::OnRelease() {} | |||
| 19 | 24 | ||
| 20 | void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 25 | void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 21 | std::size_t size) { | 26 | std::size_t size) { |
| 22 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | ||
| 23 | shared_memory.header.total_entry_count = 17; | ||
| 24 | |||
| 25 | if (!IsControllerActivated()) { | 27 | if (!IsControllerActivated()) { |
| 26 | shared_memory.header.entry_count = 0; | 28 | mouse_lifo.buffer_count = 0; |
| 27 | shared_memory.header.last_entry_index = 0; | 29 | mouse_lifo.buffer_tail = 0; |
| 30 | std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); | ||
| 28 | return; | 31 | return; |
| 29 | } | 32 | } |
| 30 | shared_memory.header.entry_count = 16; | ||
| 31 | 33 | ||
| 32 | auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; | 34 | const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; |
| 33 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | 35 | next_state.sampling_number = last_entry.sampling_number + 1; |
| 34 | auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; | ||
| 35 | 36 | ||
| 36 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 37 | next_state.attribute.raw = 0; |
| 37 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 38 | |||
| 39 | cur_entry.attribute.raw = 0; | ||
| 40 | if (Settings::values.mouse_enabled) { | 38 | if (Settings::values.mouse_enabled) { |
| 41 | const auto [px, py, sx, sy] = mouse_device->GetStatus(); | 39 | const auto& mouse_button_state = emulated_devices->GetMouseButtons(); |
| 42 | const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); | 40 | const auto& mouse_position_state = emulated_devices->GetMousePosition(); |
| 43 | const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height); | 41 | const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); |
| 44 | cur_entry.x = x; | 42 | next_state.attribute.is_connected.Assign(1); |
| 45 | cur_entry.y = y; | 43 | next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); |
| 46 | cur_entry.delta_x = x - last_entry.x; | 44 | next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); |
| 47 | cur_entry.delta_y = y - last_entry.y; | 45 | next_state.delta_x = next_state.x - last_entry.x; |
| 48 | cur_entry.mouse_wheel_x = sx; | 46 | next_state.delta_y = next_state.y - last_entry.y; |
| 49 | cur_entry.mouse_wheel_y = sy; | 47 | next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; |
| 50 | cur_entry.attribute.is_connected.Assign(1); | 48 | next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; |
| 51 | 49 | ||
| 52 | using namespace Settings::NativeMouseButton; | 50 | last_mouse_wheel_state = mouse_wheel_state; |
| 53 | cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus()); | 51 | next_state.button = mouse_button_state; |
| 54 | cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus()); | ||
| 55 | cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus()); | ||
| 56 | cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus()); | ||
| 57 | cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus()); | ||
| 58 | } | 52 | } |
| 59 | 53 | ||
| 60 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 54 | mouse_lifo.WriteNextEntry(next_state); |
| 55 | std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); | ||
| 61 | } | 56 | } |
| 62 | 57 | ||
| 63 | void Controller_Mouse::OnLoadInputDevices() { | ||
| 64 | mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device); | ||
| 65 | std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), | ||
| 66 | mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 67 | } | ||
| 68 | } // namespace Service::HID | 58 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 3d391a798..7559fc78d 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h | |||
| @@ -7,15 +7,20 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/settings.h" | ||
| 11 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 12 | #include "core/frontend/input.h" | ||
| 13 | #include "core/hle/service/hid/controllers/controller_base.h" | 11 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 12 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 13 | |||
| 14 | namespace Core::HID { | ||
| 15 | class EmulatedDevices; | ||
| 16 | struct MouseState; | ||
| 17 | struct AnalogStickState; | ||
| 18 | } // namespace Core::HID | ||
| 14 | 19 | ||
| 15 | namespace Service::HID { | 20 | namespace Service::HID { |
| 16 | class Controller_Mouse final : public ControllerBase { | 21 | class Controller_Mouse final : public ControllerBase { |
| 17 | public: | 22 | public: |
| 18 | explicit Controller_Mouse(Core::System& system_); | 23 | explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); |
| 19 | ~Controller_Mouse() override; | 24 | ~Controller_Mouse() override; |
| 20 | 25 | ||
| 21 | // Called when the controller is initialized | 26 | // Called when the controller is initialized |
| @@ -27,53 +32,13 @@ public: | |||
| 27 | // When the controller is requesting an update for the shared memory | 32 | // When the controller is requesting an update for the shared memory |
| 28 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 33 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 29 | 34 | ||
| 30 | // Called when input devices should be loaded | ||
| 31 | void OnLoadInputDevices() override; | ||
| 32 | |||
| 33 | private: | 35 | private: |
| 34 | struct Buttons { | 36 | // This is nn::hid::detail::MouseLifo |
| 35 | union { | 37 | Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{}; |
| 36 | u32_le raw{}; | 38 | static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); |
| 37 | BitField<0, 1, u32> left; | 39 | Core::HID::MouseState next_state{}; |
| 38 | BitField<1, 1, u32> right; | ||
| 39 | BitField<2, 1, u32> middle; | ||
| 40 | BitField<3, 1, u32> forward; | ||
| 41 | BitField<4, 1, u32> back; | ||
| 42 | }; | ||
| 43 | }; | ||
| 44 | static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size"); | ||
| 45 | |||
| 46 | struct Attributes { | ||
| 47 | union { | ||
| 48 | u32_le raw{}; | ||
| 49 | BitField<0, 1, u32> transferable; | ||
| 50 | BitField<1, 1, u32> is_connected; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 54 | |||
| 55 | struct MouseState { | ||
| 56 | s64_le sampling_number; | ||
| 57 | s64_le sampling_number2; | ||
| 58 | s32_le x; | ||
| 59 | s32_le y; | ||
| 60 | s32_le delta_x; | ||
| 61 | s32_le delta_y; | ||
| 62 | s32_le mouse_wheel_x; | ||
| 63 | s32_le mouse_wheel_y; | ||
| 64 | Buttons button; | ||
| 65 | Attributes attribute; | ||
| 66 | }; | ||
| 67 | static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); | ||
| 68 | |||
| 69 | struct SharedMemory { | ||
| 70 | CommonHeader header; | ||
| 71 | std::array<MouseState, 17> mouse_states; | ||
| 72 | }; | ||
| 73 | SharedMemory shared_memory{}; | ||
| 74 | 40 | ||
| 75 | std::unique_ptr<Input::MouseDevice> mouse_device; | 41 | Core::HID::AnalogStickState last_mouse_wheel_state; |
| 76 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons> | 42 | Core::HID::EmulatedDevices* emulated_devices; |
| 77 | mouse_button_devices; | ||
| 78 | }; | 43 | }; |
| 79 | } // namespace Service::HID | 44 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 196876810..2705e9dcb 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -10,9 +10,9 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "common/settings.h" | 12 | #include "common/settings.h" |
| 13 | #include "core/core.h" | ||
| 14 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| 15 | #include "core/frontend/input.h" | 14 | #include "core/hid/emulated_controller.h" |
| 15 | #include "core/hid/hid_core.h" | ||
| 16 | #include "core/hle/kernel/k_event.h" | 16 | #include "core/hle/kernel/k_event.h" |
| 17 | #include "core/hle/kernel/k_readable_event.h" | 17 | #include "core/hle/kernel/k_readable_event.h" |
| 18 | #include "core/hle/kernel/k_writable_event.h" | 18 | #include "core/hle/kernel/k_writable_event.h" |
| @@ -20,120 +20,26 @@ | |||
| 20 | #include "core/hle/service/kernel_helpers.h" | 20 | #include "core/hle/service/kernel_helpers.h" |
| 21 | 21 | ||
| 22 | namespace Service::HID { | 22 | namespace Service::HID { |
| 23 | constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | ||
| 24 | constexpr s32 HID_TRIGGER_MAX = 0x7fff; | ||
| 25 | [[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; | ||
| 26 | constexpr std::size_t NPAD_OFFSET = 0x9A00; | 23 | constexpr std::size_t NPAD_OFFSET = 0x9A00; |
| 27 | constexpr u32 BATTERY_FULL = 2; | 24 | constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ |
| 28 | constexpr u32 MAX_NPAD_ID = 7; | 25 | Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, |
| 29 | constexpr std::size_t HANDHELD_INDEX = 8; | 26 | Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, |
| 30 | constexpr std::array<u32, 10> npad_id_list{ | 27 | Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, |
| 31 | 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, | 28 | Core::HID::NpadIdType::Handheld, |
| 32 | }; | 29 | }; |
| 33 | 30 | ||
| 34 | enum class JoystickId : std::size_t { | 31 | bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { |
| 35 | Joystick_Left, | ||
| 36 | Joystick_Right, | ||
| 37 | }; | ||
| 38 | |||
| 39 | Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad( | ||
| 40 | Settings::ControllerType type) { | ||
| 41 | switch (type) { | ||
| 42 | case Settings::ControllerType::ProController: | ||
| 43 | return NPadControllerType::ProController; | ||
| 44 | case Settings::ControllerType::DualJoyconDetached: | ||
| 45 | return NPadControllerType::JoyDual; | ||
| 46 | case Settings::ControllerType::LeftJoycon: | ||
| 47 | return NPadControllerType::JoyLeft; | ||
| 48 | case Settings::ControllerType::RightJoycon: | ||
| 49 | return NPadControllerType::JoyRight; | ||
| 50 | case Settings::ControllerType::Handheld: | ||
| 51 | return NPadControllerType::Handheld; | ||
| 52 | case Settings::ControllerType::GameCube: | ||
| 53 | return NPadControllerType::GameCube; | ||
| 54 | default: | ||
| 55 | UNREACHABLE(); | ||
| 56 | return NPadControllerType::ProController; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | Settings::ControllerType Controller_NPad::MapNPadToSettingsType( | ||
| 61 | Controller_NPad::NPadControllerType type) { | ||
| 62 | switch (type) { | ||
| 63 | case NPadControllerType::ProController: | ||
| 64 | return Settings::ControllerType::ProController; | ||
| 65 | case NPadControllerType::JoyDual: | ||
| 66 | return Settings::ControllerType::DualJoyconDetached; | ||
| 67 | case NPadControllerType::JoyLeft: | ||
| 68 | return Settings::ControllerType::LeftJoycon; | ||
| 69 | case NPadControllerType::JoyRight: | ||
| 70 | return Settings::ControllerType::RightJoycon; | ||
| 71 | case NPadControllerType::Handheld: | ||
| 72 | return Settings::ControllerType::Handheld; | ||
| 73 | case NPadControllerType::GameCube: | ||
| 74 | return Settings::ControllerType::GameCube; | ||
| 75 | default: | ||
| 76 | UNREACHABLE(); | ||
| 77 | return Settings::ControllerType::ProController; | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { | ||
| 82 | switch (npad_id) { | 32 | switch (npad_id) { |
| 83 | case 0: | 33 | case Core::HID::NpadIdType::Player1: |
| 84 | case 1: | 34 | case Core::HID::NpadIdType::Player2: |
| 85 | case 2: | 35 | case Core::HID::NpadIdType::Player3: |
| 86 | case 3: | 36 | case Core::HID::NpadIdType::Player4: |
| 87 | case 4: | 37 | case Core::HID::NpadIdType::Player5: |
| 88 | case 5: | 38 | case Core::HID::NpadIdType::Player6: |
| 89 | case 6: | 39 | case Core::HID::NpadIdType::Player7: |
| 90 | case 7: | 40 | case Core::HID::NpadIdType::Player8: |
| 91 | return npad_id; | 41 | case Core::HID::NpadIdType::Other: |
| 92 | case HANDHELD_INDEX: | 42 | case Core::HID::NpadIdType::Handheld: |
| 93 | case NPAD_HANDHELD: | ||
| 94 | return HANDHELD_INDEX; | ||
| 95 | case 9: | ||
| 96 | case NPAD_UNKNOWN: | ||
| 97 | return 9; | ||
| 98 | default: | ||
| 99 | UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); | ||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | u32 Controller_NPad::IndexToNPad(std::size_t index) { | ||
| 105 | switch (index) { | ||
| 106 | case 0: | ||
| 107 | case 1: | ||
| 108 | case 2: | ||
| 109 | case 3: | ||
| 110 | case 4: | ||
| 111 | case 5: | ||
| 112 | case 6: | ||
| 113 | case 7: | ||
| 114 | return static_cast<u32>(index); | ||
| 115 | case HANDHELD_INDEX: | ||
| 116 | return NPAD_HANDHELD; | ||
| 117 | case 9: | ||
| 118 | return NPAD_UNKNOWN; | ||
| 119 | default: | ||
| 120 | UNIMPLEMENTED_MSG("Unknown npad index {}", index); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | bool Controller_NPad::IsNpadIdValid(u32 npad_id) { | ||
| 126 | switch (npad_id) { | ||
| 127 | case 0: | ||
| 128 | case 1: | ||
| 129 | case 2: | ||
| 130 | case 3: | ||
| 131 | case 4: | ||
| 132 | case 5: | ||
| 133 | case 6: | ||
| 134 | case 7: | ||
| 135 | case NPAD_UNKNOWN: | ||
| 136 | case NPAD_HANDHELD: | ||
| 137 | return true; | 43 | return true; |
| 138 | default: | 44 | default: |
| 139 | LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); | 45 | LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); |
| @@ -141,305 +47,337 @@ bool Controller_NPad::IsNpadIdValid(u32 npad_id) { | |||
| 141 | } | 47 | } |
| 142 | } | 48 | } |
| 143 | 49 | ||
| 144 | bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { | 50 | bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { |
| 145 | return IsNpadIdValid(device_handle.npad_id) && | 51 | return IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)) && |
| 146 | device_handle.npad_type < NpadType::MaxNpadType && | 52 | device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && |
| 147 | device_handle.device_index < DeviceIndex::MaxDeviceIndex; | 53 | device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; |
| 148 | } | 54 | } |
| 149 | 55 | ||
| 150 | Controller_NPad::Controller_NPad(Core::System& system_, | 56 | bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) { |
| 57 | return IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)) && | ||
| 58 | device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && | ||
| 59 | device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; | ||
| 60 | } | ||
| 61 | |||
| 62 | Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, | ||
| 151 | KernelHelpers::ServiceContext& service_context_) | 63 | KernelHelpers::ServiceContext& service_context_) |
| 152 | : ControllerBase{system_}, service_context{service_context_} { | 64 | : ControllerBase{hid_core_}, service_context{service_context_} { |
| 153 | latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); | 65 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 66 | auto& controller = controller_data[i]; | ||
| 67 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | ||
| 68 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | ||
| 69 | DEFAULT_VIBRATION_VALUE; | ||
| 70 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = | ||
| 71 | DEFAULT_VIBRATION_VALUE; | ||
| 72 | Core::HID::ControllerUpdateCallback engine_callback{ | ||
| 73 | .on_change = [this, | ||
| 74 | i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, | ||
| 75 | .is_npad_service = true, | ||
| 76 | }; | ||
| 77 | controller.callback_key = controller.device->SetCallback(engine_callback); | ||
| 78 | } | ||
| 154 | } | 79 | } |
| 155 | 80 | ||
| 156 | Controller_NPad::~Controller_NPad() { | 81 | Controller_NPad::~Controller_NPad() { |
| 82 | for (std::size_t i = 0; i < controller_data.size(); ++i) { | ||
| 83 | auto& controller = controller_data[i]; | ||
| 84 | controller.device->DeleteCallback(controller.callback_key); | ||
| 85 | } | ||
| 157 | OnRelease(); | 86 | OnRelease(); |
| 158 | } | 87 | } |
| 159 | 88 | ||
| 160 | void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { | 89 | void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, |
| 161 | const auto controller_type = connected_controllers[controller_idx].type; | 90 | std::size_t controller_idx) { |
| 162 | auto& controller = shared_memory_entries[controller_idx]; | 91 | if (type == Core::HID::ControllerTriggerType::All) { |
| 163 | if (controller_type == NPadControllerType::None) { | 92 | ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); |
| 164 | styleset_changed_events[controller_idx]->GetWritableEvent().Signal(); | 93 | ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); |
| 94 | return; | ||
| 95 | } | ||
| 96 | if (controller_idx >= controller_data.size()) { | ||
| 97 | return; | ||
| 98 | } | ||
| 99 | |||
| 100 | auto& controller = controller_data[controller_idx]; | ||
| 101 | const auto is_connected = controller.device->IsConnected(); | ||
| 102 | const auto npad_type = controller.device->GetNpadStyleIndex(); | ||
| 103 | const auto npad_id = controller.device->GetNpadIdType(); | ||
| 104 | switch (type) { | ||
| 105 | case Core::HID::ControllerTriggerType::Connected: | ||
| 106 | case Core::HID::ControllerTriggerType::Disconnected: | ||
| 107 | if (is_connected == controller.is_connected) { | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | UpdateControllerAt(npad_type, npad_id, is_connected); | ||
| 111 | break; | ||
| 112 | case Core::HID::ControllerTriggerType::Battery: { | ||
| 113 | if (!controller.device->IsConnected()) { | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | auto& shared_memory = controller.shared_memory_entry; | ||
| 117 | const auto& battery_level = controller.device->GetBattery(); | ||
| 118 | shared_memory.battery_level_dual = battery_level.dual.battery_level; | ||
| 119 | shared_memory.battery_level_left = battery_level.left.battery_level; | ||
| 120 | shared_memory.battery_level_right = battery_level.right.battery_level; | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | default: | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { | ||
| 129 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 130 | if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { | ||
| 165 | return; | 131 | return; |
| 166 | } | 132 | } |
| 167 | controller.style_set.raw = 0; // Zero out | 133 | LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); |
| 168 | controller.device_type.raw = 0; | 134 | const auto controller_type = controller.device->GetNpadStyleIndex(); |
| 169 | controller.system_properties.raw = 0; | 135 | auto& shared_memory = controller.shared_memory_entry; |
| 136 | if (controller_type == Core::HID::NpadStyleIndex::None) { | ||
| 137 | controller.styleset_changed_event->GetWritableEvent().Signal(); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; | ||
| 141 | shared_memory.device_type.raw = 0; | ||
| 142 | shared_memory.system_properties.raw = 0; | ||
| 170 | switch (controller_type) { | 143 | switch (controller_type) { |
| 171 | case NPadControllerType::None: | 144 | case Core::HID::NpadStyleIndex::None: |
| 172 | UNREACHABLE(); | 145 | UNREACHABLE(); |
| 173 | break; | 146 | break; |
| 174 | case NPadControllerType::ProController: | 147 | case Core::HID::NpadStyleIndex::ProController: |
| 175 | controller.style_set.fullkey.Assign(1); | 148 | shared_memory.style_tag.fullkey.Assign(1); |
| 176 | controller.device_type.fullkey.Assign(1); | 149 | shared_memory.device_type.fullkey.Assign(1); |
| 177 | controller.system_properties.is_vertical.Assign(1); | 150 | shared_memory.system_properties.is_vertical.Assign(1); |
| 178 | controller.system_properties.use_plus.Assign(1); | 151 | shared_memory.system_properties.use_plus.Assign(1); |
| 179 | controller.system_properties.use_minus.Assign(1); | 152 | shared_memory.system_properties.use_minus.Assign(1); |
| 180 | controller.assignment_mode = NpadAssignments::Single; | 153 | shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; |
| 181 | controller.footer_type = AppletFooterUiType::SwitchProController; | ||
| 182 | break; | 154 | break; |
| 183 | case NPadControllerType::Handheld: | 155 | case Core::HID::NpadStyleIndex::Handheld: |
| 184 | controller.style_set.handheld.Assign(1); | 156 | shared_memory.style_tag.handheld.Assign(1); |
| 185 | controller.device_type.handheld_left.Assign(1); | 157 | shared_memory.device_type.handheld_left.Assign(1); |
| 186 | controller.device_type.handheld_right.Assign(1); | 158 | shared_memory.device_type.handheld_right.Assign(1); |
| 187 | controller.system_properties.is_vertical.Assign(1); | 159 | shared_memory.system_properties.is_vertical.Assign(1); |
| 188 | controller.system_properties.use_plus.Assign(1); | 160 | shared_memory.system_properties.use_plus.Assign(1); |
| 189 | controller.system_properties.use_minus.Assign(1); | 161 | shared_memory.system_properties.use_minus.Assign(1); |
| 190 | controller.assignment_mode = NpadAssignments::Dual; | 162 | shared_memory.system_properties.use_directional_buttons.Assign(1); |
| 191 | controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; | 163 | shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; |
| 164 | shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; | ||
| 165 | break; | ||
| 166 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 167 | shared_memory.style_tag.joycon_dual.Assign(1); | ||
| 168 | if (controller.is_dual_left_connected) { | ||
| 169 | shared_memory.device_type.joycon_left.Assign(1); | ||
| 170 | shared_memory.system_properties.use_minus.Assign(1); | ||
| 171 | } | ||
| 172 | if (controller.is_dual_right_connected) { | ||
| 173 | shared_memory.device_type.joycon_right.Assign(1); | ||
| 174 | shared_memory.system_properties.use_plus.Assign(1); | ||
| 175 | } | ||
| 176 | shared_memory.system_properties.use_directional_buttons.Assign(1); | ||
| 177 | shared_memory.system_properties.is_vertical.Assign(1); | ||
| 178 | shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; | ||
| 179 | if (controller.is_dual_left_connected && controller.is_dual_right_connected) { | ||
| 180 | shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; | ||
| 181 | } else if (controller.is_dual_left_connected) { | ||
| 182 | shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; | ||
| 183 | } else { | ||
| 184 | shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; | ||
| 185 | } | ||
| 192 | break; | 186 | break; |
| 193 | case NPadControllerType::JoyDual: | 187 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 194 | controller.style_set.joycon_dual.Assign(1); | 188 | shared_memory.style_tag.joycon_left.Assign(1); |
| 195 | controller.device_type.joycon_left.Assign(1); | 189 | shared_memory.device_type.joycon_left.Assign(1); |
| 196 | controller.device_type.joycon_right.Assign(1); | 190 | shared_memory.system_properties.is_horizontal.Assign(1); |
| 197 | controller.system_properties.is_vertical.Assign(1); | 191 | shared_memory.system_properties.use_minus.Assign(1); |
| 198 | controller.system_properties.use_plus.Assign(1); | 192 | shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; |
| 199 | controller.system_properties.use_minus.Assign(1); | ||
| 200 | controller.assignment_mode = NpadAssignments::Dual; | ||
| 201 | controller.footer_type = AppletFooterUiType::JoyDual; | ||
| 202 | break; | 193 | break; |
| 203 | case NPadControllerType::JoyLeft: | 194 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 204 | controller.style_set.joycon_left.Assign(1); | 195 | shared_memory.style_tag.joycon_right.Assign(1); |
| 205 | controller.device_type.joycon_left.Assign(1); | 196 | shared_memory.device_type.joycon_right.Assign(1); |
| 206 | controller.system_properties.is_horizontal.Assign(1); | 197 | shared_memory.system_properties.is_horizontal.Assign(1); |
| 207 | controller.system_properties.use_minus.Assign(1); | 198 | shared_memory.system_properties.use_plus.Assign(1); |
| 208 | controller.assignment_mode = NpadAssignments::Single; | 199 | shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; |
| 209 | controller.footer_type = AppletFooterUiType::JoyLeftHorizontal; | ||
| 210 | break; | 200 | break; |
| 211 | case NPadControllerType::JoyRight: | 201 | case Core::HID::NpadStyleIndex::GameCube: |
| 212 | controller.style_set.joycon_right.Assign(1); | 202 | shared_memory.style_tag.gamecube.Assign(1); |
| 213 | controller.device_type.joycon_right.Assign(1); | 203 | shared_memory.device_type.fullkey.Assign(1); |
| 214 | controller.system_properties.is_horizontal.Assign(1); | 204 | shared_memory.system_properties.is_vertical.Assign(1); |
| 215 | controller.system_properties.use_plus.Assign(1); | 205 | shared_memory.system_properties.use_plus.Assign(1); |
| 216 | controller.assignment_mode = NpadAssignments::Single; | ||
| 217 | controller.footer_type = AppletFooterUiType::JoyRightHorizontal; | ||
| 218 | break; | 206 | break; |
| 219 | case NPadControllerType::GameCube: | 207 | case Core::HID::NpadStyleIndex::Pokeball: |
| 220 | controller.style_set.gamecube.Assign(1); | 208 | shared_memory.style_tag.palma.Assign(1); |
| 221 | // The GC Controller behaves like a wired Pro Controller | 209 | shared_memory.device_type.palma.Assign(1); |
| 222 | controller.device_type.fullkey.Assign(1); | ||
| 223 | controller.system_properties.is_vertical.Assign(1); | ||
| 224 | controller.system_properties.use_plus.Assign(1); | ||
| 225 | break; | 210 | break; |
| 226 | case NPadControllerType::Pokeball: | 211 | case Core::HID::NpadStyleIndex::NES: |
| 227 | controller.style_set.palma.Assign(1); | 212 | shared_memory.style_tag.lark.Assign(1); |
| 228 | controller.device_type.palma.Assign(1); | 213 | shared_memory.device_type.fullkey.Assign(1); |
| 229 | controller.assignment_mode = NpadAssignments::Single; | 214 | break; |
| 215 | case Core::HID::NpadStyleIndex::SNES: | ||
| 216 | shared_memory.style_tag.lucia.Assign(1); | ||
| 217 | shared_memory.device_type.fullkey.Assign(1); | ||
| 218 | shared_memory.applet_footer.type = AppletFooterUiType::Lucia; | ||
| 219 | break; | ||
| 220 | case Core::HID::NpadStyleIndex::N64: | ||
| 221 | shared_memory.style_tag.lagoon.Assign(1); | ||
| 222 | shared_memory.device_type.fullkey.Assign(1); | ||
| 223 | shared_memory.applet_footer.type = AppletFooterUiType::Lagon; | ||
| 224 | break; | ||
| 225 | case Core::HID::NpadStyleIndex::SegaGenesis: | ||
| 226 | shared_memory.style_tag.lager.Assign(1); | ||
| 227 | shared_memory.device_type.fullkey.Assign(1); | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | break; | 230 | break; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | controller.fullkey_color.attribute = ColorAttributes::Ok; | 233 | const auto& body_colors = controller.device->GetColors(); |
| 234 | controller.fullkey_color.fullkey.body = 0; | ||
| 235 | controller.fullkey_color.fullkey.button = 0; | ||
| 236 | 234 | ||
| 237 | controller.joycon_color.attribute = ColorAttributes::Ok; | 235 | shared_memory.fullkey_color.attribute = ColorAttribute::Ok; |
| 238 | controller.joycon_color.left.body = | 236 | shared_memory.fullkey_color.fullkey = body_colors.fullkey; |
| 239 | Settings::values.players.GetValue()[controller_idx].body_color_left; | ||
| 240 | controller.joycon_color.left.button = | ||
| 241 | Settings::values.players.GetValue()[controller_idx].button_color_left; | ||
| 242 | controller.joycon_color.right.body = | ||
| 243 | Settings::values.players.GetValue()[controller_idx].body_color_right; | ||
| 244 | controller.joycon_color.right.button = | ||
| 245 | Settings::values.players.GetValue()[controller_idx].button_color_right; | ||
| 246 | 237 | ||
| 247 | // TODO: Investigate when we should report all batery types | 238 | shared_memory.joycon_color.attribute = ColorAttribute::Ok; |
| 248 | controller.battery_level_dual = BATTERY_FULL; | 239 | shared_memory.joycon_color.left = body_colors.left; |
| 249 | controller.battery_level_left = BATTERY_FULL; | 240 | shared_memory.joycon_color.right = body_colors.right; |
| 250 | controller.battery_level_right = BATTERY_FULL; | ||
| 251 | 241 | ||
| 252 | SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); | 242 | // TODO: Investigate when we should report all batery types |
| 243 | const auto& battery_level = controller.device->GetBattery(); | ||
| 244 | shared_memory.battery_level_dual = battery_level.dual.battery_level; | ||
| 245 | shared_memory.battery_level_left = battery_level.left.battery_level; | ||
| 246 | shared_memory.battery_level_right = battery_level.right.battery_level; | ||
| 247 | |||
| 248 | controller.is_connected = true; | ||
| 249 | controller.device->Connect(); | ||
| 250 | SignalStyleSetChangedEvent(npad_id); | ||
| 251 | WriteEmptyEntry(controller.shared_memory_entry); | ||
| 253 | } | 252 | } |
| 254 | 253 | ||
| 255 | void Controller_NPad::OnInit() { | 254 | void Controller_NPad::OnInit() { |
| 256 | for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { | ||
| 257 | styleset_changed_events[i] = | ||
| 258 | service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); | ||
| 259 | } | ||
| 260 | |||
| 261 | if (!IsControllerActivated()) { | 255 | if (!IsControllerActivated()) { |
| 262 | return; | 256 | return; |
| 263 | } | 257 | } |
| 264 | 258 | ||
| 265 | OnLoadInputDevices(); | 259 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 266 | 260 | auto& controller = controller_data[i]; | |
| 267 | if (style.raw == 0) { | 261 | controller.styleset_changed_event = |
| 268 | // We want to support all controllers | 262 | service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); |
| 269 | style.handheld.Assign(1); | ||
| 270 | style.joycon_left.Assign(1); | ||
| 271 | style.joycon_right.Assign(1); | ||
| 272 | style.joycon_dual.Assign(1); | ||
| 273 | style.fullkey.Assign(1); | ||
| 274 | style.gamecube.Assign(1); | ||
| 275 | style.palma.Assign(1); | ||
| 276 | } | ||
| 277 | |||
| 278 | std::transform(Settings::values.players.GetValue().begin(), | ||
| 279 | Settings::values.players.GetValue().end(), connected_controllers.begin(), | ||
| 280 | [](const Settings::PlayerInput& player) { | ||
| 281 | return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), | ||
| 282 | player.connected}; | ||
| 283 | }); | ||
| 284 | |||
| 285 | // Connect the Player 1 or Handheld controller if none are connected. | ||
| 286 | if (std::none_of(connected_controllers.begin(), connected_controllers.end(), | ||
| 287 | [](const ControllerHolder& controller) { return controller.is_connected; })) { | ||
| 288 | const auto controller = | ||
| 289 | MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type); | ||
| 290 | if (controller == NPadControllerType::Handheld) { | ||
| 291 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; | ||
| 292 | connected_controllers[HANDHELD_INDEX] = {controller, true}; | ||
| 293 | } else { | ||
| 294 | Settings::values.players.GetValue()[0].connected = true; | ||
| 295 | connected_controllers[0] = {controller, true}; | ||
| 296 | } | ||
| 297 | } | 263 | } |
| 298 | 264 | ||
| 299 | // Account for handheld | 265 | if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { |
| 300 | if (connected_controllers[HANDHELD_INDEX].is_connected) { | 266 | // We want to support all controllers |
| 301 | connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; | 267 | hid_core.SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); |
| 302 | } | 268 | } |
| 303 | 269 | ||
| 304 | supported_npad_id_types.resize(npad_id_list.size()); | 270 | supported_npad_id_types.resize(npad_id_list.size()); |
| 305 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), | 271 | std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), |
| 306 | npad_id_list.size() * sizeof(u32)); | 272 | npad_id_list.size() * sizeof(Core::HID::NpadIdType)); |
| 273 | |||
| 274 | // Prefill controller buffers | ||
| 275 | for (auto& controller : controller_data) { | ||
| 276 | auto& npad = controller.shared_memory_entry; | ||
| 277 | npad.fullkey_color = { | ||
| 278 | .attribute = ColorAttribute::NoController, | ||
| 279 | .fullkey = {}, | ||
| 280 | }; | ||
| 281 | npad.joycon_color = { | ||
| 282 | .attribute = ColorAttribute::NoController, | ||
| 283 | .left = {}, | ||
| 284 | .right = {}, | ||
| 285 | }; | ||
| 286 | // HW seems to initialize the first 19 entries | ||
| 287 | for (std::size_t i = 0; i < 19; ++i) { | ||
| 288 | WriteEmptyEntry(npad); | ||
| 289 | } | ||
| 290 | } | ||
| 307 | 291 | ||
| 308 | for (std::size_t i = 0; i < connected_controllers.size(); ++i) { | 292 | // Connect controllers |
| 309 | const auto& controller = connected_controllers[i]; | 293 | for (auto& controller : controller_data) { |
| 310 | if (controller.is_connected) { | 294 | const auto& device = controller.device; |
| 311 | AddNewControllerAt(controller.type, i); | 295 | if (device->IsConnected()) { |
| 296 | AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); | ||
| 312 | } | 297 | } |
| 313 | } | 298 | } |
| 314 | } | 299 | } |
| 315 | 300 | ||
| 316 | void Controller_NPad::OnLoadInputDevices() { | 301 | void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { |
| 317 | const auto& players = Settings::values.players.GetValue(); | 302 | NPadGenericState dummy_pad_state{}; |
| 303 | NpadGcTriggerState dummy_gc_state{}; | ||
| 304 | dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 305 | npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); | ||
| 306 | dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 307 | npad.handheld_lifo.WriteNextEntry(dummy_pad_state); | ||
| 308 | dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 309 | npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); | ||
| 310 | dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 311 | npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); | ||
| 312 | dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 313 | npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); | ||
| 314 | dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 315 | npad.palma_lifo.WriteNextEntry(dummy_pad_state); | ||
| 316 | dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 317 | npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); | ||
| 318 | dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; | ||
| 319 | npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); | ||
| 320 | } | ||
| 318 | 321 | ||
| 319 | std::lock_guard lock{mutex}; | 322 | void Controller_NPad::OnRelease() { |
| 320 | for (std::size_t i = 0; i < players.size(); ++i) { | 323 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 321 | std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, | 324 | auto& controller = controller_data[i]; |
| 322 | players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, | 325 | service_context.CloseEvent(controller.styleset_changed_event); |
| 323 | buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>); | 326 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { |
| 324 | std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, | 327 | VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); |
| 325 | players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, | ||
| 326 | sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); | ||
| 327 | std::transform(players[i].vibrations.begin() + | ||
| 328 | Settings::NativeVibration::VIBRATION_HID_BEGIN, | ||
| 329 | players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, | ||
| 330 | vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>); | ||
| 331 | std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, | ||
| 332 | players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, | ||
| 333 | motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); | ||
| 334 | for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) { | ||
| 335 | InitializeVibrationDeviceAtIndex(i, device_idx); | ||
| 336 | } | 328 | } |
| 337 | } | 329 | } |
| 338 | } | 330 | } |
| 339 | 331 | ||
| 340 | void Controller_NPad::OnRelease() { | 332 | void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { |
| 341 | for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { | 333 | std::lock_guard lock{mutex}; |
| 342 | for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { | 334 | auto& controller = GetControllerFromNpadIdType(npad_id); |
| 343 | VibrateControllerAtIndex(npad_idx, device_idx, {}); | 335 | const auto controller_type = controller.device->GetNpadStyleIndex(); |
| 344 | } | 336 | if (!controller.device->IsConnected()) { |
| 337 | return; | ||
| 345 | } | 338 | } |
| 346 | 339 | ||
| 347 | for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { | 340 | auto& pad_entry = controller.npad_pad_state; |
| 348 | service_context.CloseEvent(styleset_changed_events[i]); | 341 | auto& trigger_entry = controller.npad_trigger_state; |
| 342 | const auto button_state = controller.device->GetNpadButtons(); | ||
| 343 | const auto stick_state = controller.device->GetSticks(); | ||
| 344 | |||
| 345 | using btn = Core::HID::NpadButton; | ||
| 346 | pad_entry.npad_buttons.raw = btn::None; | ||
| 347 | if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { | ||
| 348 | constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | | ||
| 349 | btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | | ||
| 350 | btn::StickRRight | btn::StickRDown; | ||
| 351 | pad_entry.npad_buttons.raw = button_state.raw & right_button_mask; | ||
| 352 | pad_entry.r_stick = stick_state.right; | ||
| 349 | } | 353 | } |
| 350 | } | ||
| 351 | 354 | ||
| 352 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | 355 | if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { |
| 353 | std::lock_guard lock{mutex}; | 356 | constexpr btn left_button_mask = |
| 357 | btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL | | ||
| 358 | btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown; | ||
| 359 | pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask; | ||
| 360 | pad_entry.l_stick = stick_state.left; | ||
| 361 | } | ||
| 354 | 362 | ||
| 355 | const auto controller_idx = NPadIdToIndex(npad_id); | 363 | if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) { |
| 356 | const auto controller_type = connected_controllers[controller_idx].type; | 364 | pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl); |
| 357 | if (!connected_controllers[controller_idx].is_connected) { | 365 | pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr); |
| 358 | return; | ||
| 359 | } | 366 | } |
| 360 | auto& pad_state = npad_pad_states[controller_idx].pad_states; | 367 | |
| 361 | auto& lstick_entry = npad_pad_states[controller_idx].l_stick; | 368 | if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) { |
| 362 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; | 369 | pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); |
| 363 | auto& trigger_entry = npad_trigger_states[controller_idx]; | 370 | pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); |
| 364 | const auto& button_state = buttons[controller_idx]; | 371 | } |
| 365 | const auto& analog_state = sticks[controller_idx]; | 372 | |
| 366 | const auto [stick_l_x_f, stick_l_y_f] = | 373 | if (controller_type == Core::HID::NpadStyleIndex::GameCube) { |
| 367 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | 374 | const auto& trigger_state = controller.device->GetTriggers(); |
| 368 | const auto [stick_r_x_f, stick_r_y_f] = | 375 | trigger_entry.l_analog = trigger_state.left; |
| 369 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | 376 | trigger_entry.r_analog = trigger_state.right; |
| 370 | 377 | pad_entry.npad_buttons.zl.Assign(false); | |
| 371 | using namespace Settings::NativeButton; | 378 | pad_entry.npad_buttons.zr.Assign(button_state.r); |
| 372 | if (controller_type != NPadControllerType::JoyLeft) { | 379 | pad_entry.npad_buttons.l.Assign(button_state.zl); |
| 373 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); | 380 | pad_entry.npad_buttons.r.Assign(button_state.zr); |
| 374 | pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 375 | pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 376 | pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 377 | pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 378 | pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 379 | pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 380 | pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 381 | |||
| 382 | pad_state.r_stick_right.Assign( | ||
| 383 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 384 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | ||
| 385 | pad_state.r_stick_left.Assign( | ||
| 386 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 387 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); | ||
| 388 | pad_state.r_stick_up.Assign( | ||
| 389 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 390 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); | ||
| 391 | pad_state.r_stick_down.Assign( | ||
| 392 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 393 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); | ||
| 394 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | ||
| 395 | rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); | ||
| 396 | } | ||
| 397 | |||
| 398 | if (controller_type != NPadControllerType::JoyRight) { | ||
| 399 | pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 400 | pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 401 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 402 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 403 | pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 404 | pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 405 | pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 406 | pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 407 | |||
| 408 | pad_state.l_stick_right.Assign( | ||
| 409 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | ||
| 410 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | ||
| 411 | pad_state.l_stick_left.Assign( | ||
| 412 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | ||
| 413 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); | ||
| 414 | pad_state.l_stick_up.Assign( | ||
| 415 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | ||
| 416 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); | ||
| 417 | pad_state.l_stick_down.Assign( | ||
| 418 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)] | ||
| 419 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); | ||
| 420 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | ||
| 421 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | ||
| 422 | } | ||
| 423 | |||
| 424 | if (controller_type == NPadControllerType::JoyLeft) { | ||
| 425 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 426 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 427 | } | ||
| 428 | |||
| 429 | if (controller_type == NPadControllerType::JoyRight) { | ||
| 430 | pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 431 | pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 432 | } | ||
| 433 | |||
| 434 | if (controller_type == NPadControllerType::GameCube) { | ||
| 435 | trigger_entry.l_analog = static_cast<s32>( | ||
| 436 | button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); | ||
| 437 | trigger_entry.r_analog = static_cast<s32>( | ||
| 438 | button_state[ZR - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); | ||
| 439 | pad_state.zl.Assign(false); | ||
| 440 | pad_state.zr.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 441 | pad_state.l.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 442 | pad_state.r.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); | ||
| 443 | } | 381 | } |
| 444 | } | 382 | } |
| 445 | 383 | ||
| @@ -448,173 +386,136 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 448 | if (!IsControllerActivated()) { | 386 | if (!IsControllerActivated()) { |
| 449 | return; | 387 | return; |
| 450 | } | 388 | } |
| 451 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { | ||
| 452 | auto& npad = shared_memory_entries[i]; | ||
| 453 | const std::array<NPadGeneric*, 7> controller_npads{ | ||
| 454 | &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states, | ||
| 455 | &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states, | ||
| 456 | &npad.system_ext_states}; | ||
| 457 | |||
| 458 | // There is the posibility to have more controllers with analog triggers | ||
| 459 | const std::array<TriggerGeneric*, 1> controller_triggers{ | ||
| 460 | &npad.gc_trigger_states, | ||
| 461 | }; | ||
| 462 | |||
| 463 | for (auto* main_controller : controller_npads) { | ||
| 464 | main_controller->common.entry_count = 16; | ||
| 465 | main_controller->common.total_entry_count = 17; | ||
| 466 | |||
| 467 | const auto& last_entry = | ||
| 468 | main_controller->npad[main_controller->common.last_entry_index]; | ||
| 469 | |||
| 470 | main_controller->common.timestamp = core_timing.GetCPUTicks(); | ||
| 471 | main_controller->common.last_entry_index = | ||
| 472 | (main_controller->common.last_entry_index + 1) % 17; | ||
| 473 | |||
| 474 | auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index]; | ||
| 475 | |||
| 476 | cur_entry.timestamp = last_entry.timestamp + 1; | ||
| 477 | cur_entry.timestamp2 = cur_entry.timestamp; | ||
| 478 | } | ||
| 479 | |||
| 480 | for (auto* analog_trigger : controller_triggers) { | ||
| 481 | analog_trigger->entry_count = 16; | ||
| 482 | analog_trigger->total_entry_count = 17; | ||
| 483 | |||
| 484 | const auto& last_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; | ||
| 485 | |||
| 486 | analog_trigger->timestamp = core_timing.GetCPUTicks(); | ||
| 487 | analog_trigger->last_entry_index = (analog_trigger->last_entry_index + 1) % 17; | ||
| 488 | |||
| 489 | auto& cur_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; | ||
| 490 | 389 | ||
| 491 | cur_entry.timestamp = last_entry.timestamp + 1; | 390 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 492 | cur_entry.timestamp2 = cur_entry.timestamp; | 391 | auto& controller = controller_data[i]; |
| 493 | } | 392 | auto& npad = controller.shared_memory_entry; |
| 494 | 393 | ||
| 495 | const auto& controller_type = connected_controllers[i].type; | 394 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| 496 | 395 | ||
| 497 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { | 396 | if (controller_type == Core::HID::NpadStyleIndex::None || |
| 397 | !controller.device->IsConnected()) { | ||
| 398 | // Refresh shared memory | ||
| 399 | std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), | ||
| 400 | &controller.shared_memory_entry, sizeof(NpadInternalState)); | ||
| 498 | continue; | 401 | continue; |
| 499 | } | 402 | } |
| 500 | const u32 npad_index = static_cast<u32>(i); | ||
| 501 | |||
| 502 | RequestPadStateUpdate(npad_index); | ||
| 503 | auto& pad_state = npad_pad_states[npad_index]; | ||
| 504 | auto& trigger_state = npad_trigger_states[npad_index]; | ||
| 505 | |||
| 506 | auto& main_controller = | ||
| 507 | npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index]; | ||
| 508 | auto& handheld_entry = | ||
| 509 | npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; | ||
| 510 | auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index]; | ||
| 511 | auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index]; | ||
| 512 | auto& right_entry = | ||
| 513 | npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index]; | ||
| 514 | auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index]; | ||
| 515 | auto& libnx_entry = | ||
| 516 | npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index]; | ||
| 517 | auto& trigger_entry = | ||
| 518 | npad.gc_trigger_states.trigger[npad.gc_trigger_states.last_entry_index]; | ||
| 519 | |||
| 520 | libnx_entry.connection_status.raw = 0; | ||
| 521 | libnx_entry.connection_status.is_connected.Assign(1); | ||
| 522 | 403 | ||
| 404 | RequestPadStateUpdate(controller.device->GetNpadIdType()); | ||
| 405 | auto& pad_state = controller.npad_pad_state; | ||
| 406 | auto& libnx_state = controller.npad_libnx_state; | ||
| 407 | auto& trigger_state = controller.npad_trigger_state; | ||
| 408 | |||
| 409 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | ||
| 410 | // any controllers. | ||
| 411 | libnx_state.connection_status.raw = 0; | ||
| 412 | libnx_state.connection_status.is_connected.Assign(1); | ||
| 523 | switch (controller_type) { | 413 | switch (controller_type) { |
| 524 | case NPadControllerType::None: | 414 | case Core::HID::NpadStyleIndex::None: |
| 525 | UNREACHABLE(); | 415 | UNREACHABLE(); |
| 526 | break; | 416 | break; |
| 527 | case NPadControllerType::ProController: | 417 | case Core::HID::NpadStyleIndex::ProController: |
| 528 | main_controller.connection_status.raw = 0; | 418 | case Core::HID::NpadStyleIndex::NES: |
| 529 | main_controller.connection_status.is_connected.Assign(1); | 419 | case Core::HID::NpadStyleIndex::SNES: |
| 530 | main_controller.connection_status.is_wired.Assign(1); | 420 | case Core::HID::NpadStyleIndex::N64: |
| 531 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; | 421 | case Core::HID::NpadStyleIndex::SegaGenesis: |
| 532 | main_controller.pad.l_stick = pad_state.l_stick; | 422 | pad_state.connection_status.raw = 0; |
| 533 | main_controller.pad.r_stick = pad_state.r_stick; | 423 | pad_state.connection_status.is_connected.Assign(1); |
| 534 | 424 | pad_state.connection_status.is_wired.Assign(1); | |
| 535 | libnx_entry.connection_status.is_wired.Assign(1); | 425 | |
| 426 | libnx_state.connection_status.is_wired.Assign(1); | ||
| 427 | pad_state.sampling_number = | ||
| 428 | npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 429 | npad.fullkey_lifo.WriteNextEntry(pad_state); | ||
| 536 | break; | 430 | break; |
| 537 | case NPadControllerType::Handheld: | 431 | case Core::HID::NpadStyleIndex::Handheld: |
| 538 | handheld_entry.connection_status.raw = 0; | 432 | pad_state.connection_status.raw = 0; |
| 539 | handheld_entry.connection_status.is_connected.Assign(1); | 433 | pad_state.connection_status.is_connected.Assign(1); |
| 540 | handheld_entry.connection_status.is_wired.Assign(1); | 434 | pad_state.connection_status.is_wired.Assign(1); |
| 541 | handheld_entry.connection_status.is_left_connected.Assign(1); | 435 | pad_state.connection_status.is_left_connected.Assign(1); |
| 542 | handheld_entry.connection_status.is_right_connected.Assign(1); | 436 | pad_state.connection_status.is_right_connected.Assign(1); |
| 543 | handheld_entry.connection_status.is_left_wired.Assign(1); | 437 | pad_state.connection_status.is_left_wired.Assign(1); |
| 544 | handheld_entry.connection_status.is_right_wired.Assign(1); | 438 | pad_state.connection_status.is_right_wired.Assign(1); |
| 545 | handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 439 | |
| 546 | handheld_entry.pad.l_stick = pad_state.l_stick; | 440 | libnx_state.connection_status.is_wired.Assign(1); |
| 547 | handheld_entry.pad.r_stick = pad_state.r_stick; | 441 | libnx_state.connection_status.is_left_connected.Assign(1); |
| 548 | 442 | libnx_state.connection_status.is_right_connected.Assign(1); | |
| 549 | libnx_entry.connection_status.is_wired.Assign(1); | 443 | libnx_state.connection_status.is_left_wired.Assign(1); |
| 550 | libnx_entry.connection_status.is_left_connected.Assign(1); | 444 | libnx_state.connection_status.is_right_wired.Assign(1); |
| 551 | libnx_entry.connection_status.is_right_connected.Assign(1); | 445 | pad_state.sampling_number = |
| 552 | libnx_entry.connection_status.is_left_wired.Assign(1); | 446 | npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; |
| 553 | libnx_entry.connection_status.is_right_wired.Assign(1); | 447 | npad.handheld_lifo.WriteNextEntry(pad_state); |
| 554 | break; | 448 | break; |
| 555 | case NPadControllerType::JoyDual: | 449 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 556 | dual_entry.connection_status.raw = 0; | 450 | pad_state.connection_status.raw = 0; |
| 557 | dual_entry.connection_status.is_connected.Assign(1); | 451 | pad_state.connection_status.is_connected.Assign(1); |
| 558 | dual_entry.connection_status.is_left_connected.Assign(1); | 452 | if (controller.is_dual_left_connected) { |
| 559 | dual_entry.connection_status.is_right_connected.Assign(1); | 453 | pad_state.connection_status.is_left_connected.Assign(1); |
| 560 | dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 454 | libnx_state.connection_status.is_left_connected.Assign(1); |
| 561 | dual_entry.pad.l_stick = pad_state.l_stick; | 455 | } |
| 562 | dual_entry.pad.r_stick = pad_state.r_stick; | 456 | if (controller.is_dual_right_connected) { |
| 563 | 457 | pad_state.connection_status.is_right_connected.Assign(1); | |
| 564 | libnx_entry.connection_status.is_left_connected.Assign(1); | 458 | libnx_state.connection_status.is_right_connected.Assign(1); |
| 565 | libnx_entry.connection_status.is_right_connected.Assign(1); | 459 | } |
| 460 | |||
| 461 | pad_state.sampling_number = | ||
| 462 | npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 463 | npad.joy_dual_lifo.WriteNextEntry(pad_state); | ||
| 566 | break; | 464 | break; |
| 567 | case NPadControllerType::JoyLeft: | 465 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 568 | left_entry.connection_status.raw = 0; | 466 | pad_state.connection_status.raw = 0; |
| 569 | left_entry.connection_status.is_connected.Assign(1); | 467 | pad_state.connection_status.is_connected.Assign(1); |
| 570 | left_entry.connection_status.is_left_connected.Assign(1); | 468 | pad_state.connection_status.is_left_connected.Assign(1); |
| 571 | left_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 469 | |
| 572 | left_entry.pad.l_stick = pad_state.l_stick; | 470 | libnx_state.connection_status.is_left_connected.Assign(1); |
| 573 | left_entry.pad.r_stick = pad_state.r_stick; | 471 | pad_state.sampling_number = |
| 574 | 472 | npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | |
| 575 | libnx_entry.connection_status.is_left_connected.Assign(1); | 473 | npad.joy_left_lifo.WriteNextEntry(pad_state); |
| 576 | break; | 474 | break; |
| 577 | case NPadControllerType::JoyRight: | 475 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 578 | right_entry.connection_status.raw = 0; | 476 | pad_state.connection_status.raw = 0; |
| 579 | right_entry.connection_status.is_connected.Assign(1); | 477 | pad_state.connection_status.is_connected.Assign(1); |
| 580 | right_entry.connection_status.is_right_connected.Assign(1); | 478 | pad_state.connection_status.is_right_connected.Assign(1); |
| 581 | right_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 479 | |
| 582 | right_entry.pad.l_stick = pad_state.l_stick; | 480 | libnx_state.connection_status.is_right_connected.Assign(1); |
| 583 | right_entry.pad.r_stick = pad_state.r_stick; | 481 | pad_state.sampling_number = |
| 584 | 482 | npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | |
| 585 | libnx_entry.connection_status.is_right_connected.Assign(1); | 483 | npad.joy_right_lifo.WriteNextEntry(pad_state); |
| 586 | break; | 484 | break; |
| 587 | case NPadControllerType::GameCube: | 485 | case Core::HID::NpadStyleIndex::GameCube: |
| 588 | main_controller.connection_status.raw = 0; | 486 | pad_state.connection_status.raw = 0; |
| 589 | main_controller.connection_status.is_connected.Assign(1); | 487 | pad_state.connection_status.is_connected.Assign(1); |
| 590 | main_controller.connection_status.is_wired.Assign(1); | 488 | pad_state.connection_status.is_wired.Assign(1); |
| 591 | main_controller.pad.pad_states.raw = pad_state.pad_states.raw; | 489 | |
| 592 | main_controller.pad.l_stick = pad_state.l_stick; | 490 | libnx_state.connection_status.is_wired.Assign(1); |
| 593 | main_controller.pad.r_stick = pad_state.r_stick; | 491 | pad_state.sampling_number = |
| 594 | trigger_entry.l_analog = trigger_state.l_analog; | 492 | npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; |
| 595 | trigger_entry.r_analog = trigger_state.r_analog; | 493 | trigger_state.sampling_number = |
| 596 | 494 | npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; | |
| 597 | libnx_entry.connection_status.is_wired.Assign(1); | 495 | npad.fullkey_lifo.WriteNextEntry(pad_state); |
| 496 | npad.gc_trigger_lifo.WriteNextEntry(trigger_state); | ||
| 598 | break; | 497 | break; |
| 599 | case NPadControllerType::Pokeball: | 498 | case Core::HID::NpadStyleIndex::Pokeball: |
| 600 | pokeball_entry.connection_status.raw = 0; | 499 | pad_state.connection_status.raw = 0; |
| 601 | pokeball_entry.connection_status.is_connected.Assign(1); | 500 | pad_state.connection_status.is_connected.Assign(1); |
| 602 | pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 501 | pad_state.sampling_number = |
| 603 | pokeball_entry.pad.l_stick = pad_state.l_stick; | 502 | npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; |
| 604 | pokeball_entry.pad.r_stick = pad_state.r_stick; | 503 | npad.palma_lifo.WriteNextEntry(pad_state); |
| 504 | break; | ||
| 505 | default: | ||
| 605 | break; | 506 | break; |
| 606 | } | 507 | } |
| 607 | 508 | ||
| 608 | // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate | 509 | libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; |
| 609 | // any controllers. | 510 | libnx_state.l_stick = pad_state.l_stick; |
| 610 | libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; | 511 | libnx_state.r_stick = pad_state.r_stick; |
| 611 | libnx_entry.pad.l_stick = pad_state.l_stick; | 512 | npad.system_ext_lifo.WriteNextEntry(pad_state); |
| 612 | libnx_entry.pad.r_stick = pad_state.r_stick; | 513 | |
| 514 | press_state |= static_cast<u64>(pad_state.npad_buttons.raw); | ||
| 613 | 515 | ||
| 614 | press_state |= static_cast<u32>(pad_state.pad_states.raw); | 516 | std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), |
| 517 | &controller.shared_memory_entry, sizeof(NpadInternalState)); | ||
| 615 | } | 518 | } |
| 616 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | ||
| 617 | shared_memory_entries.size() * sizeof(NPadEntry)); | ||
| 618 | } | 519 | } |
| 619 | 520 | ||
| 620 | void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 521 | void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| @@ -622,145 +523,138 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing | |||
| 622 | if (!IsControllerActivated()) { | 523 | if (!IsControllerActivated()) { |
| 623 | return; | 524 | return; |
| 624 | } | 525 | } |
| 625 | for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { | ||
| 626 | auto& npad = shared_memory_entries[i]; | ||
| 627 | |||
| 628 | const auto& controller_type = connected_controllers[i].type; | ||
| 629 | 526 | ||
| 630 | if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { | 527 | for (std::size_t i = 0; i < controller_data.size(); ++i) { |
| 631 | continue; | 528 | auto& controller = controller_data[i]; |
| 632 | } | ||
| 633 | |||
| 634 | const std::array<SixAxisGeneric*, 6> controller_sixaxes{ | ||
| 635 | &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, | ||
| 636 | &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, | ||
| 637 | }; | ||
| 638 | |||
| 639 | for (auto* sixaxis_sensor : controller_sixaxes) { | ||
| 640 | sixaxis_sensor->common.entry_count = 16; | ||
| 641 | sixaxis_sensor->common.total_entry_count = 17; | ||
| 642 | |||
| 643 | const auto& last_entry = | ||
| 644 | sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; | ||
| 645 | |||
| 646 | sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks(); | ||
| 647 | sixaxis_sensor->common.last_entry_index = | ||
| 648 | (sixaxis_sensor->common.last_entry_index + 1) % 17; | ||
| 649 | 529 | ||
| 650 | auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; | 530 | const auto& controller_type = controller.device->GetNpadStyleIndex(); |
| 651 | 531 | ||
| 652 | cur_entry.timestamp = last_entry.timestamp + 1; | 532 | if (controller_type == Core::HID::NpadStyleIndex::None || |
| 653 | cur_entry.timestamp2 = cur_entry.timestamp; | 533 | !controller.device->IsConnected()) { |
| 534 | continue; | ||
| 654 | } | 535 | } |
| 655 | 536 | ||
| 656 | // Try to read sixaxis sensor states | 537 | auto& npad = controller.shared_memory_entry; |
| 657 | std::array<MotionDevice, 2> motion_devices; | 538 | const auto& motion_state = controller.device->GetMotions(); |
| 658 | 539 | auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; | |
| 659 | if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) { | 540 | auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; |
| 660 | sixaxis_at_rest = true; | 541 | auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; |
| 661 | for (std::size_t e = 0; e < motion_devices.size(); ++e) { | 542 | auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; |
| 662 | const auto& device = motions[i][e]; | 543 | auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; |
| 663 | if (device) { | 544 | auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; |
| 664 | std::tie(motion_devices[e].accel, motion_devices[e].gyro, | 545 | |
| 665 | motion_devices[e].rotation, motion_devices[e].orientation, | 546 | if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { |
| 666 | motion_devices[e].quaternion) = device->GetStatus(); | 547 | controller.sixaxis_at_rest = true; |
| 667 | sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; | 548 | for (std::size_t e = 0; e < motion_state.size(); ++e) { |
| 668 | } | 549 | controller.sixaxis_at_rest = |
| 550 | controller.sixaxis_at_rest && motion_state[e].is_at_rest; | ||
| 669 | } | 551 | } |
| 670 | } | 552 | } |
| 671 | 553 | ||
| 672 | auto& full_sixaxis_entry = | ||
| 673 | npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index]; | ||
| 674 | auto& handheld_sixaxis_entry = | ||
| 675 | npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; | ||
| 676 | auto& dual_left_sixaxis_entry = | ||
| 677 | npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; | ||
| 678 | auto& dual_right_sixaxis_entry = | ||
| 679 | npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; | ||
| 680 | auto& left_sixaxis_entry = | ||
| 681 | npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; | ||
| 682 | auto& right_sixaxis_entry = | ||
| 683 | npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; | ||
| 684 | |||
| 685 | switch (controller_type) { | 554 | switch (controller_type) { |
| 686 | case NPadControllerType::None: | 555 | case Core::HID::NpadStyleIndex::None: |
| 687 | UNREACHABLE(); | 556 | UNREACHABLE(); |
| 688 | break; | 557 | break; |
| 689 | case NPadControllerType::ProController: | 558 | case Core::HID::NpadStyleIndex::ProController: |
| 690 | full_sixaxis_entry.attribute.raw = 0; | 559 | sixaxis_fullkey_state.attribute.raw = 0; |
| 691 | if (sixaxis_sensors_enabled && motions[i][0]) { | 560 | if (controller.sixaxis_sensor_enabled) { |
| 692 | full_sixaxis_entry.attribute.is_connected.Assign(1); | 561 | sixaxis_fullkey_state.attribute.is_connected.Assign(1); |
| 693 | full_sixaxis_entry.accel = motion_devices[0].accel; | 562 | sixaxis_fullkey_state.accel = motion_state[0].accel; |
| 694 | full_sixaxis_entry.gyro = motion_devices[0].gyro; | 563 | sixaxis_fullkey_state.gyro = motion_state[0].gyro; |
| 695 | full_sixaxis_entry.rotation = motion_devices[0].rotation; | 564 | sixaxis_fullkey_state.rotation = motion_state[0].rotation; |
| 696 | full_sixaxis_entry.orientation = motion_devices[0].orientation; | 565 | sixaxis_fullkey_state.orientation = motion_state[0].orientation; |
| 697 | } | 566 | } |
| 698 | break; | 567 | break; |
| 699 | case NPadControllerType::Handheld: | 568 | case Core::HID::NpadStyleIndex::Handheld: |
| 700 | handheld_sixaxis_entry.attribute.raw = 0; | 569 | sixaxis_handheld_state.attribute.raw = 0; |
| 701 | if (sixaxis_sensors_enabled && motions[i][0]) { | 570 | if (controller.sixaxis_sensor_enabled) { |
| 702 | handheld_sixaxis_entry.attribute.is_connected.Assign(1); | 571 | sixaxis_handheld_state.attribute.is_connected.Assign(1); |
| 703 | handheld_sixaxis_entry.accel = motion_devices[0].accel; | 572 | sixaxis_handheld_state.accel = motion_state[0].accel; |
| 704 | handheld_sixaxis_entry.gyro = motion_devices[0].gyro; | 573 | sixaxis_handheld_state.gyro = motion_state[0].gyro; |
| 705 | handheld_sixaxis_entry.rotation = motion_devices[0].rotation; | 574 | sixaxis_handheld_state.rotation = motion_state[0].rotation; |
| 706 | handheld_sixaxis_entry.orientation = motion_devices[0].orientation; | 575 | sixaxis_handheld_state.orientation = motion_state[0].orientation; |
| 707 | } | 576 | } |
| 708 | break; | 577 | break; |
| 709 | case NPadControllerType::JoyDual: | 578 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 710 | dual_left_sixaxis_entry.attribute.raw = 0; | 579 | sixaxis_dual_left_state.attribute.raw = 0; |
| 711 | dual_right_sixaxis_entry.attribute.raw = 0; | 580 | sixaxis_dual_right_state.attribute.raw = 0; |
| 712 | if (sixaxis_sensors_enabled && motions[i][0]) { | 581 | if (controller.sixaxis_sensor_enabled) { |
| 713 | // Set motion for the left joycon | 582 | // Set motion for the left joycon |
| 714 | dual_left_sixaxis_entry.attribute.is_connected.Assign(1); | 583 | sixaxis_dual_left_state.attribute.is_connected.Assign(1); |
| 715 | dual_left_sixaxis_entry.accel = motion_devices[0].accel; | 584 | sixaxis_dual_left_state.accel = motion_state[0].accel; |
| 716 | dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; | 585 | sixaxis_dual_left_state.gyro = motion_state[0].gyro; |
| 717 | dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; | 586 | sixaxis_dual_left_state.rotation = motion_state[0].rotation; |
| 718 | dual_left_sixaxis_entry.orientation = motion_devices[0].orientation; | 587 | sixaxis_dual_left_state.orientation = motion_state[0].orientation; |
| 719 | } | 588 | } |
| 720 | if (sixaxis_sensors_enabled && motions[i][1]) { | 589 | if (controller.sixaxis_sensor_enabled) { |
| 721 | // Set motion for the right joycon | 590 | // Set motion for the right joycon |
| 722 | dual_right_sixaxis_entry.attribute.is_connected.Assign(1); | 591 | sixaxis_dual_right_state.attribute.is_connected.Assign(1); |
| 723 | dual_right_sixaxis_entry.accel = motion_devices[1].accel; | 592 | sixaxis_dual_right_state.accel = motion_state[1].accel; |
| 724 | dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; | 593 | sixaxis_dual_right_state.gyro = motion_state[1].gyro; |
| 725 | dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; | 594 | sixaxis_dual_right_state.rotation = motion_state[1].rotation; |
| 726 | dual_right_sixaxis_entry.orientation = motion_devices[1].orientation; | 595 | sixaxis_dual_right_state.orientation = motion_state[1].orientation; |
| 727 | } | 596 | } |
| 728 | break; | 597 | break; |
| 729 | case NPadControllerType::JoyLeft: | 598 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 730 | left_sixaxis_entry.attribute.raw = 0; | 599 | sixaxis_left_lifo_state.attribute.raw = 0; |
| 731 | if (sixaxis_sensors_enabled && motions[i][0]) { | 600 | if (controller.sixaxis_sensor_enabled) { |
| 732 | left_sixaxis_entry.attribute.is_connected.Assign(1); | 601 | sixaxis_left_lifo_state.attribute.is_connected.Assign(1); |
| 733 | left_sixaxis_entry.accel = motion_devices[0].accel; | 602 | sixaxis_left_lifo_state.accel = motion_state[0].accel; |
| 734 | left_sixaxis_entry.gyro = motion_devices[0].gyro; | 603 | sixaxis_left_lifo_state.gyro = motion_state[0].gyro; |
| 735 | left_sixaxis_entry.rotation = motion_devices[0].rotation; | 604 | sixaxis_left_lifo_state.rotation = motion_state[0].rotation; |
| 736 | left_sixaxis_entry.orientation = motion_devices[0].orientation; | 605 | sixaxis_left_lifo_state.orientation = motion_state[0].orientation; |
| 737 | } | 606 | } |
| 738 | break; | 607 | break; |
| 739 | case NPadControllerType::JoyRight: | 608 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 740 | right_sixaxis_entry.attribute.raw = 0; | 609 | sixaxis_right_lifo_state.attribute.raw = 0; |
| 741 | if (sixaxis_sensors_enabled && motions[i][1]) { | 610 | if (controller.sixaxis_sensor_enabled) { |
| 742 | right_sixaxis_entry.attribute.is_connected.Assign(1); | 611 | sixaxis_right_lifo_state.attribute.is_connected.Assign(1); |
| 743 | right_sixaxis_entry.accel = motion_devices[1].accel; | 612 | sixaxis_right_lifo_state.accel = motion_state[1].accel; |
| 744 | right_sixaxis_entry.gyro = motion_devices[1].gyro; | 613 | sixaxis_right_lifo_state.gyro = motion_state[1].gyro; |
| 745 | right_sixaxis_entry.rotation = motion_devices[1].rotation; | 614 | sixaxis_right_lifo_state.rotation = motion_state[1].rotation; |
| 746 | right_sixaxis_entry.orientation = motion_devices[1].orientation; | 615 | sixaxis_right_lifo_state.orientation = motion_state[1].orientation; |
| 747 | } | 616 | } |
| 748 | break; | 617 | break; |
| 749 | case NPadControllerType::GameCube: | 618 | default: |
| 750 | case NPadControllerType::Pokeball: | ||
| 751 | break; | 619 | break; |
| 752 | } | 620 | } |
| 621 | |||
| 622 | sixaxis_fullkey_state.sampling_number = | ||
| 623 | npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 624 | sixaxis_handheld_state.sampling_number = | ||
| 625 | npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 626 | sixaxis_dual_left_state.sampling_number = | ||
| 627 | npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 628 | sixaxis_dual_right_state.sampling_number = | ||
| 629 | npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 630 | sixaxis_left_lifo_state.sampling_number = | ||
| 631 | npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 632 | sixaxis_right_lifo_state.sampling_number = | ||
| 633 | npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; | ||
| 634 | |||
| 635 | if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { | ||
| 636 | // This buffer only is updated on handheld on HW | ||
| 637 | npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); | ||
| 638 | } else { | ||
| 639 | // Handheld doesn't update this buffer on HW | ||
| 640 | npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); | ||
| 641 | } | ||
| 642 | |||
| 643 | npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); | ||
| 644 | npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); | ||
| 645 | npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); | ||
| 646 | npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); | ||
| 647 | std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), | ||
| 648 | &controller.shared_memory_entry, sizeof(NpadInternalState)); | ||
| 753 | } | 649 | } |
| 754 | std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), | ||
| 755 | shared_memory_entries.size() * sizeof(NPadEntry)); | ||
| 756 | } | 650 | } |
| 757 | 651 | ||
| 758 | void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) { | 652 | void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { |
| 759 | style.raw = style_set.raw; | 653 | hid_core.SetSupportedStyleTag(style_set); |
| 760 | } | 654 | } |
| 761 | 655 | ||
| 762 | Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const { | 656 | Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { |
| 763 | return style; | 657 | return hid_core.GetSupportedStyleTag(); |
| 764 | } | 658 | } |
| 765 | 659 | ||
| 766 | void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { | 660 | void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { |
| @@ -779,11 +673,11 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { | |||
| 779 | return supported_npad_id_types.size(); | 673 | return supported_npad_id_types.size(); |
| 780 | } | 674 | } |
| 781 | 675 | ||
| 782 | void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { | 676 | void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { |
| 783 | hold_type = joy_hold_type; | 677 | hold_type = joy_hold_type; |
| 784 | } | 678 | } |
| 785 | 679 | ||
| 786 | Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { | 680 | Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { |
| 787 | return hold_type; | 681 | return hold_type; |
| 788 | } | 682 | } |
| 789 | 683 | ||
| @@ -803,29 +697,91 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode | |||
| 803 | return communication_mode; | 697 | return communication_mode; |
| 804 | } | 698 | } |
| 805 | 699 | ||
| 806 | void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { | 700 | void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, |
| 807 | const std::size_t npad_index = NPadIdToIndex(npad_id); | 701 | NpadJoyAssignmentMode assignment_mode) { |
| 808 | ASSERT(npad_index < shared_memory_entries.size()); | 702 | if (!IsNpadIdValid(npad_id)) { |
| 809 | if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) { | 703 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 810 | shared_memory_entries[npad_index].assignment_mode = assignment_mode; | 704 | return; |
| 705 | } | ||
| 706 | |||
| 707 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 708 | if (controller.shared_memory_entry.assignment_mode != assignment_mode) { | ||
| 709 | controller.shared_memory_entry.assignment_mode = assignment_mode; | ||
| 710 | } | ||
| 711 | |||
| 712 | if (!controller.device->IsConnected()) { | ||
| 713 | return; | ||
| 714 | } | ||
| 715 | |||
| 716 | if (assignment_mode == NpadJoyAssignmentMode::Dual) { | ||
| 717 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { | ||
| 718 | DisconnectNpad(npad_id); | ||
| 719 | controller.is_dual_left_connected = true; | ||
| 720 | controller.is_dual_right_connected = false; | ||
| 721 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | ||
| 722 | return; | ||
| 723 | } | ||
| 724 | if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { | ||
| 725 | DisconnectNpad(npad_id); | ||
| 726 | controller.is_dual_left_connected = false; | ||
| 727 | controller.is_dual_right_connected = true; | ||
| 728 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); | ||
| 729 | return; | ||
| 730 | } | ||
| 731 | return; | ||
| 732 | } | ||
| 733 | |||
| 734 | // This is for NpadJoyAssignmentMode::Single | ||
| 735 | |||
| 736 | // Only JoyconDual get affected by this function | ||
| 737 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { | ||
| 738 | return; | ||
| 739 | } | ||
| 740 | |||
| 741 | if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { | ||
| 742 | DisconnectNpad(npad_id); | ||
| 743 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | ||
| 744 | return; | ||
| 745 | } | ||
| 746 | if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { | ||
| 747 | DisconnectNpad(npad_id); | ||
| 748 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | ||
| 749 | return; | ||
| 750 | } | ||
| 751 | |||
| 752 | // We have two controllers connected to the same npad_id we need to split them | ||
| 753 | const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId(); | ||
| 754 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); | ||
| 755 | DisconnectNpad(npad_id); | ||
| 756 | if (npad_device_type == NpadJoyDeviceType::Left) { | ||
| 757 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); | ||
| 758 | controller_2.is_dual_left_connected = false; | ||
| 759 | controller_2.is_dual_right_connected = true; | ||
| 760 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); | ||
| 761 | } else { | ||
| 762 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); | ||
| 763 | controller_2.is_dual_left_connected = true; | ||
| 764 | controller_2.is_dual_right_connected = false; | ||
| 765 | UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true); | ||
| 811 | } | 766 | } |
| 812 | } | 767 | } |
| 813 | 768 | ||
| 814 | bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, | 769 | bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, |
| 815 | const VibrationValue& vibration_value) { | 770 | std::size_t device_index, |
| 816 | if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { | 771 | const Core::HID::VibrationValue& vibration_value) { |
| 772 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 773 | if (!controller.device->IsConnected()) { | ||
| 817 | return false; | 774 | return false; |
| 818 | } | 775 | } |
| 819 | 776 | ||
| 820 | const auto& player = Settings::values.players.GetValue()[npad_index]; | 777 | if (!controller.device->IsVibrationEnabled()) { |
| 821 | 778 | if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || | |
| 822 | if (!player.vibration_enabled) { | 779 | controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { |
| 823 | if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || | ||
| 824 | latest_vibration_values[npad_index][device_index].amp_high != 0.0f) { | ||
| 825 | // Send an empty vibration to stop any vibrations. | 780 | // Send an empty vibration to stop any vibrations. |
| 826 | vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); | 781 | Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; |
| 782 | controller.device->SetVibration(device_index, vibration); | ||
| 827 | // Then reset the vibration value to its default value. | 783 | // Then reset the vibration value to its default value. |
| 828 | latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE; | 784 | controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE; |
| 829 | } | 785 | } |
| 830 | 786 | ||
| 831 | return false; | 787 | return false; |
| @@ -839,27 +795,25 @@ bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size | |||
| 839 | const auto now = steady_clock::now(); | 795 | const auto now = steady_clock::now(); |
| 840 | 796 | ||
| 841 | // Filter out non-zero vibrations that are within 10ms of each other. | 797 | // Filter out non-zero vibrations that are within 10ms of each other. |
| 842 | if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && | 798 | if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && |
| 843 | duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) < | 799 | duration_cast<milliseconds>( |
| 800 | now - controller.vibration[device_index].last_vibration_timepoint) < | ||
| 844 | milliseconds(10)) { | 801 | milliseconds(10)) { |
| 845 | return false; | 802 | return false; |
| 846 | } | 803 | } |
| 847 | 804 | ||
| 848 | last_vibration_timepoints[npad_index][device_index] = now; | 805 | controller.vibration[device_index].last_vibration_timepoint = now; |
| 849 | } | 806 | } |
| 850 | 807 | ||
| 851 | auto& vibration = vibrations[npad_index][device_index]; | 808 | Core::HID::VibrationValue vibration{ |
| 852 | const auto player_vibration_strength = static_cast<f32>(player.vibration_strength); | 809 | vibration_value.low_amplitude, vibration_value.low_frequency, |
| 853 | const auto amp_low = | 810 | vibration_value.high_amplitude, vibration_value.high_frequency}; |
| 854 | std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f); | 811 | return controller.device->SetVibration(device_index, vibration); |
| 855 | const auto amp_high = | ||
| 856 | std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f); | ||
| 857 | return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high, | ||
| 858 | vibration_value.freq_high); | ||
| 859 | } | 812 | } |
| 860 | 813 | ||
| 861 | void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, | 814 | void Controller_NPad::VibrateController( |
| 862 | const VibrationValue& vibration_value) { | 815 | const Core::HID::VibrationDeviceHandle& vibration_device_handle, |
| 816 | const Core::HID::VibrationValue& vibration_value) { | ||
| 863 | if (!IsDeviceHandleValid(vibration_device_handle)) { | 817 | if (!IsDeviceHandleValid(vibration_device_handle)) { |
| 864 | return; | 818 | return; |
| 865 | } | 819 | } |
| @@ -868,42 +822,45 @@ void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_han | |||
| 868 | return; | 822 | return; |
| 869 | } | 823 | } |
| 870 | 824 | ||
| 871 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | 825 | auto& controller = GetControllerFromHandle(vibration_device_handle); |
| 872 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 826 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 873 | 827 | ||
| 874 | if (!vibration_devices_mounted[npad_index][device_index] || | 828 | if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { |
| 875 | !connected_controllers[npad_index].is_connected) { | ||
| 876 | return; | 829 | return; |
| 877 | } | 830 | } |
| 878 | 831 | ||
| 879 | if (vibration_device_handle.device_index == DeviceIndex::None) { | 832 | if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { |
| 880 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | 833 | UNREACHABLE_MSG("DeviceIndex should never be None!"); |
| 881 | return; | 834 | return; |
| 882 | } | 835 | } |
| 883 | 836 | ||
| 884 | // Some games try to send mismatched parameters in the device handle, block these. | 837 | // Some games try to send mismatched parameters in the device handle, block these. |
| 885 | if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && | 838 | if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && |
| 886 | (vibration_device_handle.npad_type == NpadType::JoyconRight || | 839 | (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || |
| 887 | vibration_device_handle.device_index == DeviceIndex::Right)) || | 840 | vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || |
| 888 | (connected_controllers[npad_index].type == NPadControllerType::JoyRight && | 841 | (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && |
| 889 | (vibration_device_handle.npad_type == NpadType::JoyconLeft || | 842 | (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || |
| 890 | vibration_device_handle.device_index == DeviceIndex::Left))) { | 843 | vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) { |
| 891 | return; | 844 | return; |
| 892 | } | 845 | } |
| 893 | 846 | ||
| 894 | // Filter out vibrations with equivalent values to reduce unnecessary state changes. | 847 | // Filter out vibrations with equivalent values to reduce unnecessary state changes. |
| 895 | if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low && | 848 | if (vibration_value.low_amplitude == |
| 896 | vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) { | 849 | controller.vibration[device_index].latest_vibration_value.low_amplitude && |
| 850 | vibration_value.high_amplitude == | ||
| 851 | controller.vibration[device_index].latest_vibration_value.high_amplitude) { | ||
| 897 | return; | 852 | return; |
| 898 | } | 853 | } |
| 899 | 854 | ||
| 900 | if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { | 855 | if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, |
| 901 | latest_vibration_values[npad_index][device_index] = vibration_value; | 856 | vibration_value)) { |
| 857 | controller.vibration[device_index].latest_vibration_value = vibration_value; | ||
| 902 | } | 858 | } |
| 903 | } | 859 | } |
| 904 | 860 | ||
| 905 | void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, | 861 | void Controller_NPad::VibrateControllers( |
| 906 | const std::vector<VibrationValue>& vibration_values) { | 862 | const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, |
| 863 | const std::vector<Core::HID::VibrationValue>& vibration_values) { | ||
| 907 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | 864 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { |
| 908 | return; | 865 | return; |
| 909 | } | 866 | } |
| @@ -918,168 +875,285 @@ void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibrat | |||
| 918 | } | 875 | } |
| 919 | } | 876 | } |
| 920 | 877 | ||
| 921 | Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( | 878 | Core::HID::VibrationValue Controller_NPad::GetLastVibration( |
| 922 | const DeviceHandle& vibration_device_handle) const { | 879 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { |
| 923 | if (!IsDeviceHandleValid(vibration_device_handle)) { | 880 | if (!IsDeviceHandleValid(vibration_device_handle)) { |
| 924 | return {}; | 881 | return {}; |
| 925 | } | 882 | } |
| 926 | 883 | ||
| 927 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | 884 | const auto& controller = GetControllerFromHandle(vibration_device_handle); |
| 928 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 885 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 929 | return latest_vibration_values[npad_index][device_index]; | 886 | return controller.vibration[device_index].latest_vibration_value; |
| 930 | } | 887 | } |
| 931 | 888 | ||
| 932 | void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { | 889 | void Controller_NPad::InitializeVibrationDevice( |
| 890 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) { | ||
| 933 | if (!IsDeviceHandleValid(vibration_device_handle)) { | 891 | if (!IsDeviceHandleValid(vibration_device_handle)) { |
| 934 | return; | 892 | return; |
| 935 | } | 893 | } |
| 936 | 894 | ||
| 937 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | 895 | const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); |
| 938 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 896 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 939 | InitializeVibrationDeviceAtIndex(npad_index, device_index); | 897 | InitializeVibrationDeviceAtIndex(npad_index, device_index); |
| 940 | } | 898 | } |
| 941 | 899 | ||
| 942 | void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, | 900 | void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, |
| 943 | std::size_t device_index) { | 901 | std::size_t device_index) { |
| 902 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 944 | if (!Settings::values.vibration_enabled.GetValue()) { | 903 | if (!Settings::values.vibration_enabled.GetValue()) { |
| 945 | vibration_devices_mounted[npad_index][device_index] = false; | 904 | controller.vibration[device_index].device_mounted = false; |
| 946 | return; | 905 | return; |
| 947 | } | 906 | } |
| 948 | 907 | ||
| 949 | if (vibrations[npad_index][device_index]) { | 908 | controller.vibration[device_index].device_mounted = |
| 950 | vibration_devices_mounted[npad_index][device_index] = | 909 | controller.device->TestVibration(device_index); |
| 951 | vibrations[npad_index][device_index]->GetStatus() == 1; | ||
| 952 | } else { | ||
| 953 | vibration_devices_mounted[npad_index][device_index] = false; | ||
| 954 | } | ||
| 955 | } | 910 | } |
| 956 | 911 | ||
| 957 | void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { | 912 | void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { |
| 958 | permit_vibration_session_enabled = permit_vibration_session; | 913 | permit_vibration_session_enabled = permit_vibration_session; |
| 959 | } | 914 | } |
| 960 | 915 | ||
| 961 | bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { | 916 | bool Controller_NPad::IsVibrationDeviceMounted( |
| 917 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { | ||
| 962 | if (!IsDeviceHandleValid(vibration_device_handle)) { | 918 | if (!IsDeviceHandleValid(vibration_device_handle)) { |
| 963 | return false; | 919 | return false; |
| 964 | } | 920 | } |
| 965 | 921 | ||
| 966 | const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); | 922 | const auto& controller = GetControllerFromHandle(vibration_device_handle); |
| 967 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | 923 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 968 | return vibration_devices_mounted[npad_index][device_index]; | 924 | return controller.vibration[device_index].device_mounted; |
| 969 | } | 925 | } |
| 970 | 926 | ||
| 971 | Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) { | 927 | Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { |
| 972 | return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent(); | 928 | if (!IsNpadIdValid(npad_id)) { |
| 929 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | ||
| 930 | // Fallback to player 1 | ||
| 931 | const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); | ||
| 932 | return controller.styleset_changed_event->GetReadableEvent(); | ||
| 933 | } | ||
| 934 | |||
| 935 | const auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 936 | return controller.styleset_changed_event->GetReadableEvent(); | ||
| 973 | } | 937 | } |
| 974 | 938 | ||
| 975 | void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { | 939 | void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { |
| 976 | styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal(); | 940 | const auto& controller = GetControllerFromNpadIdType(npad_id); |
| 941 | controller.styleset_changed_event->GetWritableEvent().Signal(); | ||
| 977 | } | 942 | } |
| 978 | 943 | ||
| 979 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { | 944 | void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, |
| 980 | UpdateControllerAt(controller, npad_index, true); | 945 | Core::HID::NpadIdType npad_id) { |
| 946 | UpdateControllerAt(controller, npad_id, true); | ||
| 981 | } | 947 | } |
| 982 | 948 | ||
| 983 | void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, | 949 | void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, |
| 984 | bool connected) { | 950 | Core::HID::NpadIdType npad_id, bool connected) { |
| 951 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 985 | if (!connected) { | 952 | if (!connected) { |
| 986 | DisconnectNpadAtIndex(npad_index); | 953 | DisconnectNpad(npad_id); |
| 987 | return; | ||
| 988 | } | ||
| 989 | |||
| 990 | if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) { | ||
| 991 | Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = | ||
| 992 | MapNPadToSettingsType(controller); | ||
| 993 | Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; | ||
| 994 | connected_controllers[HANDHELD_INDEX] = {controller, true}; | ||
| 995 | InitNewlyAddedController(HANDHELD_INDEX); | ||
| 996 | return; | 954 | return; |
| 997 | } | 955 | } |
| 998 | 956 | ||
| 999 | Settings::values.players.GetValue()[npad_index].controller_type = | 957 | controller.device->SetNpadStyleIndex(type); |
| 1000 | MapNPadToSettingsType(controller); | 958 | InitNewlyAddedController(npad_id); |
| 1001 | Settings::values.players.GetValue()[npad_index].connected = true; | ||
| 1002 | connected_controllers[npad_index] = {controller, true}; | ||
| 1003 | InitNewlyAddedController(npad_index); | ||
| 1004 | } | 959 | } |
| 1005 | 960 | ||
| 1006 | void Controller_NPad::DisconnectNpad(u32 npad_id) { | 961 | void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { |
| 1007 | DisconnectNpadAtIndex(NPadIdToIndex(npad_id)); | 962 | if (!IsNpadIdValid(npad_id)) { |
| 1008 | } | 963 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 964 | return; | ||
| 965 | } | ||
| 1009 | 966 | ||
| 1010 | void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { | 967 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); |
| 1011 | for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { | 968 | auto& controller = GetControllerFromNpadIdType(npad_id); |
| 969 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { | ||
| 1012 | // Send an empty vibration to stop any vibrations. | 970 | // Send an empty vibration to stop any vibrations. |
| 1013 | VibrateControllerAtIndex(npad_index, device_idx, {}); | 971 | VibrateControllerAtIndex(npad_id, device_idx, {}); |
| 1014 | vibration_devices_mounted[npad_index][device_idx] = false; | 972 | controller.vibration[device_idx].device_mounted = false; |
| 1015 | } | 973 | } |
| 1016 | 974 | ||
| 1017 | Settings::values.players.GetValue()[npad_index].connected = false; | 975 | auto& shared_memory_entry = controller.shared_memory_entry; |
| 1018 | connected_controllers[npad_index].is_connected = false; | 976 | // Don't reset shared_memory_entry.assignment_mode this value is persistent |
| 1019 | 977 | shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out | |
| 1020 | auto& controller = shared_memory_entries[npad_index]; | 978 | shared_memory_entry.device_type.raw = 0; |
| 1021 | controller.style_set.raw = 0; // Zero out | 979 | shared_memory_entry.system_properties.raw = 0; |
| 1022 | controller.device_type.raw = 0; | 980 | shared_memory_entry.button_properties.raw = 0; |
| 1023 | controller.system_properties.raw = 0; | 981 | shared_memory_entry.battery_level_dual = 0; |
| 1024 | controller.button_properties.raw = 0; | 982 | shared_memory_entry.battery_level_left = 0; |
| 1025 | controller.battery_level_dual = 0; | 983 | shared_memory_entry.battery_level_right = 0; |
| 1026 | controller.battery_level_left = 0; | 984 | shared_memory_entry.fullkey_color = { |
| 1027 | controller.battery_level_right = 0; | 985 | .attribute = ColorAttribute::NoController, |
| 1028 | controller.fullkey_color = {}; | 986 | .fullkey = {}, |
| 1029 | controller.joycon_color = {}; | 987 | }; |
| 1030 | controller.assignment_mode = NpadAssignments::Dual; | 988 | shared_memory_entry.joycon_color = { |
| 1031 | controller.footer_type = AppletFooterUiType::None; | 989 | .attribute = ColorAttribute::NoController, |
| 990 | .left = {}, | ||
| 991 | .right = {}, | ||
| 992 | }; | ||
| 993 | shared_memory_entry.applet_footer.type = AppletFooterUiType::None; | ||
| 994 | |||
| 995 | controller.is_dual_left_connected = true; | ||
| 996 | controller.is_dual_right_connected = true; | ||
| 997 | controller.is_connected = false; | ||
| 998 | controller.device->Disconnect(); | ||
| 999 | SignalStyleSetChangedEvent(npad_id); | ||
| 1000 | WriteEmptyEntry(controller.shared_memory_entry); | ||
| 1001 | } | ||
| 1032 | 1002 | ||
| 1033 | SignalStyleSetChangedEvent(IndexToNPad(npad_index)); | 1003 | void Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 1004 | GyroscopeZeroDriftMode drift_mode) { | ||
| 1005 | if (!IsDeviceHandleValid(sixaxis_handle)) { | ||
| 1006 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1007 | return; | ||
| 1008 | } | ||
| 1009 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1010 | controller.gyroscope_zero_drift_mode = drift_mode; | ||
| 1034 | } | 1011 | } |
| 1035 | 1012 | ||
| 1036 | void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { | 1013 | Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode( |
| 1037 | gyroscope_zero_drift_mode = drift_mode; | 1014 | Core::HID::SixAxisSensorHandle sixaxis_handle) const { |
| 1015 | if (!IsDeviceHandleValid(sixaxis_handle)) { | ||
| 1016 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1017 | // Return the default value | ||
| 1018 | return GyroscopeZeroDriftMode::Standard; | ||
| 1019 | } | ||
| 1020 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1021 | return controller.gyroscope_zero_drift_mode; | ||
| 1038 | } | 1022 | } |
| 1039 | 1023 | ||
| 1040 | Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const { | 1024 | bool Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const { |
| 1041 | return gyroscope_zero_drift_mode; | 1025 | if (!IsDeviceHandleValid(sixaxis_handle)) { |
| 1026 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1027 | // Return the default value | ||
| 1028 | return true; | ||
| 1029 | } | ||
| 1030 | const auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1031 | return controller.sixaxis_at_rest; | ||
| 1042 | } | 1032 | } |
| 1043 | 1033 | ||
| 1044 | bool Controller_NPad::IsSixAxisSensorAtRest() const { | 1034 | void Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 1045 | return sixaxis_at_rest; | 1035 | bool sixaxis_status) { |
| 1036 | if (!IsDeviceHandleValid(sixaxis_handle)) { | ||
| 1037 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1038 | return; | ||
| 1039 | } | ||
| 1040 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1041 | controller.sixaxis_sensor_enabled = sixaxis_status; | ||
| 1046 | } | 1042 | } |
| 1047 | 1043 | ||
| 1048 | void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { | 1044 | void Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 1049 | sixaxis_sensors_enabled = six_axis_status; | 1045 | bool sixaxis_fusion_status) { |
| 1046 | if (!IsDeviceHandleValid(sixaxis_handle)) { | ||
| 1047 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1048 | return; | ||
| 1049 | } | ||
| 1050 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1051 | controller.sixaxis_fusion_enabled = sixaxis_fusion_status; | ||
| 1050 | } | 1052 | } |
| 1051 | 1053 | ||
| 1052 | void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) { | 1054 | void Controller_NPad::SetSixAxisFusionParameters( |
| 1053 | sixaxis_fusion_parameter1 = parameter1; | 1055 | Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 1054 | sixaxis_fusion_parameter2 = parameter2; | 1056 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { |
| 1057 | if (!IsDeviceHandleValid(sixaxis_handle)) { | ||
| 1058 | LOG_ERROR(Service_HID, "Invalid handle"); | ||
| 1059 | return; | ||
| 1060 | } | ||
| 1061 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1062 | controller.sixaxis_fusion = sixaxis_fusion_parameters; | ||
| 1055 | } | 1063 | } |
| 1056 | 1064 | ||
| 1057 | std::pair<f32, f32> Controller_NPad::GetSixAxisFusionParameters() { | 1065 | Core::HID::SixAxisSensorFusionParameters Controller_NPad::GetSixAxisFusionParameters( |
| 1058 | return { | 1066 | Core::HID::SixAxisSensorHandle sixaxis_handle) { |
| 1059 | sixaxis_fusion_parameter1, | 1067 | if (!IsDeviceHandleValid(sixaxis_handle)) { |
| 1060 | sixaxis_fusion_parameter2, | 1068 | LOG_ERROR(Service_HID, "Invalid handle"); |
| 1061 | }; | 1069 | // Since these parameters are unknow just return zeros |
| 1070 | return {}; | ||
| 1071 | } | ||
| 1072 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1073 | return controller.sixaxis_fusion; | ||
| 1062 | } | 1074 | } |
| 1063 | 1075 | ||
| 1064 | void Controller_NPad::ResetSixAxisFusionParameters() { | 1076 | void Controller_NPad::ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle) { |
| 1065 | sixaxis_fusion_parameter1 = 0.0f; | 1077 | if (!IsDeviceHandleValid(sixaxis_handle)) { |
| 1066 | sixaxis_fusion_parameter2 = 0.0f; | 1078 | LOG_ERROR(Service_HID, "Invalid handle"); |
| 1079 | return; | ||
| 1080 | } | ||
| 1081 | auto& controller = GetControllerFromHandle(sixaxis_handle); | ||
| 1082 | // Since these parameters are unknow just fill with zeros | ||
| 1083 | controller.sixaxis_fusion = {}; | ||
| 1067 | } | 1084 | } |
| 1068 | 1085 | ||
| 1069 | void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { | 1086 | void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, |
| 1070 | const auto npad_index_1 = NPadIdToIndex(npad_id_1); | 1087 | Core::HID::NpadIdType npad_id_2) { |
| 1071 | const auto npad_index_2 = NPadIdToIndex(npad_id_2); | 1088 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1089 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | ||
| 1090 | npad_id_2); | ||
| 1091 | return; | ||
| 1092 | } | ||
| 1093 | auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); | ||
| 1094 | auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); | ||
| 1095 | const auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); | ||
| 1096 | const auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); | ||
| 1097 | bool merge_controllers = false; | ||
| 1072 | 1098 | ||
| 1073 | // If the controllers at both npad indices form a pair of left and right joycons, merge them. | 1099 | // If the controllers at both npad indices form a pair of left and right joycons, merge them. |
| 1074 | // Otherwise, do nothing. | 1100 | // Otherwise, do nothing. |
| 1075 | if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft && | 1101 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && |
| 1076 | connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) || | 1102 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { |
| 1077 | (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && | 1103 | merge_controllers = true; |
| 1078 | connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { | 1104 | } |
| 1105 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 1106 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) { | ||
| 1107 | merge_controllers = true; | ||
| 1108 | } | ||
| 1109 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1110 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight && | ||
| 1111 | controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { | ||
| 1112 | merge_controllers = true; | ||
| 1113 | } | ||
| 1114 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1115 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 1116 | !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { | ||
| 1117 | merge_controllers = true; | ||
| 1118 | } | ||
| 1119 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1120 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && | ||
| 1121 | controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { | ||
| 1122 | merge_controllers = true; | ||
| 1123 | } | ||
| 1124 | if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1125 | controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 1126 | !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { | ||
| 1127 | merge_controllers = true; | ||
| 1128 | } | ||
| 1129 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1130 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1131 | controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected && | ||
| 1132 | !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { | ||
| 1133 | merge_controllers = true; | ||
| 1134 | } | ||
| 1135 | if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1136 | controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual && | ||
| 1137 | !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected && | ||
| 1138 | controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { | ||
| 1139 | merge_controllers = true; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | if (merge_controllers) { | ||
| 1079 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. | 1143 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. |
| 1080 | DisconnectNpad(npad_id_2); | 1144 | DisconnectNpad(npad_id_2); |
| 1081 | AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); | 1145 | controller_1.is_dual_left_connected = true; |
| 1146 | controller_1.is_dual_right_connected = true; | ||
| 1147 | AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); | ||
| 1148 | return; | ||
| 1082 | } | 1149 | } |
| 1150 | LOG_WARNING(Service_HID, | ||
| 1151 | "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, " | ||
| 1152 | "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}", | ||
| 1153 | npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(), | ||
| 1154 | controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected, | ||
| 1155 | controller_1.is_dual_right_connected, controller_2.is_dual_left_connected, | ||
| 1156 | controller_2.is_dual_right_connected); | ||
| 1083 | } | 1157 | } |
| 1084 | 1158 | ||
| 1085 | void Controller_NPad::StartLRAssignmentMode() { | 1159 | void Controller_NPad::StartLRAssignmentMode() { |
| @@ -1092,61 +1166,66 @@ void Controller_NPad::StopLRAssignmentMode() { | |||
| 1092 | is_in_lr_assignment_mode = false; | 1166 | is_in_lr_assignment_mode = false; |
| 1093 | } | 1167 | } |
| 1094 | 1168 | ||
| 1095 | bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { | 1169 | bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, |
| 1096 | if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN || | 1170 | Core::HID::NpadIdType npad_id_2) { |
| 1097 | npad_id_2 == NPAD_UNKNOWN) { | 1171 | if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { |
| 1172 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, | ||
| 1173 | npad_id_2); | ||
| 1174 | return false; | ||
| 1175 | } | ||
| 1176 | if (npad_id_1 == Core::HID::NpadIdType::Handheld || | ||
| 1177 | npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || | ||
| 1178 | npad_id_2 == Core::HID::NpadIdType::Other) { | ||
| 1098 | return true; | 1179 | return true; |
| 1099 | } | 1180 | } |
| 1100 | const auto npad_index_1 = NPadIdToIndex(npad_id_1); | 1181 | const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; |
| 1101 | const auto npad_index_2 = NPadIdToIndex(npad_id_2); | 1182 | const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; |
| 1102 | 1183 | const auto type_index_1 = controller_1->GetNpadStyleIndex(); | |
| 1103 | if (!IsControllerSupported(connected_controllers[npad_index_1].type) || | 1184 | const auto type_index_2 = controller_2->GetNpadStyleIndex(); |
| 1104 | !IsControllerSupported(connected_controllers[npad_index_2].type)) { | 1185 | const auto is_connected_1 = controller_1->IsConnected(); |
| 1186 | const auto is_connected_2 = controller_2->IsConnected(); | ||
| 1187 | |||
| 1188 | if (!IsControllerSupported(type_index_1) && is_connected_1) { | ||
| 1189 | return false; | ||
| 1190 | } | ||
| 1191 | if (!IsControllerSupported(type_index_2) && is_connected_2) { | ||
| 1105 | return false; | 1192 | return false; |
| 1106 | } | 1193 | } |
| 1107 | 1194 | ||
| 1108 | std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); | 1195 | UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); |
| 1109 | 1196 | UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); | |
| 1110 | AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1); | ||
| 1111 | AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2); | ||
| 1112 | 1197 | ||
| 1113 | return true; | 1198 | return true; |
| 1114 | } | 1199 | } |
| 1115 | 1200 | ||
| 1116 | Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { | 1201 | Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) { |
| 1117 | if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { | 1202 | if (!IsNpadIdValid(npad_id)) { |
| 1118 | // These are controllers without led patterns | 1203 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); |
| 1119 | return LedPattern{0, 0, 0, 0}; | 1204 | return Core::HID::LedPattern{0, 0, 0, 0}; |
| 1120 | } | ||
| 1121 | switch (npad_id) { | ||
| 1122 | case 0: | ||
| 1123 | return LedPattern{1, 0, 0, 0}; | ||
| 1124 | case 1: | ||
| 1125 | return LedPattern{1, 1, 0, 0}; | ||
| 1126 | case 2: | ||
| 1127 | return LedPattern{1, 1, 1, 0}; | ||
| 1128 | case 3: | ||
| 1129 | return LedPattern{1, 1, 1, 1}; | ||
| 1130 | case 4: | ||
| 1131 | return LedPattern{1, 0, 0, 1}; | ||
| 1132 | case 5: | ||
| 1133 | return LedPattern{1, 0, 1, 0}; | ||
| 1134 | case 6: | ||
| 1135 | return LedPattern{1, 0, 1, 1}; | ||
| 1136 | case 7: | ||
| 1137 | return LedPattern{0, 1, 1, 0}; | ||
| 1138 | default: | ||
| 1139 | return LedPattern{0, 0, 0, 0}; | ||
| 1140 | } | 1205 | } |
| 1206 | const auto& controller = GetControllerFromNpadIdType(npad_id).device; | ||
| 1207 | return controller->GetLedPattern(); | ||
| 1141 | } | 1208 | } |
| 1142 | 1209 | ||
| 1143 | bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { | 1210 | bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( |
| 1144 | return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; | 1211 | Core::HID::NpadIdType npad_id) const { |
| 1212 | if (!IsNpadIdValid(npad_id)) { | ||
| 1213 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | ||
| 1214 | // Return the default value | ||
| 1215 | return false; | ||
| 1216 | } | ||
| 1217 | const auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 1218 | return controller.unintended_home_button_input_protection; | ||
| 1145 | } | 1219 | } |
| 1146 | 1220 | ||
| 1147 | void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | 1221 | void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, |
| 1148 | u32 npad_id) { | 1222 | Core::HID::NpadIdType npad_id) { |
| 1149 | unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; | 1223 | if (!IsNpadIdValid(npad_id)) { |
| 1224 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | ||
| 1225 | return; | ||
| 1226 | } | ||
| 1227 | auto& controller = GetControllerFromNpadIdType(npad_id); | ||
| 1228 | controller.unintended_home_button_input_protection = is_protection_enabled; | ||
| 1150 | } | 1229 | } |
| 1151 | 1230 | ||
| 1152 | void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { | 1231 | void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { |
| @@ -1154,49 +1233,51 @@ void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { | |||
| 1154 | } | 1233 | } |
| 1155 | 1234 | ||
| 1156 | void Controller_NPad::ClearAllConnectedControllers() { | 1235 | void Controller_NPad::ClearAllConnectedControllers() { |
| 1157 | for (auto& controller : connected_controllers) { | 1236 | for (auto& controller : controller_data) { |
| 1158 | if (controller.is_connected && controller.type != NPadControllerType::None) { | 1237 | if (controller.device->IsConnected() && |
| 1159 | controller.type = NPadControllerType::None; | 1238 | controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { |
| 1160 | controller.is_connected = false; | 1239 | controller.device->Disconnect(); |
| 1240 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); | ||
| 1161 | } | 1241 | } |
| 1162 | } | 1242 | } |
| 1163 | } | 1243 | } |
| 1164 | 1244 | ||
| 1165 | void Controller_NPad::DisconnectAllConnectedControllers() { | 1245 | void Controller_NPad::DisconnectAllConnectedControllers() { |
| 1166 | for (auto& controller : connected_controllers) { | 1246 | for (auto& controller : controller_data) { |
| 1167 | controller.is_connected = false; | 1247 | controller.device->Disconnect(); |
| 1168 | } | 1248 | } |
| 1169 | } | 1249 | } |
| 1170 | 1250 | ||
| 1171 | void Controller_NPad::ConnectAllDisconnectedControllers() { | 1251 | void Controller_NPad::ConnectAllDisconnectedControllers() { |
| 1172 | for (auto& controller : connected_controllers) { | 1252 | for (auto& controller : controller_data) { |
| 1173 | if (controller.type != NPadControllerType::None && !controller.is_connected) { | 1253 | if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && |
| 1174 | controller.is_connected = true; | 1254 | !controller.device->IsConnected()) { |
| 1255 | controller.device->Connect(); | ||
| 1175 | } | 1256 | } |
| 1176 | } | 1257 | } |
| 1177 | } | 1258 | } |
| 1178 | 1259 | ||
| 1179 | void Controller_NPad::ClearAllControllers() { | 1260 | void Controller_NPad::ClearAllControllers() { |
| 1180 | for (auto& controller : connected_controllers) { | 1261 | for (auto& controller : controller_data) { |
| 1181 | controller.type = NPadControllerType::None; | 1262 | controller.device->Disconnect(); |
| 1182 | controller.is_connected = false; | 1263 | controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); |
| 1183 | } | 1264 | } |
| 1184 | } | 1265 | } |
| 1185 | 1266 | ||
| 1186 | u32 Controller_NPad::GetAndResetPressState() { | 1267 | Core::HID::NpadButton Controller_NPad::GetAndResetPressState() { |
| 1187 | return press_state.exchange(0); | 1268 | return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); |
| 1188 | } | 1269 | } |
| 1189 | 1270 | ||
| 1190 | bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { | 1271 | bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { |
| 1191 | if (controller == NPadControllerType::Handheld) { | 1272 | if (controller == Core::HID::NpadStyleIndex::Handheld) { |
| 1192 | const bool support_handheld = | 1273 | const bool support_handheld = |
| 1193 | std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), | 1274 | std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), |
| 1194 | NPAD_HANDHELD) != supported_npad_id_types.end(); | 1275 | Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); |
| 1195 | // Handheld is not even a supported type, lets stop here | 1276 | // Handheld is not even a supported type, lets stop here |
| 1196 | if (!support_handheld) { | 1277 | if (!support_handheld) { |
| 1197 | return false; | 1278 | return false; |
| 1198 | } | 1279 | } |
| 1199 | // Handheld should not be supported in docked mode | 1280 | // Handheld shouldn't be supported in docked mode |
| 1200 | if (Settings::values.use_docked_mode.GetValue()) { | 1281 | if (Settings::values.use_docked_mode.GetValue()) { |
| 1201 | return false; | 1282 | return false; |
| 1202 | } | 1283 | } |
| @@ -1205,20 +1286,31 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const | |||
| 1205 | } | 1286 | } |
| 1206 | 1287 | ||
| 1207 | if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), | 1288 | if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), |
| 1208 | [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { | 1289 | [](Core::HID::NpadIdType npad_id) { |
| 1290 | return npad_id <= Core::HID::NpadIdType::Player8; | ||
| 1291 | })) { | ||
| 1292 | Core::HID::NpadStyleTag style = GetSupportedStyleSet(); | ||
| 1209 | switch (controller) { | 1293 | switch (controller) { |
| 1210 | case NPadControllerType::ProController: | 1294 | case Core::HID::NpadStyleIndex::ProController: |
| 1211 | return style.fullkey; | 1295 | return style.fullkey; |
| 1212 | case NPadControllerType::JoyDual: | 1296 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1213 | return style.joycon_dual; | 1297 | return style.joycon_dual; |
| 1214 | case NPadControllerType::JoyLeft: | 1298 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 1215 | return style.joycon_left; | 1299 | return style.joycon_left; |
| 1216 | case NPadControllerType::JoyRight: | 1300 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 1217 | return style.joycon_right; | 1301 | return style.joycon_right; |
| 1218 | case NPadControllerType::GameCube: | 1302 | case Core::HID::NpadStyleIndex::GameCube: |
| 1219 | return style.gamecube; | 1303 | return style.gamecube; |
| 1220 | case NPadControllerType::Pokeball: | 1304 | case Core::HID::NpadStyleIndex::Pokeball: |
| 1221 | return style.palma; | 1305 | return style.palma; |
| 1306 | case Core::HID::NpadStyleIndex::NES: | ||
| 1307 | return style.lark; | ||
| 1308 | case Core::HID::NpadStyleIndex::SNES: | ||
| 1309 | return style.lucia; | ||
| 1310 | case Core::HID::NpadStyleIndex::N64: | ||
| 1311 | return style.lagoon; | ||
| 1312 | case Core::HID::NpadStyleIndex::SegaGenesis: | ||
| 1313 | return style.lager; | ||
| 1222 | default: | 1314 | default: |
| 1223 | return false; | 1315 | return false; |
| 1224 | } | 1316 | } |
| @@ -1227,4 +1319,48 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const | |||
| 1227 | return false; | 1319 | return false; |
| 1228 | } | 1320 | } |
| 1229 | 1321 | ||
| 1322 | Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( | ||
| 1323 | const Core::HID::SixAxisSensorHandle& device_handle) { | ||
| 1324 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | ||
| 1325 | return GetControllerFromNpadIdType(npad_id); | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( | ||
| 1329 | const Core::HID::SixAxisSensorHandle& device_handle) const { | ||
| 1330 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | ||
| 1331 | return GetControllerFromNpadIdType(npad_id); | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( | ||
| 1335 | const Core::HID::VibrationDeviceHandle& device_handle) { | ||
| 1336 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | ||
| 1337 | return GetControllerFromNpadIdType(npad_id); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( | ||
| 1341 | const Core::HID::VibrationDeviceHandle& device_handle) const { | ||
| 1342 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | ||
| 1343 | return GetControllerFromNpadIdType(npad_id); | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( | ||
| 1347 | Core::HID::NpadIdType npad_id) { | ||
| 1348 | if (!IsNpadIdValid(npad_id)) { | ||
| 1349 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | ||
| 1350 | npad_id = Core::HID::NpadIdType::Player1; | ||
| 1351 | } | ||
| 1352 | const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); | ||
| 1353 | return controller_data[npad_index]; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( | ||
| 1357 | Core::HID::NpadIdType npad_id) const { | ||
| 1358 | if (!IsNpadIdValid(npad_id)) { | ||
| 1359 | LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); | ||
| 1360 | npad_id = Core::HID::NpadIdType::Player1; | ||
| 1361 | } | ||
| 1362 | const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); | ||
| 1363 | return controller_data[npad_index]; | ||
| 1364 | } | ||
| 1365 | |||
| 1230 | } // namespace Service::HID | 1366 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 9ee146caf..63281cb35 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -11,9 +11,14 @@ | |||
| 11 | #include "common/bit_field.h" | 11 | #include "common/bit_field.h" |
| 12 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 13 | #include "common/quaternion.h" | 13 | #include "common/quaternion.h" |
| 14 | #include "common/settings.h" | 14 | #include "core/hid/hid_types.h" |
| 15 | #include "core/frontend/input.h" | ||
| 16 | #include "core/hle/service/hid/controllers/controller_base.h" | 15 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 16 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 17 | |||
| 18 | namespace Core::HID { | ||
| 19 | class EmulatedController; | ||
| 20 | enum class ControllerTriggerType; | ||
| 21 | } // namespace Core::HID | ||
| 17 | 22 | ||
| 18 | namespace Kernel { | 23 | namespace Kernel { |
| 19 | class KEvent; | 24 | class KEvent; |
| @@ -26,12 +31,9 @@ class ServiceContext; | |||
| 26 | 31 | ||
| 27 | namespace Service::HID { | 32 | namespace Service::HID { |
| 28 | 33 | ||
| 29 | constexpr u32 NPAD_HANDHELD = 32; | ||
| 30 | constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? | ||
| 31 | |||
| 32 | class Controller_NPad final : public ControllerBase { | 34 | class Controller_NPad final : public ControllerBase { |
| 33 | public: | 35 | public: |
| 34 | explicit Controller_NPad(Core::System& system_, | 36 | explicit Controller_NPad(Core::HID::HIDCore& hid_core_, |
| 35 | KernelHelpers::ServiceContext& service_context_); | 37 | KernelHelpers::ServiceContext& service_context_); |
| 36 | ~Controller_NPad() override; | 38 | ~Controller_NPad() override; |
| 37 | 39 | ||
| @@ -48,60 +50,39 @@ public: | |||
| 48 | void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 50 | void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 49 | std::size_t size) override; | 51 | std::size_t size) override; |
| 50 | 52 | ||
| 51 | // Called when input devices should be loaded | 53 | // This is nn::hid::GyroscopeZeroDriftMode |
| 52 | void OnLoadInputDevices() override; | ||
| 53 | |||
| 54 | enum class NPadControllerType { | ||
| 55 | None, | ||
| 56 | ProController, | ||
| 57 | Handheld, | ||
| 58 | JoyDual, | ||
| 59 | JoyLeft, | ||
| 60 | JoyRight, | ||
| 61 | GameCube, | ||
| 62 | Pokeball, | ||
| 63 | }; | ||
| 64 | |||
| 65 | enum class NpadType : u8 { | ||
| 66 | ProController = 3, | ||
| 67 | Handheld = 4, | ||
| 68 | JoyconDual = 5, | ||
| 69 | JoyconLeft = 6, | ||
| 70 | JoyconRight = 7, | ||
| 71 | GameCube = 8, | ||
| 72 | Pokeball = 9, | ||
| 73 | MaxNpadType = 10, | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum class DeviceIndex : u8 { | ||
| 77 | Left = 0, | ||
| 78 | Right = 1, | ||
| 79 | None = 2, | ||
| 80 | MaxDeviceIndex = 3, | ||
| 81 | }; | ||
| 82 | |||
| 83 | enum class GyroscopeZeroDriftMode : u32 { | 54 | enum class GyroscopeZeroDriftMode : u32 { |
| 84 | Loose = 0, | 55 | Loose = 0, |
| 85 | Standard = 1, | 56 | Standard = 1, |
| 86 | Tight = 2, | 57 | Tight = 2, |
| 87 | }; | 58 | }; |
| 88 | 59 | ||
| 89 | enum class NpadHoldType : u64 { | 60 | // This is nn::hid::NpadJoyHoldType |
| 61 | enum class NpadJoyHoldType : u64 { | ||
| 90 | Vertical = 0, | 62 | Vertical = 0, |
| 91 | Horizontal = 1, | 63 | Horizontal = 1, |
| 92 | }; | 64 | }; |
| 93 | 65 | ||
| 94 | enum class NpadAssignments : u32 { | 66 | // This is nn::hid::NpadJoyAssignmentMode |
| 67 | enum class NpadJoyAssignmentMode : u32 { | ||
| 95 | Dual = 0, | 68 | Dual = 0, |
| 96 | Single = 1, | 69 | Single = 1, |
| 97 | }; | 70 | }; |
| 98 | 71 | ||
| 72 | // This is nn::hid::NpadJoyDeviceType | ||
| 73 | enum class NpadJoyDeviceType : s64 { | ||
| 74 | Left = 0, | ||
| 75 | Right = 1, | ||
| 76 | }; | ||
| 77 | |||
| 78 | // This is nn::hid::NpadHandheldActivationMode | ||
| 99 | enum class NpadHandheldActivationMode : u64 { | 79 | enum class NpadHandheldActivationMode : u64 { |
| 100 | Dual = 0, | 80 | Dual = 0, |
| 101 | Single = 1, | 81 | Single = 1, |
| 102 | None = 2, | 82 | None = 2, |
| 103 | }; | 83 | }; |
| 104 | 84 | ||
| 85 | // This is nn::hid::NpadCommunicationMode | ||
| 105 | enum class NpadCommunicationMode : u64 { | 86 | enum class NpadCommunicationMode : u64 { |
| 106 | Mode_5ms = 0, | 87 | Mode_5ms = 0, |
| 107 | Mode_10ms = 1, | 88 | Mode_10ms = 1, |
| @@ -109,74 +90,22 @@ public: | |||
| 109 | Default = 3, | 90 | Default = 3, |
| 110 | }; | 91 | }; |
| 111 | 92 | ||
| 112 | struct DeviceHandle { | 93 | static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{ |
| 113 | NpadType npad_type; | 94 | .low_amplitude = 0.0f, |
| 114 | u8 npad_id; | 95 | .low_frequency = 160.0f, |
| 115 | DeviceIndex device_index; | 96 | .high_amplitude = 0.0f, |
| 116 | INSERT_PADDING_BYTES_NOINIT(1); | 97 | .high_frequency = 320.0f, |
| 117 | }; | 98 | }; |
| 118 | static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); | ||
| 119 | 99 | ||
| 120 | struct NpadStyleSet { | 100 | void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); |
| 121 | union { | 101 | Core::HID::NpadStyleTag GetSupportedStyleSet() const; |
| 122 | u32_le raw{}; | ||
| 123 | |||
| 124 | BitField<0, 1, u32> fullkey; | ||
| 125 | BitField<1, 1, u32> handheld; | ||
| 126 | BitField<2, 1, u32> joycon_dual; | ||
| 127 | BitField<3, 1, u32> joycon_left; | ||
| 128 | BitField<4, 1, u32> joycon_right; | ||
| 129 | BitField<5, 1, u32> gamecube; | ||
| 130 | BitField<6, 1, u32> palma; | ||
| 131 | BitField<7, 1, u32> lark; | ||
| 132 | BitField<8, 1, u32> handheld_lark; | ||
| 133 | BitField<9, 1, u32> lucia; | ||
| 134 | BitField<29, 1, u32> system_ext; | ||
| 135 | BitField<30, 1, u32> system; | ||
| 136 | }; | ||
| 137 | }; | ||
| 138 | static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); | ||
| 139 | |||
| 140 | struct VibrationValue { | ||
| 141 | f32 amp_low; | ||
| 142 | f32 freq_low; | ||
| 143 | f32 amp_high; | ||
| 144 | f32 freq_high; | ||
| 145 | }; | ||
| 146 | static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); | ||
| 147 | |||
| 148 | static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ | ||
| 149 | .amp_low = 0.0f, | ||
| 150 | .freq_low = 160.0f, | ||
| 151 | .amp_high = 0.0f, | ||
| 152 | .freq_high = 320.0f, | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct LedPattern { | ||
| 156 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | ||
| 157 | position1.Assign(light1); | ||
| 158 | position2.Assign(light2); | ||
| 159 | position3.Assign(light3); | ||
| 160 | position4.Assign(light4); | ||
| 161 | } | ||
| 162 | union { | ||
| 163 | u64 raw{}; | ||
| 164 | BitField<0, 1, u64> position1; | ||
| 165 | BitField<1, 1, u64> position2; | ||
| 166 | BitField<2, 1, u64> position3; | ||
| 167 | BitField<3, 1, u64> position4; | ||
| 168 | }; | ||
| 169 | }; | ||
| 170 | |||
| 171 | void SetSupportedStyleSet(NpadStyleSet style_set); | ||
| 172 | NpadStyleSet GetSupportedStyleSet() const; | ||
| 173 | 102 | ||
| 174 | void SetSupportedNpadIdTypes(u8* data, std::size_t length); | 103 | void SetSupportedNpadIdTypes(u8* data, std::size_t length); |
| 175 | void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); | 104 | void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); |
| 176 | std::size_t GetSupportedNpadIdTypesSize() const; | 105 | std::size_t GetSupportedNpadIdTypesSize() const; |
| 177 | 106 | ||
| 178 | void SetHoldType(NpadHoldType joy_hold_type); | 107 | void SetHoldType(NpadJoyHoldType joy_hold_type); |
| 179 | NpadHoldType GetHoldType() const; | 108 | NpadJoyHoldType GetHoldType() const; |
| 180 | 109 | ||
| 181 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); | 110 | void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); |
| 182 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; | 111 | NpadHandheldActivationMode GetNpadHandheldActivationMode() const; |
| @@ -184,162 +113,107 @@ public: | |||
| 184 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); | 113 | void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); |
| 185 | NpadCommunicationMode GetNpadCommunicationMode() const; | 114 | NpadCommunicationMode GetNpadCommunicationMode() const; |
| 186 | 115 | ||
| 187 | void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); | 116 | void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type, |
| 117 | NpadJoyAssignmentMode assignment_mode); | ||
| 188 | 118 | ||
| 189 | bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, | 119 | bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, |
| 190 | const VibrationValue& vibration_value); | 120 | const Core::HID::VibrationValue& vibration_value); |
| 191 | 121 | ||
| 192 | void VibrateController(const DeviceHandle& vibration_device_handle, | 122 | void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, |
| 193 | const VibrationValue& vibration_value); | 123 | const Core::HID::VibrationValue& vibration_value); |
| 194 | 124 | ||
| 195 | void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, | 125 | void VibrateControllers( |
| 196 | const std::vector<VibrationValue>& vibration_values); | 126 | const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles, |
| 127 | const std::vector<Core::HID::VibrationValue>& vibration_values); | ||
| 197 | 128 | ||
| 198 | VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; | 129 | Core::HID::VibrationValue GetLastVibration( |
| 130 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | ||
| 199 | 131 | ||
| 200 | void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); | 132 | void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); |
| 201 | 133 | ||
| 202 | void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); | 134 | void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); |
| 203 | 135 | ||
| 204 | void SetPermitVibrationSession(bool permit_vibration_session); | 136 | void SetPermitVibrationSession(bool permit_vibration_session); |
| 205 | 137 | ||
| 206 | bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; | 138 | bool IsVibrationDeviceMounted( |
| 139 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | ||
| 207 | 140 | ||
| 208 | Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); | 141 | Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); |
| 209 | void SignalStyleSetChangedEvent(u32 npad_id) const; | 142 | void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; |
| 210 | 143 | ||
| 211 | // Adds a new controller at an index. | 144 | // Adds a new controller at an index. |
| 212 | void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); | 145 | void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); |
| 213 | // Adds a new controller at an index with connection status. | 146 | // Adds a new controller at an index with connection status. |
| 214 | void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); | 147 | void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, |
| 215 | 148 | bool connected); | |
| 216 | void DisconnectNpad(u32 npad_id); | 149 | |
| 217 | void DisconnectNpadAtIndex(std::size_t index); | 150 | void DisconnectNpad(Core::HID::NpadIdType npad_id); |
| 218 | 151 | ||
| 219 | void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); | 152 | void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 220 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; | 153 | GyroscopeZeroDriftMode drift_mode); |
| 221 | bool IsSixAxisSensorAtRest() const; | 154 | GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode( |
| 222 | void SetSixAxisEnabled(bool six_axis_status); | 155 | Core::HID::SixAxisSensorHandle sixaxis_handle) const; |
| 223 | void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); | 156 | bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const; |
| 224 | std::pair<f32, f32> GetSixAxisFusionParameters(); | 157 | void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status); |
| 225 | void ResetSixAxisFusionParameters(); | 158 | void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 226 | LedPattern GetLedPattern(u32 npad_id); | 159 | bool sixaxis_fusion_status); |
| 227 | bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; | 160 | void SetSixAxisFusionParameters( |
| 228 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); | 161 | Core::HID::SixAxisSensorHandle sixaxis_handle, |
| 162 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); | ||
| 163 | Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters( | ||
| 164 | Core::HID::SixAxisSensorHandle sixaxis_handle); | ||
| 165 | void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle); | ||
| 166 | Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id); | ||
| 167 | bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const; | ||
| 168 | void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, | ||
| 169 | Core::HID::NpadIdType npad_id); | ||
| 229 | void SetAnalogStickUseCenterClamp(bool use_center_clamp); | 170 | void SetAnalogStickUseCenterClamp(bool use_center_clamp); |
| 230 | void ClearAllConnectedControllers(); | 171 | void ClearAllConnectedControllers(); |
| 231 | void DisconnectAllConnectedControllers(); | 172 | void DisconnectAllConnectedControllers(); |
| 232 | void ConnectAllDisconnectedControllers(); | 173 | void ConnectAllDisconnectedControllers(); |
| 233 | void ClearAllControllers(); | 174 | void ClearAllControllers(); |
| 234 | 175 | ||
| 235 | void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); | 176 | void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); |
| 236 | void StartLRAssignmentMode(); | 177 | void StartLRAssignmentMode(); |
| 237 | void StopLRAssignmentMode(); | 178 | void StopLRAssignmentMode(); |
| 238 | bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); | 179 | bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); |
| 239 | 180 | ||
| 240 | // Logical OR for all buttons presses on all controllers | 181 | // Logical OR for all buttons presses on all controllers |
| 241 | // Specifically for cheat engine and other features. | 182 | // Specifically for cheat engine and other features. |
| 242 | u32 GetAndResetPressState(); | 183 | Core::HID::NpadButton GetAndResetPressState(); |
| 243 | 184 | ||
| 244 | static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type); | 185 | static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); |
| 245 | static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); | 186 | static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); |
| 246 | static std::size_t NPadIdToIndex(u32 npad_id); | 187 | static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); |
| 247 | static u32 IndexToNPad(std::size_t index); | ||
| 248 | static bool IsNpadIdValid(u32 npad_id); | ||
| 249 | static bool IsDeviceHandleValid(const DeviceHandle& device_handle); | ||
| 250 | 188 | ||
| 251 | private: | 189 | private: |
| 252 | struct CommonHeader { | 190 | // This is nn::hid::detail::ColorAttribute |
| 253 | s64_le timestamp; | 191 | enum class ColorAttribute : u32 { |
| 254 | s64_le total_entry_count; | ||
| 255 | s64_le last_entry_index; | ||
| 256 | s64_le entry_count; | ||
| 257 | }; | ||
| 258 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||
| 259 | |||
| 260 | enum class ColorAttributes : u32_le { | ||
| 261 | Ok = 0, | 192 | Ok = 0, |
| 262 | ReadError = 1, | 193 | ReadError = 1, |
| 263 | NoController = 2, | 194 | NoController = 2, |
| 264 | }; | 195 | }; |
| 265 | static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); | 196 | static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); |
| 266 | 197 | ||
| 267 | struct ControllerColor { | 198 | // This is nn::hid::detail::NpadFullKeyColorState |
| 268 | u32_le body; | 199 | struct NpadFullKeyColorState { |
| 269 | u32_le button; | 200 | ColorAttribute attribute; |
| 201 | Core::HID::NpadControllerColor fullkey; | ||
| 270 | }; | 202 | }; |
| 271 | static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); | 203 | static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); |
| 272 | 204 | ||
| 273 | struct FullKeyColor { | 205 | // This is nn::hid::detail::NpadJoyColorState |
| 274 | ColorAttributes attribute; | 206 | struct NpadJoyColorState { |
| 275 | ControllerColor fullkey; | 207 | ColorAttribute attribute; |
| 208 | Core::HID::NpadControllerColor left; | ||
| 209 | Core::HID::NpadControllerColor right; | ||
| 276 | }; | 210 | }; |
| 277 | static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); | 211 | static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); |
| 278 | 212 | ||
| 279 | struct JoyconColor { | 213 | // This is nn::hid::NpadAttribute |
| 280 | ColorAttributes attribute; | 214 | struct NpadAttribute { |
| 281 | ControllerColor left; | ||
| 282 | ControllerColor right; | ||
| 283 | }; | ||
| 284 | static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size"); | ||
| 285 | |||
| 286 | struct ControllerPadState { | ||
| 287 | union { | ||
| 288 | u64_le raw{}; | ||
| 289 | // Button states | ||
| 290 | BitField<0, 1, u64> a; | ||
| 291 | BitField<1, 1, u64> b; | ||
| 292 | BitField<2, 1, u64> x; | ||
| 293 | BitField<3, 1, u64> y; | ||
| 294 | BitField<4, 1, u64> l_stick; | ||
| 295 | BitField<5, 1, u64> r_stick; | ||
| 296 | BitField<6, 1, u64> l; | ||
| 297 | BitField<7, 1, u64> r; | ||
| 298 | BitField<8, 1, u64> zl; | ||
| 299 | BitField<9, 1, u64> zr; | ||
| 300 | BitField<10, 1, u64> plus; | ||
| 301 | BitField<11, 1, u64> minus; | ||
| 302 | |||
| 303 | // D-Pad | ||
| 304 | BitField<12, 1, u64> d_left; | ||
| 305 | BitField<13, 1, u64> d_up; | ||
| 306 | BitField<14, 1, u64> d_right; | ||
| 307 | BitField<15, 1, u64> d_down; | ||
| 308 | |||
| 309 | // Left JoyStick | ||
| 310 | BitField<16, 1, u64> l_stick_left; | ||
| 311 | BitField<17, 1, u64> l_stick_up; | ||
| 312 | BitField<18, 1, u64> l_stick_right; | ||
| 313 | BitField<19, 1, u64> l_stick_down; | ||
| 314 | |||
| 315 | // Right JoyStick | ||
| 316 | BitField<20, 1, u64> r_stick_left; | ||
| 317 | BitField<21, 1, u64> r_stick_up; | ||
| 318 | BitField<22, 1, u64> r_stick_right; | ||
| 319 | BitField<23, 1, u64> r_stick_down; | ||
| 320 | |||
| 321 | // Not always active? | ||
| 322 | BitField<24, 1, u64> left_sl; | ||
| 323 | BitField<25, 1, u64> left_sr; | ||
| 324 | |||
| 325 | BitField<26, 1, u64> right_sl; | ||
| 326 | BitField<27, 1, u64> right_sr; | ||
| 327 | |||
| 328 | BitField<28, 1, u64> palma; | ||
| 329 | BitField<30, 1, u64> handheld_left_b; | ||
| 330 | }; | ||
| 331 | }; | ||
| 332 | static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); | ||
| 333 | |||
| 334 | struct AnalogPosition { | ||
| 335 | s32_le x; | ||
| 336 | s32_le y; | ||
| 337 | }; | ||
| 338 | static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); | ||
| 339 | |||
| 340 | struct ConnectionState { | ||
| 341 | union { | 215 | union { |
| 342 | u32_le raw{}; | 216 | u32 raw{}; |
| 343 | BitField<0, 1, u32> is_connected; | 217 | BitField<0, 1, u32> is_connected; |
| 344 | BitField<1, 1, u32> is_wired; | 218 | BitField<1, 1, u32> is_wired; |
| 345 | BitField<2, 1, u32> is_left_connected; | 219 | BitField<2, 1, u32> is_left_connected; |
| @@ -348,79 +222,60 @@ private: | |||
| 348 | BitField<5, 1, u32> is_right_wired; | 222 | BitField<5, 1, u32> is_right_wired; |
| 349 | }; | 223 | }; |
| 350 | }; | 224 | }; |
| 351 | static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); | 225 | static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); |
| 352 | 226 | ||
| 353 | struct ControllerPad { | 227 | // This is nn::hid::NpadFullKeyState |
| 354 | ControllerPadState pad_states; | 228 | // This is nn::hid::NpadHandheldState |
| 355 | AnalogPosition l_stick; | 229 | // This is nn::hid::NpadJoyDualState |
| 356 | AnalogPosition r_stick; | 230 | // This is nn::hid::NpadJoyLeftState |
| 357 | }; | 231 | // This is nn::hid::NpadJoyRightState |
| 358 | static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size"); | 232 | // This is nn::hid::NpadPalmaState |
| 359 | 233 | // This is nn::hid::NpadSystemExtState | |
| 360 | struct GenericStates { | 234 | struct NPadGenericState { |
| 361 | s64_le timestamp; | 235 | s64_le sampling_number; |
| 362 | s64_le timestamp2; | 236 | Core::HID::NpadButtonState npad_buttons; |
| 363 | ControllerPad pad; | 237 | Core::HID::AnalogStickState l_stick; |
| 364 | ConnectionState connection_status; | 238 | Core::HID::AnalogStickState r_stick; |
| 365 | }; | 239 | NpadAttribute connection_status; |
| 366 | static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); | 240 | INSERT_PADDING_BYTES(4); // Reserved |
| 367 | |||
| 368 | struct NPadGeneric { | ||
| 369 | CommonHeader common; | ||
| 370 | std::array<GenericStates, 17> npad; | ||
| 371 | }; | 241 | }; |
| 372 | static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); | 242 | static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); |
| 373 | 243 | ||
| 374 | struct SixAxisAttributes { | 244 | // This is nn::hid::SixAxisSensorAttribute |
| 245 | struct SixAxisSensorAttribute { | ||
| 375 | union { | 246 | union { |
| 376 | u32_le raw{}; | 247 | u32 raw{}; |
| 377 | BitField<0, 1, u32> is_connected; | 248 | BitField<0, 1, u32> is_connected; |
| 378 | BitField<1, 1, u32> is_interpolated; | 249 | BitField<1, 1, u32> is_interpolated; |
| 379 | }; | 250 | }; |
| 380 | }; | 251 | }; |
| 381 | static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size"); | 252 | static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size"); |
| 382 | 253 | ||
| 383 | struct SixAxisStates { | 254 | // This is nn::hid::SixAxisSensorState |
| 384 | s64_le timestamp{}; | 255 | struct SixAxisSensorState { |
| 385 | INSERT_PADDING_WORDS(2); | 256 | s64 delta_time{}; |
| 386 | s64_le timestamp2{}; | 257 | s64 sampling_number{}; |
| 387 | Common::Vec3f accel{}; | 258 | Common::Vec3f accel{}; |
| 388 | Common::Vec3f gyro{}; | 259 | Common::Vec3f gyro{}; |
| 389 | Common::Vec3f rotation{}; | 260 | Common::Vec3f rotation{}; |
| 390 | std::array<Common::Vec3f, 3> orientation{}; | 261 | std::array<Common::Vec3f, 3> orientation{}; |
| 391 | SixAxisAttributes attribute; | 262 | SixAxisSensorAttribute attribute; |
| 392 | INSERT_PADDING_BYTES(4); // Reserved | 263 | INSERT_PADDING_BYTES(4); // Reserved |
| 393 | }; | 264 | }; |
| 394 | static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); | 265 | static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); |
| 395 | |||
| 396 | struct SixAxisGeneric { | ||
| 397 | CommonHeader common{}; | ||
| 398 | std::array<SixAxisStates, 17> sixaxis{}; | ||
| 399 | }; | ||
| 400 | static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); | ||
| 401 | 266 | ||
| 402 | struct TriggerState { | 267 | // This is nn::hid::server::NpadGcTriggerState |
| 403 | s64_le timestamp{}; | 268 | struct NpadGcTriggerState { |
| 404 | s64_le timestamp2{}; | 269 | s64 sampling_number{}; |
| 405 | s32_le l_analog{}; | 270 | s32 l_analog{}; |
| 406 | s32_le r_analog{}; | 271 | s32 r_analog{}; |
| 407 | }; | 272 | }; |
| 408 | static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size"); | 273 | static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); |
| 409 | |||
| 410 | struct TriggerGeneric { | ||
| 411 | INSERT_PADDING_BYTES(0x4); | ||
| 412 | s64_le timestamp; | ||
| 413 | INSERT_PADDING_BYTES(0x4); | ||
| 414 | s64_le total_entry_count; | ||
| 415 | s64_le last_entry_index; | ||
| 416 | s64_le entry_count; | ||
| 417 | std::array<TriggerState, 17> trigger{}; | ||
| 418 | }; | ||
| 419 | static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size"); | ||
| 420 | 274 | ||
| 275 | // This is nn::hid::NpadSystemProperties | ||
| 421 | struct NPadSystemProperties { | 276 | struct NPadSystemProperties { |
| 422 | union { | 277 | union { |
| 423 | s64_le raw{}; | 278 | s64 raw{}; |
| 424 | BitField<0, 1, s64> is_charging_joy_dual; | 279 | BitField<0, 1, s64> is_charging_joy_dual; |
| 425 | BitField<1, 1, s64> is_charging_joy_left; | 280 | BitField<1, 1, s64> is_charging_joy_left; |
| 426 | BitField<2, 1, s64> is_charging_joy_right; | 281 | BitField<2, 1, s64> is_charging_joy_right; |
| @@ -438,17 +293,20 @@ private: | |||
| 438 | }; | 293 | }; |
| 439 | static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); | 294 | static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); |
| 440 | 295 | ||
| 441 | struct NPadButtonProperties { | 296 | // This is nn::hid::NpadSystemButtonProperties |
| 297 | struct NpadSystemButtonProperties { | ||
| 442 | union { | 298 | union { |
| 443 | s32_le raw{}; | 299 | s32 raw{}; |
| 444 | BitField<0, 1, s32> is_home_button_protection_enabled; | 300 | BitField<0, 1, s32> is_home_button_protection_enabled; |
| 445 | }; | 301 | }; |
| 446 | }; | 302 | }; |
| 447 | static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); | 303 | static_assert(sizeof(NpadSystemButtonProperties) == 0x4, |
| 304 | "NPadButtonProperties is an invalid size"); | ||
| 448 | 305 | ||
| 449 | struct NPadDevice { | 306 | // This is nn::hid::system::DeviceType |
| 307 | struct DeviceType { | ||
| 450 | union { | 308 | union { |
| 451 | u32_le raw{}; | 309 | u32 raw{}; |
| 452 | BitField<0, 1, s32> fullkey; | 310 | BitField<0, 1, s32> fullkey; |
| 453 | BitField<1, 1, s32> debug_pad; | 311 | BitField<1, 1, s32> debug_pad; |
| 454 | BitField<2, 1, s32> handheld_left; | 312 | BitField<2, 1, s32> handheld_left; |
| @@ -465,26 +323,29 @@ private: | |||
| 465 | BitField<13, 1, s32> handheld_lark_nes_left; | 323 | BitField<13, 1, s32> handheld_lark_nes_left; |
| 466 | BitField<14, 1, s32> handheld_lark_nes_right; | 324 | BitField<14, 1, s32> handheld_lark_nes_right; |
| 467 | BitField<15, 1, s32> lucia; | 325 | BitField<15, 1, s32> lucia; |
| 326 | BitField<16, 1, s32> lagon; | ||
| 327 | BitField<17, 1, s32> lager; | ||
| 468 | BitField<31, 1, s32> system; | 328 | BitField<31, 1, s32> system; |
| 469 | }; | 329 | }; |
| 470 | }; | 330 | }; |
| 471 | 331 | ||
| 472 | struct MotionDevice { | 332 | // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl |
| 473 | Common::Vec3f accel; | 333 | struct NfcXcdDeviceHandleStateImpl { |
| 474 | Common::Vec3f gyro; | 334 | u64 handle; |
| 475 | Common::Vec3f rotation; | 335 | bool is_available; |
| 476 | std::array<Common::Vec3f, 3> orientation; | 336 | bool is_activated; |
| 477 | Common::Quaternion<f32> quaternion; | 337 | INSERT_PADDING_BYTES(0x6); // Reserved |
| 478 | }; | 338 | u64 sampling_number; |
| 479 | |||
| 480 | struct NfcXcdHandle { | ||
| 481 | INSERT_PADDING_BYTES(0x60); | ||
| 482 | }; | 339 | }; |
| 340 | static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, | ||
| 341 | "NfcXcdDeviceHandleStateImpl is an invalid size"); | ||
| 483 | 342 | ||
| 343 | // This is nn::hid::system::AppletFooterUiAttributesSet | ||
| 484 | struct AppletFooterUiAttributes { | 344 | struct AppletFooterUiAttributes { |
| 485 | INSERT_PADDING_BYTES(0x4); | 345 | INSERT_PADDING_BYTES(0x4); |
| 486 | }; | 346 | }; |
| 487 | 347 | ||
| 348 | // This is nn::hid::system::AppletFooterUiType | ||
| 488 | enum class AppletFooterUiType : u8 { | 349 | enum class AppletFooterUiType : u8 { |
| 489 | None = 0, | 350 | None = 0, |
| 490 | HandheldNone = 1, | 351 | HandheldNone = 1, |
| @@ -510,95 +371,153 @@ private: | |||
| 510 | Lagon = 21, | 371 | Lagon = 21, |
| 511 | }; | 372 | }; |
| 512 | 373 | ||
| 513 | struct NPadEntry { | 374 | struct AppletFooterUi { |
| 514 | NpadStyleSet style_set; | 375 | AppletFooterUiAttributes attributes; |
| 515 | NpadAssignments assignment_mode; | 376 | AppletFooterUiType type; |
| 516 | FullKeyColor fullkey_color; | 377 | INSERT_PADDING_BYTES(0x5B); // Reserved |
| 517 | JoyconColor joycon_color; | 378 | }; |
| 518 | 379 | static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); | |
| 519 | NPadGeneric fullkey_states; | 380 | |
| 520 | NPadGeneric handheld_states; | 381 | // This is nn::hid::NpadLarkType |
| 521 | NPadGeneric joy_dual_states; | 382 | enum class NpadLarkType : u32 { |
| 522 | NPadGeneric joy_left_states; | 383 | Invalid, |
| 523 | NPadGeneric joy_right_states; | 384 | H1, |
| 524 | NPadGeneric palma_states; | 385 | H2, |
| 525 | NPadGeneric system_ext_states; | 386 | NL, |
| 526 | SixAxisGeneric sixaxis_fullkey; | 387 | NR, |
| 527 | SixAxisGeneric sixaxis_handheld; | 388 | }; |
| 528 | SixAxisGeneric sixaxis_dual_left; | 389 | |
| 529 | SixAxisGeneric sixaxis_dual_right; | 390 | // This is nn::hid::NpadLuciaType |
| 530 | SixAxisGeneric sixaxis_left; | 391 | enum class NpadLuciaType : u32 { |
| 531 | SixAxisGeneric sixaxis_right; | 392 | Invalid, |
| 532 | NPadDevice device_type; | 393 | J, |
| 533 | INSERT_PADDING_BYTES(0x4); // reserved | 394 | E, |
| 395 | U, | ||
| 396 | }; | ||
| 397 | |||
| 398 | // This is nn::hid::NpadLagonType | ||
| 399 | enum class NpadLagonType : u32 { | ||
| 400 | Invalid, | ||
| 401 | }; | ||
| 402 | |||
| 403 | // This is nn::hid::NpadLagerType | ||
| 404 | enum class NpadLagerType : u32 { | ||
| 405 | Invalid, | ||
| 406 | J, | ||
| 407 | E, | ||
| 408 | U, | ||
| 409 | }; | ||
| 410 | |||
| 411 | // This is nn::hid::detail::NpadInternalState | ||
| 412 | struct NpadInternalState { | ||
| 413 | Core::HID::NpadStyleTag style_tag; | ||
| 414 | NpadJoyAssignmentMode assignment_mode; | ||
| 415 | NpadFullKeyColorState fullkey_color; | ||
| 416 | NpadJoyColorState joycon_color; | ||
| 417 | Lifo<NPadGenericState, hid_entry_count> fullkey_lifo; | ||
| 418 | Lifo<NPadGenericState, hid_entry_count> handheld_lifo; | ||
| 419 | Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo; | ||
| 420 | Lifo<NPadGenericState, hid_entry_count> joy_left_lifo; | ||
| 421 | Lifo<NPadGenericState, hid_entry_count> joy_right_lifo; | ||
| 422 | Lifo<NPadGenericState, hid_entry_count> palma_lifo; | ||
| 423 | Lifo<NPadGenericState, hid_entry_count> system_ext_lifo; | ||
| 424 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo; | ||
| 425 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo; | ||
| 426 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo; | ||
| 427 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo; | ||
| 428 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo; | ||
| 429 | Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo; | ||
| 430 | DeviceType device_type; | ||
| 431 | INSERT_PADDING_BYTES(0x4); // Reserved | ||
| 534 | NPadSystemProperties system_properties; | 432 | NPadSystemProperties system_properties; |
| 535 | NPadButtonProperties button_properties; | 433 | NpadSystemButtonProperties button_properties; |
| 536 | u32 battery_level_dual; | 434 | Core::HID::NpadBatteryLevel battery_level_dual; |
| 537 | u32 battery_level_left; | 435 | Core::HID::NpadBatteryLevel battery_level_left; |
| 538 | u32 battery_level_right; | 436 | Core::HID::NpadBatteryLevel battery_level_right; |
| 539 | AppletFooterUiAttributes footer_attributes; | 437 | union { |
| 540 | AppletFooterUiType footer_type; | 438 | Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo{}; |
| 541 | // nfc_states needs to be checked switchbrew does not match with HW | 439 | AppletFooterUi applet_footer; |
| 542 | NfcXcdHandle nfc_states; | 440 | }; |
| 543 | INSERT_PADDING_BYTES(0x8); // Mutex | 441 | INSERT_PADDING_BYTES(0x20); // Unknown |
| 544 | TriggerGeneric gc_trigger_states; | 442 | Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo; |
| 545 | INSERT_PADDING_BYTES(0xc1f); | 443 | NpadLarkType lark_type_l_and_main; |
| 546 | }; | 444 | NpadLarkType lark_type_r; |
| 547 | static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); | 445 | NpadLuciaType lucia_type; |
| 548 | 446 | NpadLagonType lagon_type; | |
| 549 | struct ControllerHolder { | 447 | NpadLagerType lager_type; |
| 550 | NPadControllerType type; | 448 | // FW 13.x Investigate there is some sort of bitflag related to joycons |
| 551 | bool is_connected; | 449 | INSERT_PADDING_BYTES(0x4); |
| 552 | }; | 450 | INSERT_PADDING_BYTES(0xc08); // Unknown |
| 553 | 451 | }; | |
| 554 | void InitNewlyAddedController(std::size_t controller_idx); | 452 | static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); |
| 555 | bool IsControllerSupported(NPadControllerType controller) const; | 453 | |
| 556 | void RequestPadStateUpdate(u32 npad_id); | 454 | struct VibrationData { |
| 557 | 455 | bool device_mounted{}; | |
| 558 | std::atomic<u32> press_state{}; | 456 | Core::HID::VibrationValue latest_vibration_value{}; |
| 559 | 457 | std::chrono::steady_clock::time_point last_vibration_timepoint{}; | |
| 560 | NpadStyleSet style{}; | 458 | }; |
| 561 | std::array<NPadEntry, 10> shared_memory_entries{}; | 459 | |
| 562 | using ButtonArray = std::array< | 460 | struct NpadControllerData { |
| 563 | std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, | 461 | Core::HID::EmulatedController* device; |
| 564 | 10>; | 462 | Kernel::KEvent* styleset_changed_event{}; |
| 565 | using StickArray = std::array< | 463 | NpadInternalState shared_memory_entry{}; |
| 566 | std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, | 464 | |
| 567 | 10>; | 465 | std::array<VibrationData, 2> vibration{}; |
| 568 | using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>, | 466 | bool unintended_home_button_input_protection{}; |
| 569 | Settings::NativeVibration::NUM_VIBRATIONS_HID>, | 467 | bool is_connected{}; |
| 570 | 10>; | 468 | |
| 571 | using MotionArray = std::array< | 469 | // Dual joycons can have only one side connected |
| 572 | std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>, | 470 | bool is_dual_left_connected{true}; |
| 573 | 10>; | 471 | bool is_dual_right_connected{true}; |
| 574 | 472 | ||
| 473 | // Motion parameters | ||
| 474 | bool sixaxis_at_rest{true}; | ||
| 475 | bool sixaxis_sensor_enabled{true}; | ||
| 476 | bool sixaxis_fusion_enabled{false}; | ||
| 477 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{}; | ||
| 478 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | ||
| 479 | |||
| 480 | // Current pad state | ||
| 481 | NPadGenericState npad_pad_state{}; | ||
| 482 | NPadGenericState npad_libnx_state{}; | ||
| 483 | NpadGcTriggerState npad_trigger_state{}; | ||
| 484 | SixAxisSensorState sixaxis_fullkey_state{}; | ||
| 485 | SixAxisSensorState sixaxis_handheld_state{}; | ||
| 486 | SixAxisSensorState sixaxis_dual_left_state{}; | ||
| 487 | SixAxisSensorState sixaxis_dual_right_state{}; | ||
| 488 | SixAxisSensorState sixaxis_left_lifo_state{}; | ||
| 489 | SixAxisSensorState sixaxis_right_lifo_state{}; | ||
| 490 | int callback_key; | ||
| 491 | }; | ||
| 492 | |||
| 493 | void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); | ||
| 494 | void InitNewlyAddedController(Core::HID::NpadIdType npad_id); | ||
| 495 | bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; | ||
| 496 | void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); | ||
| 497 | void WriteEmptyEntry(NpadInternalState& npad); | ||
| 498 | |||
| 499 | NpadControllerData& GetControllerFromHandle( | ||
| 500 | const Core::HID::SixAxisSensorHandle& device_handle); | ||
| 501 | const NpadControllerData& GetControllerFromHandle( | ||
| 502 | const Core::HID::SixAxisSensorHandle& device_handle) const; | ||
| 503 | NpadControllerData& GetControllerFromHandle( | ||
| 504 | const Core::HID::VibrationDeviceHandle& device_handle); | ||
| 505 | const NpadControllerData& GetControllerFromHandle( | ||
| 506 | const Core::HID::VibrationDeviceHandle& device_handle) const; | ||
| 507 | NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); | ||
| 508 | const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; | ||
| 509 | |||
| 510 | std::atomic<u64> press_state{}; | ||
| 511 | |||
| 512 | std::array<NpadControllerData, 10> controller_data{}; | ||
| 575 | KernelHelpers::ServiceContext& service_context; | 513 | KernelHelpers::ServiceContext& service_context; |
| 576 | std::mutex mutex; | 514 | std::mutex mutex; |
| 577 | ButtonArray buttons; | 515 | std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; |
| 578 | StickArray sticks; | 516 | NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; |
| 579 | VibrationArray vibrations; | ||
| 580 | MotionArray motions; | ||
| 581 | std::vector<u32> supported_npad_id_types{}; | ||
| 582 | NpadHoldType hold_type{NpadHoldType::Vertical}; | ||
| 583 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; | 517 | NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; |
| 584 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; | 518 | NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; |
| 585 | // Each controller should have their own styleset changed event | ||
| 586 | std::array<Kernel::KEvent*, 10> styleset_changed_events{}; | ||
| 587 | std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> | ||
| 588 | last_vibration_timepoints{}; | ||
| 589 | std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{}; | ||
| 590 | bool permit_vibration_session_enabled{false}; | 519 | bool permit_vibration_session_enabled{false}; |
| 591 | std::array<std::array<bool, 2>, 10> vibration_devices_mounted{}; | ||
| 592 | std::array<ControllerHolder, 10> connected_controllers{}; | ||
| 593 | std::array<bool, 10> unintended_home_button_input_protection{}; | ||
| 594 | bool analog_stick_use_center_clamp{}; | 520 | bool analog_stick_use_center_clamp{}; |
| 595 | GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; | ||
| 596 | bool sixaxis_sensors_enabled{true}; | ||
| 597 | f32 sixaxis_fusion_parameter1{}; | ||
| 598 | f32 sixaxis_fusion_parameter2{}; | ||
| 599 | bool sixaxis_at_rest{true}; | ||
| 600 | std::array<ControllerPad, 10> npad_pad_states{}; | ||
| 601 | std::array<TriggerState, 10> npad_trigger_states{}; | ||
| 602 | bool is_in_lr_assignment_mode{false}; | 521 | bool is_in_lr_assignment_mode{false}; |
| 603 | }; | 522 | }; |
| 604 | } // namespace Service::HID | 523 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 772c20453..b7d7a5756 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp | |||
| @@ -5,11 +5,12 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hid/hid_core.h" | ||
| 8 | #include "core/hle/service/hid/controllers/stubbed.h" | 9 | #include "core/hle/service/hid/controllers/stubbed.h" |
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
| 11 | 12 | ||
| 12 | Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {} | 13 | Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} |
| 13 | Controller_Stubbed::~Controller_Stubbed() = default; | 14 | Controller_Stubbed::~Controller_Stubbed() = default; |
| 14 | 15 | ||
| 15 | void Controller_Stubbed::OnInit() {} | 16 | void Controller_Stubbed::OnInit() {} |
| @@ -31,10 +32,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 31 | std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); | 32 | std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | void Controller_Stubbed::OnLoadInputDevices() {} | ||
| 35 | |||
| 36 | void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { | 35 | void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { |
| 37 | common_offset = off; | 36 | common_offset = off; |
| 38 | smart_update = true; | 37 | smart_update = true; |
| 39 | } | 38 | } |
| 39 | |||
| 40 | } // namespace Service::HID | 40 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 21092af0d..0044a4efa 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | namespace Service::HID { | 10 | namespace Service::HID { |
| 11 | class Controller_Stubbed final : public ControllerBase { | 11 | class Controller_Stubbed final : public ControllerBase { |
| 12 | public: | 12 | public: |
| 13 | explicit Controller_Stubbed(Core::System& system_); | 13 | explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); |
| 14 | ~Controller_Stubbed() override; | 14 | ~Controller_Stubbed() override; |
| 15 | 15 | ||
| 16 | // Called when the controller is initialized | 16 | // Called when the controller is initialized |
| @@ -22,12 +22,17 @@ public: | |||
| 22 | // When the controller is requesting an update for the shared memory | 22 | // When the controller is requesting an update for the shared memory |
| 23 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 23 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 24 | 24 | ||
| 25 | // Called when input devices should be loaded | ||
| 26 | void OnLoadInputDevices() override; | ||
| 27 | |||
| 28 | void SetCommonHeaderOffset(std::size_t off); | 25 | void SetCommonHeaderOffset(std::size_t off); |
| 29 | 26 | ||
| 30 | private: | 27 | private: |
| 28 | struct CommonHeader { | ||
| 29 | s64 timestamp; | ||
| 30 | s64 total_entry_count; | ||
| 31 | s64 last_entry_index; | ||
| 32 | s64 entry_count; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); | ||
| 35 | |||
| 31 | bool smart_update{}; | 36 | bool smart_update{}; |
| 32 | std::size_t common_offset{}; | 37 | std::size_t common_offset{}; |
| 33 | }; | 38 | }; |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 6ef17acc5..48978e5c6 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -7,72 +7,82 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 10 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 11 | #include "core/frontend/emu_window.h" | 12 | #include "core/frontend/emu_window.h" |
| 12 | #include "core/frontend/input.h" | 13 | #include "core/hid/emulated_console.h" |
| 14 | #include "core/hid/hid_core.h" | ||
| 13 | #include "core/hle/service/hid/controllers/touchscreen.h" | 15 | #include "core/hle/service/hid/controllers/touchscreen.h" |
| 14 | 16 | ||
| 15 | namespace Service::HID { | 17 | namespace Service::HID { |
| 16 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | 18 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; |
| 17 | 19 | ||
| 18 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} | 20 | Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) |
| 21 | : ControllerBase{hid_core_} { | ||
| 22 | console = hid_core.GetEmulatedConsole(); | ||
| 23 | } | ||
| 24 | |||
| 19 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 25 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 20 | 26 | ||
| 21 | void Controller_Touchscreen::OnInit() { | 27 | void Controller_Touchscreen::OnInit() {} |
| 22 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 23 | mouse_finger_id[id] = MAX_FINGERS; | ||
| 24 | keyboard_finger_id[id] = MAX_FINGERS; | ||
| 25 | udp_finger_id[id] = MAX_FINGERS; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | 28 | ||
| 29 | void Controller_Touchscreen::OnRelease() {} | 29 | void Controller_Touchscreen::OnRelease() {} |
| 30 | 30 | ||
| 31 | void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 31 | void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 32 | std::size_t size) { | 32 | std::size_t size) { |
| 33 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | 33 | touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); |
| 34 | shared_memory.header.total_entry_count = 17; | ||
| 35 | 34 | ||
| 36 | if (!IsControllerActivated()) { | 35 | if (!IsControllerActivated()) { |
| 37 | shared_memory.header.entry_count = 0; | 36 | touch_screen_lifo.buffer_count = 0; |
| 38 | shared_memory.header.last_entry_index = 0; | 37 | touch_screen_lifo.buffer_tail = 0; |
| 38 | std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||
| 39 | return; | 39 | return; |
| 40 | } | 40 | } |
| 41 | shared_memory.header.entry_count = 16; | ||
| 42 | 41 | ||
| 43 | const auto& last_entry = | 42 | const auto touch_status = console->GetTouch(); |
| 44 | shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | 43 | for (std::size_t id = 0; id < MAX_FINGERS; id++) { |
| 45 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | 44 | const auto& current_touch = touch_status[id]; |
| 46 | auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | 45 | auto& finger = fingers[id]; |
| 46 | finger.position = current_touch.position; | ||
| 47 | finger.id = current_touch.id; | ||
| 47 | 48 | ||
| 48 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 49 | if (finger.attribute.start_touch) { |
| 49 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 50 | finger.attribute.raw = 0; |
| 51 | continue; | ||
| 52 | } | ||
| 50 | 53 | ||
| 51 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 54 | if (finger.attribute.end_touch) { |
| 52 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 55 | finger.attribute.raw = 0; |
| 53 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 56 | finger.pressed = false; |
| 54 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); | 57 | continue; |
| 55 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); | 58 | } |
| 56 | } | 59 | |
| 60 | if (!finger.pressed && current_touch.pressed) { | ||
| 61 | finger.attribute.start_touch.Assign(1); | ||
| 62 | finger.pressed = true; | ||
| 63 | continue; | ||
| 64 | } | ||
| 57 | 65 | ||
| 58 | if (Settings::values.use_touch_from_button) { | 66 | if (finger.pressed && !current_touch.pressed) { |
| 59 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); | 67 | finger.attribute.raw = 0; |
| 60 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 68 | finger.attribute.end_touch.Assign(1); |
| 61 | keyboard_finger_id[id] = | ||
| 62 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | ||
| 63 | } | 69 | } |
| 64 | } | 70 | } |
| 65 | 71 | ||
| 66 | std::array<Finger, 16> active_fingers; | 72 | std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; |
| 67 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | 73 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), |
| 68 | [](const auto& finger) { return finger.pressed; }); | 74 | [](const auto& finger) { return finger.pressed; }); |
| 69 | const auto active_fingers_count = | 75 | const auto active_fingers_count = |
| 70 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | 76 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); |
| 71 | 77 | ||
| 72 | const u64 tick = core_timing.GetCPUTicks(); | 78 | const u64 tick = core_timing.GetCPUTicks(); |
| 73 | cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); | 79 | const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; |
| 80 | |||
| 81 | next_state.sampling_number = last_entry.sampling_number + 1; | ||
| 82 | next_state.entry_count = static_cast<s32>(active_fingers_count); | ||
| 83 | |||
| 74 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | 84 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { |
| 75 | auto& touch_entry = cur_entry.states[id]; | 85 | auto& touch_entry = next_state.states[id]; |
| 76 | if (id < active_fingers_count) { | 86 | if (id < active_fingers_count) { |
| 77 | const auto& [active_x, active_y] = active_fingers[id].position; | 87 | const auto& [active_x, active_y] = active_fingers[id].position; |
| 78 | touch_entry.position = { | 88 | touch_entry.position = { |
| @@ -97,66 +107,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 97 | touch_entry.finger = 0; | 107 | touch_entry.finger = 0; |
| 98 | } | 108 | } |
| 99 | } | 109 | } |
| 100 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); | ||
| 101 | } | ||
| 102 | |||
| 103 | void Controller_Touchscreen::OnLoadInputDevices() { | ||
| 104 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | ||
| 105 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | ||
| 106 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | ||
| 107 | } | ||
| 108 | |||
| 109 | std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { | ||
| 110 | // Dont assign any touch input to a finger if disabled | ||
| 111 | if (!Settings::values.touchscreen.enabled) { | ||
| 112 | return std::nullopt; | ||
| 113 | } | ||
| 114 | std::size_t first_free_id = 0; | ||
| 115 | while (first_free_id < MAX_FINGERS) { | ||
| 116 | if (!fingers[first_free_id].pressed) { | ||
| 117 | return first_free_id; | ||
| 118 | } else { | ||
| 119 | first_free_id++; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | return std::nullopt; | ||
| 123 | } | ||
| 124 | |||
| 125 | std::size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||
| 126 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 127 | const auto& [x, y, pressed] = touch_input; | ||
| 128 | if (finger_id > MAX_FINGERS) { | ||
| 129 | LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||
| 130 | return MAX_FINGERS; | ||
| 131 | } | ||
| 132 | if (pressed) { | ||
| 133 | Attributes attribute{}; | ||
| 134 | if (finger_id == MAX_FINGERS) { | ||
| 135 | const auto first_free_id = GetUnusedFingerID(); | ||
| 136 | if (!first_free_id) { | ||
| 137 | // Invalid finger id do nothing | ||
| 138 | return MAX_FINGERS; | ||
| 139 | } | ||
| 140 | finger_id = first_free_id.value(); | ||
| 141 | fingers[finger_id].pressed = true; | ||
| 142 | fingers[finger_id].id = static_cast<u32_le>(finger_id); | ||
| 143 | attribute.start_touch.Assign(1); | ||
| 144 | } | ||
| 145 | fingers[finger_id].position = {x, y}; | ||
| 146 | fingers[finger_id].attribute = attribute; | ||
| 147 | return finger_id; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (finger_id != MAX_FINGERS) { | ||
| 151 | if (!fingers[finger_id].attribute.end_touch) { | ||
| 152 | fingers[finger_id].attribute.end_touch.Assign(1); | ||
| 153 | fingers[finger_id].attribute.start_touch.Assign(0); | ||
| 154 | return finger_id; | ||
| 155 | } | ||
| 156 | fingers[finger_id].pressed = false; | ||
| 157 | } | ||
| 158 | 110 | ||
| 159 | return MAX_FINGERS; | 111 | touch_screen_lifo.WriteNextEntry(next_state); |
| 112 | std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||
| 160 | } | 113 | } |
| 161 | 114 | ||
| 162 | } // namespace Service::HID | 115 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 8e9b40c0a..708dde4f0 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -9,18 +9,25 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/point.h" | 10 | #include "common/point.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/frontend/input.h" | 12 | #include "core/hid/hid_types.h" |
| 13 | #include "core/hle/service/hid/controllers/controller_base.h" | 13 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 14 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 15 | |||
| 16 | namespace Core::HID { | ||
| 17 | class EmulatedConsole; | ||
| 18 | } // namespace Core::HID | ||
| 14 | 19 | ||
| 15 | namespace Service::HID { | 20 | namespace Service::HID { |
| 16 | class Controller_Touchscreen final : public ControllerBase { | 21 | class Controller_Touchscreen final : public ControllerBase { |
| 17 | public: | 22 | public: |
| 23 | // This is nn::hid::TouchScreenModeForNx | ||
| 18 | enum class TouchScreenModeForNx : u8 { | 24 | enum class TouchScreenModeForNx : u8 { |
| 19 | UseSystemSetting, | 25 | UseSystemSetting, |
| 20 | Finger, | 26 | Finger, |
| 21 | Heat2, | 27 | Heat2, |
| 22 | }; | 28 | }; |
| 23 | 29 | ||
| 30 | // This is nn::hid::TouchScreenConfigurationForNx | ||
| 24 | struct TouchScreenConfigurationForNx { | 31 | struct TouchScreenConfigurationForNx { |
| 25 | TouchScreenModeForNx mode; | 32 | TouchScreenModeForNx mode; |
| 26 | INSERT_PADDING_BYTES_NOINIT(0x7); | 33 | INSERT_PADDING_BYTES_NOINIT(0x7); |
| @@ -29,7 +36,7 @@ public: | |||
| 29 | static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, | 36 | static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, |
| 30 | "TouchScreenConfigurationForNx is an invalid size"); | 37 | "TouchScreenConfigurationForNx is an invalid size"); |
| 31 | 38 | ||
| 32 | explicit Controller_Touchscreen(Core::System& system_); | 39 | explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); |
| 33 | ~Controller_Touchscreen() override; | 40 | ~Controller_Touchscreen() override; |
| 34 | 41 | ||
| 35 | // Called when the controller is initialized | 42 | // Called when the controller is initialized |
| @@ -41,73 +48,24 @@ public: | |||
| 41 | // When the controller is requesting an update for the shared memory | 48 | // When the controller is requesting an update for the shared memory |
| 42 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 49 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 43 | 50 | ||
| 44 | // Called when input devices should be loaded | ||
| 45 | void OnLoadInputDevices() override; | ||
| 46 | |||
| 47 | private: | 51 | private: |
| 48 | static constexpr std::size_t MAX_FINGERS = 16; | 52 | static constexpr std::size_t MAX_FINGERS = 16; |
| 49 | 53 | ||
| 50 | // Returns an unused finger id, if there is no fingers available std::nullopt will be returned | 54 | // This is nn::hid::TouchScreenState |
| 51 | std::optional<std::size_t> GetUnusedFingerID() const; | 55 | struct TouchScreenState { |
| 52 | 56 | s64 sampling_number; | |
| 53 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no | 57 | s32 entry_count; |
| 54 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch | 58 | INSERT_PADDING_BYTES(4); // Reserved |
| 55 | // ends delays the output by one frame to set the end_touch flag before finally freeing the | 59 | std::array<Core::HID::TouchState, MAX_FINGERS> states; |
| 56 | // finger id | ||
| 57 | std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 58 | std::size_t finger_id); | ||
| 59 | |||
| 60 | struct Attributes { | ||
| 61 | union { | ||
| 62 | u32 raw{}; | ||
| 63 | BitField<0, 1, u32> start_touch; | ||
| 64 | BitField<1, 1, u32> end_touch; | ||
| 65 | }; | ||
| 66 | }; | ||
| 67 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 68 | |||
| 69 | struct TouchState { | ||
| 70 | u64_le delta_time; | ||
| 71 | Attributes attribute; | ||
| 72 | u32_le finger; | ||
| 73 | Common::Point<u32_le> position; | ||
| 74 | u32_le diameter_x; | ||
| 75 | u32_le diameter_y; | ||
| 76 | u32_le rotation_angle; | ||
| 77 | }; | 60 | }; |
| 78 | static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); | 61 | static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); |
| 79 | 62 | ||
| 80 | struct TouchScreenEntry { | 63 | // This is nn::hid::detail::TouchScreenLifo |
| 81 | s64_le sampling_number; | 64 | Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{}; |
| 82 | s64_le sampling_number2; | 65 | static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); |
| 83 | s32_le entry_count; | 66 | TouchScreenState next_state{}; |
| 84 | std::array<TouchState, MAX_FINGERS> states; | ||
| 85 | }; | ||
| 86 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); | ||
| 87 | |||
| 88 | struct TouchScreenSharedMemory { | ||
| 89 | CommonHeader header; | ||
| 90 | std::array<TouchScreenEntry, 17> shared_memory_entries{}; | ||
| 91 | INSERT_PADDING_BYTES(0x3c8); | ||
| 92 | }; | ||
| 93 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, | ||
| 94 | "TouchScreenSharedMemory is an invalid size"); | ||
| 95 | |||
| 96 | struct Finger { | ||
| 97 | u64_le last_touch{}; | ||
| 98 | Common::Point<float> position; | ||
| 99 | u32_le id{}; | ||
| 100 | bool pressed{}; | ||
| 101 | Attributes attribute; | ||
| 102 | }; | ||
| 103 | 67 | ||
| 104 | TouchScreenSharedMemory shared_memory{}; | 68 | std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; |
| 105 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; | 69 | Core::HID::EmulatedConsole* console; |
| 106 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | ||
| 107 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | ||
| 108 | std::array<std::size_t, MAX_FINGERS> mouse_finger_id; | ||
| 109 | std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; | ||
| 110 | std::array<std::size_t, MAX_FINGERS> udp_finger_id; | ||
| 111 | std::array<Finger, MAX_FINGERS> fingers; | ||
| 112 | }; | 70 | }; |
| 113 | } // namespace Service::HID | 71 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 41dc22cf9..e4da16466 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp | |||
| @@ -5,12 +5,13 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hid/hid_core.h" | ||
| 8 | #include "core/hle/service/hid/controllers/xpad.h" | 9 | #include "core/hle/service/hid/controllers/xpad.h" |
| 9 | 10 | ||
| 10 | namespace Service::HID { | 11 | namespace Service::HID { |
| 11 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; | 12 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; |
| 12 | 13 | ||
| 13 | Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {} | 14 | Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} |
| 14 | Controller_XPad::~Controller_XPad() = default; | 15 | Controller_XPad::~Controller_XPad() = default; |
| 15 | 16 | ||
| 16 | void Controller_XPad::OnInit() {} | 17 | void Controller_XPad::OnInit() {} |
| @@ -19,28 +20,19 @@ void Controller_XPad::OnRelease() {} | |||
| 19 | 20 | ||
| 20 | void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 21 | void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 21 | std::size_t size) { | 22 | std::size_t size) { |
| 22 | for (auto& xpad_entry : shared_memory.shared_memory_entries) { | 23 | if (!IsControllerActivated()) { |
| 23 | xpad_entry.header.timestamp = core_timing.GetCPUTicks(); | 24 | basic_xpad_lifo.buffer_count = 0; |
| 24 | xpad_entry.header.total_entry_count = 17; | 25 | basic_xpad_lifo.buffer_tail = 0; |
| 25 | 26 | std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); | |
| 26 | if (!IsControllerActivated()) { | 27 | return; |
| 27 | xpad_entry.header.entry_count = 0; | ||
| 28 | xpad_entry.header.last_entry_index = 0; | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | xpad_entry.header.entry_count = 16; | ||
| 32 | |||
| 33 | const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; | ||
| 34 | xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; | ||
| 35 | auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; | ||
| 36 | |||
| 37 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 38 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 39 | } | 28 | } |
| 29 | |||
| 30 | const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; | ||
| 31 | next_state.sampling_number = last_entry.sampling_number + 1; | ||
| 40 | // TODO(ogniK): Update xpad states | 32 | // TODO(ogniK): Update xpad states |
| 41 | 33 | ||
| 42 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 34 | basic_xpad_lifo.WriteNextEntry(next_state); |
| 35 | std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); | ||
| 43 | } | 36 | } |
| 44 | 37 | ||
| 45 | void Controller_XPad::OnLoadInputDevices() {} | ||
| 46 | } // namespace Service::HID | 38 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index f9ab5facf..ba8db8d9d 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h | |||
| @@ -8,12 +8,14 @@ | |||
| 8 | #include "common/common_funcs.h" | 8 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "core/hid/hid_types.h" | ||
| 11 | #include "core/hle/service/hid/controllers/controller_base.h" | 12 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 13 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 12 | 14 | ||
| 13 | namespace Service::HID { | 15 | namespace Service::HID { |
| 14 | class Controller_XPad final : public ControllerBase { | 16 | class Controller_XPad final : public ControllerBase { |
| 15 | public: | 17 | public: |
| 16 | explicit Controller_XPad(Core::System& system_); | 18 | explicit Controller_XPad(Core::HID::HIDCore& hid_core_); |
| 17 | ~Controller_XPad() override; | 19 | ~Controller_XPad() override; |
| 18 | 20 | ||
| 19 | // Called when the controller is initialized | 21 | // Called when the controller is initialized |
| @@ -25,13 +27,11 @@ public: | |||
| 25 | // When the controller is requesting an update for the shared memory | 27 | // When the controller is requesting an update for the shared memory |
| 26 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 28 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 27 | 29 | ||
| 28 | // Called when input devices should be loaded | ||
| 29 | void OnLoadInputDevices() override; | ||
| 30 | |||
| 31 | private: | 30 | private: |
| 32 | struct Attributes { | 31 | // This is nn::hid::BasicXpadAttributeSet |
| 32 | struct BasicXpadAttributeSet { | ||
| 33 | union { | 33 | union { |
| 34 | u32_le raw{}; | 34 | u32 raw{}; |
| 35 | BitField<0, 1, u32> is_connected; | 35 | BitField<0, 1, u32> is_connected; |
| 36 | BitField<1, 1, u32> is_wired; | 36 | BitField<1, 1, u32> is_wired; |
| 37 | BitField<2, 1, u32> is_left_connected; | 37 | BitField<2, 1, u32> is_left_connected; |
| @@ -40,11 +40,12 @@ private: | |||
| 40 | BitField<5, 1, u32> is_right_wired; | 40 | BitField<5, 1, u32> is_right_wired; |
| 41 | }; | 41 | }; |
| 42 | }; | 42 | }; |
| 43 | static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); | 43 | static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size"); |
| 44 | 44 | ||
| 45 | struct Buttons { | 45 | // This is nn::hid::BasicXpadButtonSet |
| 46 | struct BasicXpadButtonSet { | ||
| 46 | union { | 47 | union { |
| 47 | u32_le raw{}; | 48 | u32 raw{}; |
| 48 | // Button states | 49 | // Button states |
| 49 | BitField<0, 1, u32> a; | 50 | BitField<0, 1, u32> a; |
| 50 | BitField<1, 1, u32> b; | 51 | BitField<1, 1, u32> b; |
| @@ -88,35 +89,21 @@ private: | |||
| 88 | BitField<30, 1, u32> handheld_left_b; | 89 | BitField<30, 1, u32> handheld_left_b; |
| 89 | }; | 90 | }; |
| 90 | }; | 91 | }; |
| 91 | static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); | 92 | static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size"); |
| 92 | 93 | ||
| 93 | struct AnalogStick { | 94 | // This is nn::hid::detail::BasicXpadState |
| 94 | s32_le x; | 95 | struct BasicXpadState { |
| 95 | s32_le y; | 96 | s64 sampling_number; |
| 96 | }; | 97 | BasicXpadAttributeSet attributes; |
| 97 | static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); | 98 | BasicXpadButtonSet pad_states; |
| 98 | 99 | Core::HID::AnalogStickState l_stick; | |
| 99 | struct XPadState { | 100 | Core::HID::AnalogStickState r_stick; |
| 100 | s64_le sampling_number; | ||
| 101 | s64_le sampling_number2; | ||
| 102 | Attributes attributes; | ||
| 103 | Buttons pad_states; | ||
| 104 | AnalogStick l_stick; | ||
| 105 | AnalogStick r_stick; | ||
| 106 | }; | 101 | }; |
| 107 | static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); | 102 | static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); |
| 108 | 103 | ||
| 109 | struct XPadEntry { | 104 | // This is nn::hid::detail::BasicXpadLifo |
| 110 | CommonHeader header; | 105 | Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{}; |
| 111 | std::array<XPadState, 17> pad_states{}; | 106 | static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); |
| 112 | INSERT_PADDING_BYTES(0x138); | 107 | BasicXpadState next_state{}; |
| 113 | }; | ||
| 114 | static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); | ||
| 115 | |||
| 116 | struct SharedMemory { | ||
| 117 | std::array<XPadEntry, 4> shared_memory_entries{}; | ||
| 118 | }; | ||
| 119 | static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); | ||
| 120 | SharedMemory shared_memory{}; | ||
| 121 | }; | 108 | }; |
| 122 | } // namespace Service::HID | 109 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 10c64d41a..7163e1a4e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include "common/settings.h" | 8 | #include "common/settings.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 11 | #include "core/frontend/input.h" | 11 | #include "core/hid/hid_core.h" |
| 12 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/k_readable_event.h" | 13 | #include "core/hle/kernel/k_readable_event.h" |
| 14 | #include "core/hle/kernel/k_shared_memory.h" | 14 | #include "core/hle/kernel/k_shared_memory.h" |
| @@ -34,10 +34,10 @@ | |||
| 34 | namespace Service::HID { | 34 | namespace Service::HID { |
| 35 | 35 | ||
| 36 | // Updating period for each HID device. | 36 | // Updating period for each HID device. |
| 37 | // HID is polled every 15ms, this value was derived from | 37 | // Period time is obtained by measuring the number of samples in a second on HW using a homebrew |
| 38 | // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet | 38 | constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) |
| 39 | constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) | 39 | constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) |
| 40 | constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) | 40 | constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) |
| 41 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; | 41 | constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; |
| 42 | 42 | ||
| 43 | IAppletResource::IAppletResource(Core::System& system_, | 43 | IAppletResource::IAppletResource(Core::System& system_, |
| @@ -79,17 +79,24 @@ IAppletResource::IAppletResource(Core::System& system_, | |||
| 79 | const auto guard = LockService(); | 79 | const auto guard = LockService(); |
| 80 | UpdateControllers(user_data, ns_late); | 80 | UpdateControllers(user_data, ns_late); |
| 81 | }); | 81 | }); |
| 82 | mouse_keyboard_update_event = Core::Timing::CreateEvent( | ||
| 83 | "HID::UpdateMouseKeyboardCallback", | ||
| 84 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | ||
| 85 | const auto guard = LockService(); | ||
| 86 | UpdateMouseKeyboard(user_data, ns_late); | ||
| 87 | }); | ||
| 82 | motion_update_event = Core::Timing::CreateEvent( | 88 | motion_update_event = Core::Timing::CreateEvent( |
| 83 | "HID::MotionPadCallback", | 89 | "HID::UpdateMotionCallback", |
| 84 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 90 | [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { |
| 85 | const auto guard = LockService(); | 91 | const auto guard = LockService(); |
| 86 | UpdateMotion(user_data, ns_late); | 92 | UpdateMotion(user_data, ns_late); |
| 87 | }); | 93 | }); |
| 88 | 94 | ||
| 89 | system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); | 95 | system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); |
| 96 | system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); | ||
| 90 | system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); | 97 | system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); |
| 91 | 98 | ||
| 92 | ReloadInputDevices(); | 99 | system.HIDCore().ReloadInputDevices(); |
| 93 | } | 100 | } |
| 94 | 101 | ||
| 95 | void IAppletResource::ActivateController(HidController controller) { | 102 | void IAppletResource::ActivateController(HidController controller) { |
| @@ -102,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) { | |||
| 102 | 109 | ||
| 103 | IAppletResource::~IAppletResource() { | 110 | IAppletResource::~IAppletResource() { |
| 104 | system.CoreTiming().UnscheduleEvent(pad_update_event, 0); | 111 | system.CoreTiming().UnscheduleEvent(pad_update_event, 0); |
| 112 | system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); | ||
| 105 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); | 113 | system.CoreTiming().UnscheduleEvent(motion_update_event, 0); |
| 106 | } | 114 | } |
| 107 | 115 | ||
| @@ -117,23 +125,44 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, | |||
| 117 | std::chrono::nanoseconds ns_late) { | 125 | std::chrono::nanoseconds ns_late) { |
| 118 | auto& core_timing = system.CoreTiming(); | 126 | auto& core_timing = system.CoreTiming(); |
| 119 | 127 | ||
| 120 | const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); | ||
| 121 | for (const auto& controller : controllers) { | 128 | for (const auto& controller : controllers) { |
| 122 | if (should_reload) { | 129 | // Keyboard has it's own update event |
| 123 | controller->OnLoadInputDevices(); | 130 | if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) { |
| 131 | continue; | ||
| 132 | } | ||
| 133 | // Mouse has it's own update event | ||
| 134 | if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { | ||
| 135 | continue; | ||
| 124 | } | 136 | } |
| 125 | controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), | 137 | controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), |
| 126 | SHARED_MEMORY_SIZE); | 138 | SHARED_MEMORY_SIZE); |
| 127 | } | 139 | } |
| 128 | 140 | ||
| 129 | // If ns_late is higher than the update rate ignore the delay | 141 | // If ns_late is higher than the update rate ignore the delay |
| 130 | if (ns_late > motion_update_ns) { | 142 | if (ns_late > pad_update_ns) { |
| 131 | ns_late = {}; | 143 | ns_late = {}; |
| 132 | } | 144 | } |
| 133 | 145 | ||
| 134 | core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); | 146 | core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); |
| 135 | } | 147 | } |
| 136 | 148 | ||
| 149 | void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, | ||
| 150 | std::chrono::nanoseconds ns_late) { | ||
| 151 | auto& core_timing = system.CoreTiming(); | ||
| 152 | |||
| 153 | controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate( | ||
| 154 | core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); | ||
| 155 | controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate( | ||
| 156 | core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); | ||
| 157 | |||
| 158 | // If ns_late is higher than the update rate ignore the delay | ||
| 159 | if (ns_late > mouse_keyboard_update_ns) { | ||
| 160 | ns_late = {}; | ||
| 161 | } | ||
| 162 | |||
| 163 | core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); | ||
| 164 | } | ||
| 165 | |||
| 137 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 166 | void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { |
| 138 | auto& core_timing = system.CoreTiming(); | 167 | auto& core_timing = system.CoreTiming(); |
| 139 | 168 | ||
| @@ -166,7 +195,7 @@ public: | |||
| 166 | private: | 195 | private: |
| 167 | void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { | 196 | void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { |
| 168 | IPC::RequestParser rp{ctx}; | 197 | IPC::RequestParser rp{ctx}; |
| 169 | const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; | 198 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; |
| 170 | 199 | ||
| 171 | if (applet_resource != nullptr) { | 200 | if (applet_resource != nullptr) { |
| 172 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 201 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| @@ -264,8 +293,8 @@ Hid::Hid(Core::System& system_) | |||
| 264 | {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, | 293 | {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"}, |
| 265 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, | 294 | {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, |
| 266 | {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, | 295 | {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"}, |
| 267 | {135, nullptr, "SetNpadCaptureButtonAssignment"}, | 296 | {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"}, |
| 268 | {136, nullptr, "ClearNpadCaptureButtonAssignment"}, | 297 | {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"}, |
| 269 | {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, | 298 | {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"}, |
| 270 | {201, &Hid::SendVibrationValue, "SendVibrationValue"}, | 299 | {201, &Hid::SendVibrationValue, "SendVibrationValue"}, |
| 271 | {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, | 300 | {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"}, |
| @@ -422,6 +451,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { | |||
| 422 | INSERT_PADDING_WORDS_NOINIT(1); | 451 | INSERT_PADDING_WORDS_NOINIT(1); |
| 423 | u64 applet_resource_user_id; | 452 | u64 applet_resource_user_id; |
| 424 | }; | 453 | }; |
| 454 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 425 | 455 | ||
| 426 | const auto parameters{rp.PopRaw<Parameters>()}; | 456 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 427 | 457 | ||
| @@ -448,19 +478,18 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { | |||
| 448 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 478 | void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 449 | IPC::RequestParser rp{ctx}; | 479 | IPC::RequestParser rp{ctx}; |
| 450 | struct Parameters { | 480 | struct Parameters { |
| 451 | Controller_NPad::DeviceHandle sixaxis_handle; | 481 | u32 basic_xpad_id; |
| 452 | INSERT_PADDING_WORDS_NOINIT(1); | 482 | INSERT_PADDING_WORDS_NOINIT(1); |
| 453 | u64 applet_resource_user_id; | 483 | u64 applet_resource_user_id; |
| 454 | }; | 484 | }; |
| 485 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 455 | 486 | ||
| 456 | const auto parameters{rp.PopRaw<Parameters>()}; | 487 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 457 | 488 | ||
| 458 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); | 489 | // This function does nothing on 10.0.0+ |
| 459 | 490 | ||
| 460 | LOG_DEBUG(Service_HID, | 491 | LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", |
| 461 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 492 | parameters.basic_xpad_id, parameters.applet_resource_user_id); |
| 462 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 463 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 464 | 493 | ||
| 465 | IPC::ResponseBuilder rb{ctx, 2}; | 494 | IPC::ResponseBuilder rb{ctx, 2}; |
| 466 | rb.Push(ResultSuccess); | 495 | rb.Push(ResultSuccess); |
| @@ -469,19 +498,18 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 469 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | 498 | void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 470 | IPC::RequestParser rp{ctx}; | 499 | IPC::RequestParser rp{ctx}; |
| 471 | struct Parameters { | 500 | struct Parameters { |
| 472 | Controller_NPad::DeviceHandle sixaxis_handle; | 501 | u32 basic_xpad_id; |
| 473 | INSERT_PADDING_WORDS_NOINIT(1); | 502 | INSERT_PADDING_WORDS_NOINIT(1); |
| 474 | u64 applet_resource_user_id; | 503 | u64 applet_resource_user_id; |
| 475 | }; | 504 | }; |
| 505 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 476 | 506 | ||
| 477 | const auto parameters{rp.PopRaw<Parameters>()}; | 507 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 478 | 508 | ||
| 479 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); | 509 | // This function does nothing on 10.0.0+ |
| 480 | 510 | ||
| 481 | LOG_DEBUG(Service_HID, | 511 | LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", |
| 482 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 512 | parameters.basic_xpad_id, parameters.applet_resource_user_id); |
| 483 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | ||
| 484 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 485 | 513 | ||
| 486 | IPC::ResponseBuilder rb{ctx, 2}; | 514 | IPC::ResponseBuilder rb{ctx, 2}; |
| 487 | rb.Push(ResultSuccess); | 515 | rb.Push(ResultSuccess); |
| @@ -490,14 +518,16 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 490 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 518 | void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 491 | IPC::RequestParser rp{ctx}; | 519 | IPC::RequestParser rp{ctx}; |
| 492 | struct Parameters { | 520 | struct Parameters { |
| 493 | Controller_NPad::DeviceHandle sixaxis_handle; | 521 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 494 | INSERT_PADDING_WORDS_NOINIT(1); | 522 | INSERT_PADDING_WORDS_NOINIT(1); |
| 495 | u64 applet_resource_user_id; | 523 | u64 applet_resource_user_id; |
| 496 | }; | 524 | }; |
| 525 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 497 | 526 | ||
| 498 | const auto parameters{rp.PopRaw<Parameters>()}; | 527 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 499 | 528 | ||
| 500 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); | 529 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 530 | .SetSixAxisEnabled(parameters.sixaxis_handle, true); | ||
| 501 | 531 | ||
| 502 | LOG_DEBUG(Service_HID, | 532 | LOG_DEBUG(Service_HID, |
| 503 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 533 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| @@ -511,14 +541,16 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 511 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | 541 | void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 512 | IPC::RequestParser rp{ctx}; | 542 | IPC::RequestParser rp{ctx}; |
| 513 | struct Parameters { | 543 | struct Parameters { |
| 514 | Controller_NPad::DeviceHandle sixaxis_handle; | 544 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 515 | INSERT_PADDING_WORDS_NOINIT(1); | 545 | INSERT_PADDING_WORDS_NOINIT(1); |
| 516 | u64 applet_resource_user_id; | 546 | u64 applet_resource_user_id; |
| 517 | }; | 547 | }; |
| 548 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 518 | 549 | ||
| 519 | const auto parameters{rp.PopRaw<Parameters>()}; | 550 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 520 | 551 | ||
| 521 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); | 552 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 553 | .SetSixAxisEnabled(parameters.sixaxis_handle, false); | ||
| 522 | 554 | ||
| 523 | LOG_DEBUG(Service_HID, | 555 | LOG_DEBUG(Service_HID, |
| 524 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 556 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| @@ -534,19 +566,23 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { | |||
| 534 | struct Parameters { | 566 | struct Parameters { |
| 535 | bool enable_sixaxis_sensor_fusion; | 567 | bool enable_sixaxis_sensor_fusion; |
| 536 | INSERT_PADDING_BYTES_NOINIT(3); | 568 | INSERT_PADDING_BYTES_NOINIT(3); |
| 537 | Controller_NPad::DeviceHandle sixaxis_handle; | 569 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 538 | u64 applet_resource_user_id; | 570 | u64 applet_resource_user_id; |
| 539 | }; | 571 | }; |
| 540 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | 572 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); |
| 541 | 573 | ||
| 542 | const auto parameters{rp.PopRaw<Parameters>()}; | 574 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 543 | 575 | ||
| 544 | LOG_WARNING(Service_HID, | 576 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 545 | "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " | 577 | .SetSixAxisFusionEnabled(parameters.sixaxis_handle, |
| 546 | "device_index={}, applet_resource_user_id={}", | 578 | parameters.enable_sixaxis_sensor_fusion); |
| 547 | parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, | 579 | |
| 548 | parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, | 580 | LOG_DEBUG(Service_HID, |
| 549 | parameters.applet_resource_user_id); | 581 | "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " |
| 582 | "device_index={}, applet_resource_user_id={}", | ||
| 583 | parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, | ||
| 584 | parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, | ||
| 585 | parameters.applet_resource_user_id); | ||
| 550 | 586 | ||
| 551 | IPC::ResponseBuilder rb{ctx, 2}; | 587 | IPC::ResponseBuilder rb{ctx, 2}; |
| 552 | rb.Push(ResultSuccess); | 588 | rb.Push(ResultSuccess); |
| @@ -555,9 +591,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { | |||
| 555 | void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | 591 | void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { |
| 556 | IPC::RequestParser rp{ctx}; | 592 | IPC::RequestParser rp{ctx}; |
| 557 | struct Parameters { | 593 | struct Parameters { |
| 558 | Controller_NPad::DeviceHandle sixaxis_handle; | 594 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 559 | f32 parameter1; | 595 | Core::HID::SixAxisSensorFusionParameters sixaxis_fusion; |
| 560 | f32 parameter2; | 596 | INSERT_PADDING_WORDS_NOINIT(1); |
| 561 | u64 applet_resource_user_id; | 597 | u64 applet_resource_user_id; |
| 562 | }; | 598 | }; |
| 563 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | 599 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); |
| @@ -565,14 +601,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 565 | const auto parameters{rp.PopRaw<Parameters>()}; | 601 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 566 | 602 | ||
| 567 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 603 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 568 | .SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); | 604 | .SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); |
| 569 | 605 | ||
| 570 | LOG_WARNING(Service_HID, | 606 | LOG_DEBUG(Service_HID, |
| 571 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " | 607 | "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " |
| 572 | "parameter2={}, applet_resource_user_id={}", | 608 | "parameter2={}, applet_resource_user_id={}", |
| 573 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | 609 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, |
| 574 | parameters.sixaxis_handle.device_index, parameters.parameter1, | 610 | parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1, |
| 575 | parameters.parameter2, parameters.applet_resource_user_id); | 611 | parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id); |
| 576 | 612 | ||
| 577 | IPC::ResponseBuilder rb{ctx, 2}; | 613 | IPC::ResponseBuilder rb{ctx, 2}; |
| 578 | rb.Push(ResultSuccess); | 614 | rb.Push(ResultSuccess); |
| @@ -581,35 +617,33 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 581 | void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | 617 | void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { |
| 582 | IPC::RequestParser rp{ctx}; | 618 | IPC::RequestParser rp{ctx}; |
| 583 | struct Parameters { | 619 | struct Parameters { |
| 584 | Controller_NPad::DeviceHandle sixaxis_handle; | 620 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 621 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 585 | u64 applet_resource_user_id; | 622 | u64 applet_resource_user_id; |
| 586 | }; | 623 | }; |
| 587 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | 624 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); |
| 588 | 625 | ||
| 589 | f32 parameter1 = 0; | ||
| 590 | f32 parameter2 = 0; | ||
| 591 | const auto parameters{rp.PopRaw<Parameters>()}; | 626 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 592 | 627 | ||
| 593 | std::tie(parameter1, parameter2) = | 628 | const auto sixaxis_fusion_parameters = |
| 594 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 629 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 595 | .GetSixAxisFusionParameters(); | 630 | .GetSixAxisFusionParameters(parameters.sixaxis_handle); |
| 596 | 631 | ||
| 597 | LOG_WARNING( | 632 | LOG_DEBUG(Service_HID, |
| 598 | Service_HID, | 633 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 599 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 634 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, |
| 600 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | 635 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); |
| 601 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 602 | 636 | ||
| 603 | IPC::ResponseBuilder rb{ctx, 4}; | 637 | IPC::ResponseBuilder rb{ctx, 4}; |
| 604 | rb.Push(ResultSuccess); | 638 | rb.Push(ResultSuccess); |
| 605 | rb.Push(parameter1); | 639 | rb.PushRaw(sixaxis_fusion_parameters); |
| 606 | rb.Push(parameter2); | ||
| 607 | } | 640 | } |
| 608 | 641 | ||
| 609 | void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | 642 | void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { |
| 610 | IPC::RequestParser rp{ctx}; | 643 | IPC::RequestParser rp{ctx}; |
| 611 | struct Parameters { | 644 | struct Parameters { |
| 612 | Controller_NPad::DeviceHandle sixaxis_handle; | 645 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 646 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 613 | u64 applet_resource_user_id; | 647 | u64 applet_resource_user_id; |
| 614 | }; | 648 | }; |
| 615 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | 649 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); |
| @@ -617,13 +651,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 617 | const auto parameters{rp.PopRaw<Parameters>()}; | 651 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 618 | 652 | ||
| 619 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 653 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 620 | .ResetSixAxisFusionParameters(); | 654 | .ResetSixAxisFusionParameters(parameters.sixaxis_handle); |
| 621 | 655 | ||
| 622 | LOG_WARNING( | 656 | LOG_DEBUG(Service_HID, |
| 623 | Service_HID, | 657 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 624 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 658 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, |
| 625 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | 659 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); |
| 626 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 627 | 660 | ||
| 628 | IPC::ResponseBuilder rb{ctx, 2}; | 661 | IPC::ResponseBuilder rb{ctx, 2}; |
| 629 | rb.Push(ResultSuccess); | 662 | rb.Push(ResultSuccess); |
| @@ -631,12 +664,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { | |||
| 631 | 664 | ||
| 632 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 665 | void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 633 | IPC::RequestParser rp{ctx}; | 666 | IPC::RequestParser rp{ctx}; |
| 634 | const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; | 667 | const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()}; |
| 635 | const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; | 668 | const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; |
| 636 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 669 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 637 | 670 | ||
| 638 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 671 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 639 | .SetGyroscopeZeroDriftMode(drift_mode); | 672 | .SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); |
| 640 | 673 | ||
| 641 | LOG_DEBUG(Service_HID, | 674 | LOG_DEBUG(Service_HID, |
| 642 | "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " | 675 | "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " |
| @@ -651,10 +684,11 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 651 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 684 | void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 652 | IPC::RequestParser rp{ctx}; | 685 | IPC::RequestParser rp{ctx}; |
| 653 | struct Parameters { | 686 | struct Parameters { |
| 654 | Controller_NPad::DeviceHandle sixaxis_handle; | 687 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 655 | INSERT_PADDING_WORDS_NOINIT(1); | 688 | INSERT_PADDING_WORDS_NOINIT(1); |
| 656 | u64 applet_resource_user_id; | 689 | u64 applet_resource_user_id; |
| 657 | }; | 690 | }; |
| 691 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 658 | 692 | ||
| 659 | const auto parameters{rp.PopRaw<Parameters>()}; | 693 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 660 | 694 | ||
| @@ -666,21 +700,23 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 666 | IPC::ResponseBuilder rb{ctx, 3}; | 700 | IPC::ResponseBuilder rb{ctx, 3}; |
| 667 | rb.Push(ResultSuccess); | 701 | rb.Push(ResultSuccess); |
| 668 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 702 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 669 | .GetGyroscopeZeroDriftMode()); | 703 | .GetGyroscopeZeroDriftMode(parameters.sixaxis_handle)); |
| 670 | } | 704 | } |
| 671 | 705 | ||
| 672 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 706 | void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 673 | IPC::RequestParser rp{ctx}; | 707 | IPC::RequestParser rp{ctx}; |
| 674 | struct Parameters { | 708 | struct Parameters { |
| 675 | Controller_NPad::DeviceHandle sixaxis_handle; | 709 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 676 | INSERT_PADDING_WORDS_NOINIT(1); | 710 | INSERT_PADDING_WORDS_NOINIT(1); |
| 677 | u64 applet_resource_user_id; | 711 | u64 applet_resource_user_id; |
| 678 | }; | 712 | }; |
| 713 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 679 | 714 | ||
| 680 | const auto parameters{rp.PopRaw<Parameters>()}; | 715 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 716 | const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; | ||
| 681 | 717 | ||
| 682 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 718 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 683 | .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); | 719 | .SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); |
| 684 | 720 | ||
| 685 | LOG_DEBUG(Service_HID, | 721 | LOG_DEBUG(Service_HID, |
| 686 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 722 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| @@ -694,10 +730,11 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | |||
| 694 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | 730 | void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { |
| 695 | IPC::RequestParser rp{ctx}; | 731 | IPC::RequestParser rp{ctx}; |
| 696 | struct Parameters { | 732 | struct Parameters { |
| 697 | Controller_NPad::DeviceHandle sixaxis_handle; | 733 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 698 | INSERT_PADDING_WORDS_NOINIT(1); | 734 | INSERT_PADDING_WORDS_NOINIT(1); |
| 699 | u64 applet_resource_user_id; | 735 | u64 applet_resource_user_id; |
| 700 | }; | 736 | }; |
| 737 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 701 | 738 | ||
| 702 | const auto parameters{rp.PopRaw<Parameters>()}; | 739 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 703 | 740 | ||
| @@ -709,16 +746,17 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | |||
| 709 | IPC::ResponseBuilder rb{ctx, 3}; | 746 | IPC::ResponseBuilder rb{ctx, 3}; |
| 710 | rb.Push(ResultSuccess); | 747 | rb.Push(ResultSuccess); |
| 711 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 748 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 712 | .IsSixAxisSensorAtRest()); | 749 | .IsSixAxisSensorAtRest(parameters.sixaxis_handle)); |
| 713 | } | 750 | } |
| 714 | 751 | ||
| 715 | void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { | 752 | void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 716 | IPC::RequestParser rp{ctx}; | 753 | IPC::RequestParser rp{ctx}; |
| 717 | struct Parameters { | 754 | struct Parameters { |
| 718 | Controller_NPad::DeviceHandle sixaxis_handle; | 755 | Core::HID::SixAxisSensorHandle sixaxis_handle; |
| 719 | INSERT_PADDING_WORDS_NOINIT(1); | 756 | INSERT_PADDING_WORDS_NOINIT(1); |
| 720 | u64 applet_resource_user_id; | 757 | u64 applet_resource_user_id; |
| 721 | }; | 758 | }; |
| 759 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 722 | 760 | ||
| 723 | const auto parameters{rp.PopRaw<Parameters>()}; | 761 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 724 | 762 | ||
| @@ -740,13 +778,14 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | |||
| 740 | INSERT_PADDING_WORDS_NOINIT(1); | 778 | INSERT_PADDING_WORDS_NOINIT(1); |
| 741 | u64 applet_resource_user_id; | 779 | u64 applet_resource_user_id; |
| 742 | }; | 780 | }; |
| 781 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 743 | 782 | ||
| 744 | const auto parameters{rp.PopRaw<Parameters>()}; | 783 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 745 | 784 | ||
| 746 | applet_resource->ActivateController(HidController::Gesture); | 785 | applet_resource->ActivateController(HidController::Gesture); |
| 747 | 786 | ||
| 748 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, | 787 | LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}", |
| 749 | parameters.applet_resource_user_id); | 788 | parameters.unknown, parameters.applet_resource_user_id); |
| 750 | 789 | ||
| 751 | IPC::ResponseBuilder rb{ctx, 2}; | 790 | IPC::ResponseBuilder rb{ctx, 2}; |
| 752 | rb.Push(ResultSuccess); | 791 | rb.Push(ResultSuccess); |
| @@ -754,12 +793,20 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { | |||
| 754 | 793 | ||
| 755 | void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 794 | void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 756 | IPC::RequestParser rp{ctx}; | 795 | IPC::RequestParser rp{ctx}; |
| 757 | const auto supported_styleset{rp.Pop<u32>()}; | 796 | struct Parameters { |
| 797 | Core::HID::NpadStyleSet supported_styleset; | ||
| 798 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 799 | u64 applet_resource_user_id; | ||
| 800 | }; | ||
| 801 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 802 | |||
| 803 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 758 | 804 | ||
| 759 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 805 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 760 | .SetSupportedStyleSet({supported_styleset}); | 806 | .SetSupportedStyleSet({parameters.supported_styleset}); |
| 761 | 807 | ||
| 762 | LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); | 808 | LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", |
| 809 | parameters.supported_styleset, parameters.applet_resource_user_id); | ||
| 763 | 810 | ||
| 764 | IPC::ResponseBuilder rb{ctx, 2}; | 811 | IPC::ResponseBuilder rb{ctx, 2}; |
| 765 | rb.Push(ResultSuccess); | 812 | rb.Push(ResultSuccess); |
| @@ -773,9 +820,9 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | |||
| 773 | 820 | ||
| 774 | IPC::ResponseBuilder rb{ctx, 3}; | 821 | IPC::ResponseBuilder rb{ctx, 3}; |
| 775 | rb.Push(ResultSuccess); | 822 | rb.Push(ResultSuccess); |
| 776 | rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 823 | rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 777 | .GetSupportedStyleSet() | 824 | .GetSupportedStyleSet() |
| 778 | .raw); | 825 | .raw); |
| 779 | } | 826 | } |
| 780 | 827 | ||
| 781 | void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 828 | void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| @@ -818,11 +865,12 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { | |||
| 818 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 865 | void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 819 | IPC::RequestParser rp{ctx}; | 866 | IPC::RequestParser rp{ctx}; |
| 820 | struct Parameters { | 867 | struct Parameters { |
| 821 | u32 npad_id; | 868 | Core::HID::NpadIdType npad_id; |
| 822 | INSERT_PADDING_WORDS_NOINIT(1); | 869 | INSERT_PADDING_WORDS_NOINIT(1); |
| 823 | u64 applet_resource_user_id; | 870 | u64 applet_resource_user_id; |
| 824 | u64 unknown; | 871 | u64 unknown; |
| 825 | }; | 872 | }; |
| 873 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 826 | 874 | ||
| 827 | const auto parameters{rp.PopRaw<Parameters>()}; | 875 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 828 | 876 | ||
| @@ -838,10 +886,11 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | |||
| 838 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | 886 | void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 839 | IPC::RequestParser rp{ctx}; | 887 | IPC::RequestParser rp{ctx}; |
| 840 | struct Parameters { | 888 | struct Parameters { |
| 841 | u32 npad_id; | 889 | Core::HID::NpadIdType npad_id; |
| 842 | INSERT_PADDING_WORDS_NOINIT(1); | 890 | INSERT_PADDING_WORDS_NOINIT(1); |
| 843 | u64 applet_resource_user_id; | 891 | u64 applet_resource_user_id; |
| 844 | }; | 892 | }; |
| 893 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 845 | 894 | ||
| 846 | const auto parameters{rp.PopRaw<Parameters>()}; | 895 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 847 | 896 | ||
| @@ -857,7 +906,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { | |||
| 857 | 906 | ||
| 858 | void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 907 | void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 859 | IPC::RequestParser rp{ctx}; | 908 | IPC::RequestParser rp{ctx}; |
| 860 | const auto npad_id{rp.Pop<u32>()}; | 909 | const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 861 | 910 | ||
| 862 | LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); | 911 | LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); |
| 863 | 912 | ||
| @@ -872,16 +921,17 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | |||
| 872 | // Should have no effect with how our npad sets up the data | 921 | // Should have no effect with how our npad sets up the data |
| 873 | IPC::RequestParser rp{ctx}; | 922 | IPC::RequestParser rp{ctx}; |
| 874 | struct Parameters { | 923 | struct Parameters { |
| 875 | u32 unknown; | 924 | s32 revision; |
| 876 | INSERT_PADDING_WORDS_NOINIT(1); | 925 | INSERT_PADDING_WORDS_NOINIT(1); |
| 877 | u64 applet_resource_user_id; | 926 | u64 applet_resource_user_id; |
| 878 | }; | 927 | }; |
| 928 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 879 | 929 | ||
| 880 | const auto parameters{rp.PopRaw<Parameters>()}; | 930 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 881 | 931 | ||
| 882 | applet_resource->ActivateController(HidController::NPad); | 932 | applet_resource->ActivateController(HidController::NPad); |
| 883 | 933 | ||
| 884 | LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, | 934 | LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, |
| 885 | parameters.applet_resource_user_id); | 935 | parameters.applet_resource_user_id); |
| 886 | 936 | ||
| 887 | IPC::ResponseBuilder rb{ctx, 2}; | 937 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -891,7 +941,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | |||
| 891 | void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 941 | void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 892 | IPC::RequestParser rp{ctx}; | 942 | IPC::RequestParser rp{ctx}; |
| 893 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 943 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 894 | const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()}; | 944 | const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()}; |
| 895 | 945 | ||
| 896 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type); | 946 | applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type); |
| 897 | 947 | ||
| @@ -916,42 +966,44 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | |||
| 916 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 966 | void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 917 | IPC::RequestParser rp{ctx}; | 967 | IPC::RequestParser rp{ctx}; |
| 918 | struct Parameters { | 968 | struct Parameters { |
| 919 | u32 npad_id; | 969 | Core::HID::NpadIdType npad_id; |
| 920 | INSERT_PADDING_WORDS_NOINIT(1); | 970 | INSERT_PADDING_WORDS_NOINIT(1); |
| 921 | u64 applet_resource_user_id; | 971 | u64 applet_resource_user_id; |
| 922 | }; | 972 | }; |
| 973 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 923 | 974 | ||
| 924 | const auto parameters{rp.PopRaw<Parameters>()}; | 975 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 925 | 976 | ||
| 926 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 977 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 927 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); | 978 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, |
| 979 | Controller_NPad::NpadJoyAssignmentMode::Single); | ||
| 928 | 980 | ||
| 929 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", | 981 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 930 | parameters.npad_id, parameters.applet_resource_user_id); | 982 | parameters.applet_resource_user_id); |
| 931 | 983 | ||
| 932 | IPC::ResponseBuilder rb{ctx, 2}; | 984 | IPC::ResponseBuilder rb{ctx, 2}; |
| 933 | rb.Push(ResultSuccess); | 985 | rb.Push(ResultSuccess); |
| 934 | } | 986 | } |
| 935 | 987 | ||
| 936 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | 988 | void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { |
| 937 | // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault | ||
| 938 | IPC::RequestParser rp{ctx}; | 989 | IPC::RequestParser rp{ctx}; |
| 939 | struct Parameters { | 990 | struct Parameters { |
| 940 | u32 npad_id; | 991 | Core::HID::NpadIdType npad_id; |
| 941 | INSERT_PADDING_WORDS_NOINIT(1); | 992 | INSERT_PADDING_WORDS_NOINIT(1); |
| 942 | u64 applet_resource_user_id; | 993 | u64 applet_resource_user_id; |
| 943 | u64 npad_joy_device_type; | 994 | Controller_NPad::NpadJoyDeviceType npad_joy_device_type; |
| 944 | }; | 995 | }; |
| 996 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 945 | 997 | ||
| 946 | const auto parameters{rp.PopRaw<Parameters>()}; | 998 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 947 | 999 | ||
| 948 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1000 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 949 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); | 1001 | .SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, |
| 1002 | Controller_NPad::NpadJoyAssignmentMode::Single); | ||
| 950 | 1003 | ||
| 951 | LOG_WARNING(Service_HID, | 1004 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", |
| 952 | "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", | 1005 | parameters.npad_id, parameters.applet_resource_user_id, |
| 953 | parameters.npad_id, parameters.applet_resource_user_id, | 1006 | parameters.npad_joy_device_type); |
| 954 | parameters.npad_joy_device_type); | ||
| 955 | 1007 | ||
| 956 | IPC::ResponseBuilder rb{ctx, 2}; | 1008 | IPC::ResponseBuilder rb{ctx, 2}; |
| 957 | rb.Push(ResultSuccess); | 1009 | rb.Push(ResultSuccess); |
| @@ -960,18 +1012,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { | |||
| 960 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 1012 | void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 961 | IPC::RequestParser rp{ctx}; | 1013 | IPC::RequestParser rp{ctx}; |
| 962 | struct Parameters { | 1014 | struct Parameters { |
| 963 | u32 npad_id; | 1015 | Core::HID::NpadIdType npad_id; |
| 964 | INSERT_PADDING_WORDS_NOINIT(1); | 1016 | INSERT_PADDING_WORDS_NOINIT(1); |
| 965 | u64 applet_resource_user_id; | 1017 | u64 applet_resource_user_id; |
| 966 | }; | 1018 | }; |
| 1019 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 967 | 1020 | ||
| 968 | const auto parameters{rp.PopRaw<Parameters>()}; | 1021 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 969 | 1022 | ||
| 970 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1023 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 971 | .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); | 1024 | .SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); |
| 972 | 1025 | ||
| 973 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", | 1026 | LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, |
| 974 | parameters.npad_id, parameters.applet_resource_user_id); | 1027 | parameters.applet_resource_user_id); |
| 975 | 1028 | ||
| 976 | IPC::ResponseBuilder rb{ctx, 2}; | 1029 | IPC::ResponseBuilder rb{ctx, 2}; |
| 977 | rb.Push(ResultSuccess); | 1030 | rb.Push(ResultSuccess); |
| @@ -979,8 +1032,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | |||
| 979 | 1032 | ||
| 980 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 1033 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| 981 | IPC::RequestParser rp{ctx}; | 1034 | IPC::RequestParser rp{ctx}; |
| 982 | const auto npad_id_1{rp.Pop<u32>()}; | 1035 | const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 983 | const auto npad_id_2{rp.Pop<u32>()}; | 1036 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 984 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1037 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 985 | 1038 | ||
| 986 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1039 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| @@ -1046,8 +1099,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | |||
| 1046 | 1099 | ||
| 1047 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | 1100 | void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { |
| 1048 | IPC::RequestParser rp{ctx}; | 1101 | IPC::RequestParser rp{ctx}; |
| 1049 | const auto npad_id_1{rp.Pop<u32>()}; | 1102 | const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 1050 | const auto npad_id_2{rp.Pop<u32>()}; | 1103 | const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; |
| 1051 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1104 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1052 | 1105 | ||
| 1053 | const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) | 1106 | const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| @@ -1068,10 +1121,11 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { | |||
| 1068 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { | 1121 | void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { |
| 1069 | IPC::RequestParser rp{ctx}; | 1122 | IPC::RequestParser rp{ctx}; |
| 1070 | struct Parameters { | 1123 | struct Parameters { |
| 1071 | u32 npad_id; | 1124 | Core::HID::NpadIdType npad_id; |
| 1072 | INSERT_PADDING_WORDS_NOINIT(1); | 1125 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1073 | u64 applet_resource_user_id; | 1126 | u64 applet_resource_user_id; |
| 1074 | }; | 1127 | }; |
| 1128 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1075 | 1129 | ||
| 1076 | const auto parameters{rp.PopRaw<Parameters>()}; | 1130 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1077 | 1131 | ||
| @@ -1089,9 +1143,10 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c | |||
| 1089 | struct Parameters { | 1143 | struct Parameters { |
| 1090 | bool unintended_home_button_input_protection; | 1144 | bool unintended_home_button_input_protection; |
| 1091 | INSERT_PADDING_BYTES_NOINIT(3); | 1145 | INSERT_PADDING_BYTES_NOINIT(3); |
| 1092 | u32 npad_id; | 1146 | Core::HID::NpadIdType npad_id; |
| 1093 | u64 applet_resource_user_id; | 1147 | u64 applet_resource_user_id; |
| 1094 | }; | 1148 | }; |
| 1149 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1095 | 1150 | ||
| 1096 | const auto parameters{rp.PopRaw<Parameters>()}; | 1151 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1097 | 1152 | ||
| @@ -1113,6 +1168,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { | |||
| 1113 | IPC::RequestParser rp{ctx}; | 1168 | IPC::RequestParser rp{ctx}; |
| 1114 | struct Parameters { | 1169 | struct Parameters { |
| 1115 | bool analog_stick_use_center_clamp; | 1170 | bool analog_stick_use_center_clamp; |
| 1171 | INSERT_PADDING_BYTES_NOINIT(7); | ||
| 1116 | u64 applet_resource_user_id; | 1172 | u64 applet_resource_user_id; |
| 1117 | }; | 1173 | }; |
| 1118 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | 1174 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); |
| @@ -1130,40 +1186,71 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { | |||
| 1130 | rb.Push(ResultSuccess); | 1186 | rb.Push(ResultSuccess); |
| 1131 | } | 1187 | } |
| 1132 | 1188 | ||
| 1189 | void Hid::SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) { | ||
| 1190 | IPC::RequestParser rp{ctx}; | ||
| 1191 | struct Parameters { | ||
| 1192 | Core::HID::NpadStyleSet npad_styleset; | ||
| 1193 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 1194 | u64 applet_resource_user_id; | ||
| 1195 | Core::HID::NpadButton button; | ||
| 1196 | }; | ||
| 1197 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 1198 | |||
| 1199 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1200 | |||
| 1201 | LOG_WARNING(Service_HID, | ||
| 1202 | "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}", | ||
| 1203 | parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button); | ||
| 1204 | |||
| 1205 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1206 | rb.Push(ResultSuccess); | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) { | ||
| 1210 | IPC::RequestParser rp{ctx}; | ||
| 1211 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1212 | |||
| 1213 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 1214 | applet_resource_user_id); | ||
| 1215 | |||
| 1216 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1217 | rb.Push(ResultSuccess); | ||
| 1218 | } | ||
| 1219 | |||
| 1133 | void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 1220 | void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 1134 | IPC::RequestParser rp{ctx}; | 1221 | IPC::RequestParser rp{ctx}; |
| 1135 | const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; | 1222 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; |
| 1136 | 1223 | ||
| 1137 | VibrationDeviceInfo vibration_device_info; | 1224 | Core::HID::VibrationDeviceInfo vibration_device_info; |
| 1138 | 1225 | ||
| 1139 | switch (vibration_device_handle.npad_type) { | 1226 | switch (vibration_device_handle.npad_type) { |
| 1140 | case Controller_NPad::NpadType::ProController: | 1227 | case Core::HID::NpadStyleIndex::ProController: |
| 1141 | case Controller_NPad::NpadType::Handheld: | 1228 | case Core::HID::NpadStyleIndex::Handheld: |
| 1142 | case Controller_NPad::NpadType::JoyconDual: | 1229 | case Core::HID::NpadStyleIndex::JoyconDual: |
| 1143 | case Controller_NPad::NpadType::JoyconLeft: | 1230 | case Core::HID::NpadStyleIndex::JoyconLeft: |
| 1144 | case Controller_NPad::NpadType::JoyconRight: | 1231 | case Core::HID::NpadStyleIndex::JoyconRight: |
| 1145 | default: | 1232 | default: |
| 1146 | vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; | 1233 | vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; |
| 1147 | break; | 1234 | break; |
| 1148 | case Controller_NPad::NpadType::GameCube: | 1235 | case Core::HID::NpadStyleIndex::GameCube: |
| 1149 | vibration_device_info.type = VibrationDeviceType::GcErm; | 1236 | vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; |
| 1150 | break; | 1237 | break; |
| 1151 | case Controller_NPad::NpadType::Pokeball: | 1238 | case Core::HID::NpadStyleIndex::Pokeball: |
| 1152 | vibration_device_info.type = VibrationDeviceType::Unknown; | 1239 | vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; |
| 1153 | break; | 1240 | break; |
| 1154 | } | 1241 | } |
| 1155 | 1242 | ||
| 1156 | switch (vibration_device_handle.device_index) { | 1243 | switch (vibration_device_handle.device_index) { |
| 1157 | case Controller_NPad::DeviceIndex::Left: | 1244 | case Core::HID::DeviceIndex::Left: |
| 1158 | vibration_device_info.position = VibrationDevicePosition::Left; | 1245 | vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; |
| 1159 | break; | 1246 | break; |
| 1160 | case Controller_NPad::DeviceIndex::Right: | 1247 | case Core::HID::DeviceIndex::Right: |
| 1161 | vibration_device_info.position = VibrationDevicePosition::Right; | 1248 | vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; |
| 1162 | break; | 1249 | break; |
| 1163 | case Controller_NPad::DeviceIndex::None: | 1250 | case Core::HID::DeviceIndex::None: |
| 1164 | default: | 1251 | default: |
| 1165 | UNREACHABLE_MSG("DeviceIndex should never be None!"); | 1252 | UNREACHABLE_MSG("DeviceIndex should never be None!"); |
| 1166 | vibration_device_info.position = VibrationDevicePosition::None; | 1253 | vibration_device_info.position = Core::HID::VibrationDevicePosition::None; |
| 1167 | break; | 1254 | break; |
| 1168 | } | 1255 | } |
| 1169 | 1256 | ||
| @@ -1178,11 +1265,12 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | |||
| 1178 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | 1265 | void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 1179 | IPC::RequestParser rp{ctx}; | 1266 | IPC::RequestParser rp{ctx}; |
| 1180 | struct Parameters { | 1267 | struct Parameters { |
| 1181 | Controller_NPad::DeviceHandle vibration_device_handle; | 1268 | Core::HID::VibrationDeviceHandle vibration_device_handle; |
| 1182 | Controller_NPad::VibrationValue vibration_value; | 1269 | Core::HID::VibrationValue vibration_value; |
| 1183 | INSERT_PADDING_WORDS_NOINIT(1); | 1270 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1184 | u64 applet_resource_user_id; | 1271 | u64 applet_resource_user_id; |
| 1185 | }; | 1272 | }; |
| 1273 | static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); | ||
| 1186 | 1274 | ||
| 1187 | const auto parameters{rp.PopRaw<Parameters>()}; | 1275 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1188 | 1276 | ||
| @@ -1202,10 +1290,11 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { | |||
| 1202 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 1290 | void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 1203 | IPC::RequestParser rp{ctx}; | 1291 | IPC::RequestParser rp{ctx}; |
| 1204 | struct Parameters { | 1292 | struct Parameters { |
| 1205 | Controller_NPad::DeviceHandle vibration_device_handle; | 1293 | Core::HID::VibrationDeviceHandle vibration_device_handle; |
| 1206 | INSERT_PADDING_WORDS_NOINIT(1); | 1294 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1207 | u64 applet_resource_user_id; | 1295 | u64 applet_resource_user_id; |
| 1208 | }; | 1296 | }; |
| 1297 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1209 | 1298 | ||
| 1210 | const auto parameters{rp.PopRaw<Parameters>()}; | 1299 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1211 | 1300 | ||
| @@ -1256,10 +1345,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | |||
| 1256 | const auto handles = ctx.ReadBuffer(0); | 1345 | const auto handles = ctx.ReadBuffer(0); |
| 1257 | const auto vibrations = ctx.ReadBuffer(1); | 1346 | const auto vibrations = ctx.ReadBuffer(1); |
| 1258 | 1347 | ||
| 1259 | std::vector<Controller_NPad::DeviceHandle> vibration_device_handles( | 1348 | std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles( |
| 1260 | handles.size() / sizeof(Controller_NPad::DeviceHandle)); | 1349 | handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); |
| 1261 | std::vector<Controller_NPad::VibrationValue> vibration_values( | 1350 | std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() / |
| 1262 | vibrations.size() / sizeof(Controller_NPad::VibrationValue)); | 1351 | sizeof(Core::HID::VibrationValue)); |
| 1263 | 1352 | ||
| 1264 | std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); | 1353 | std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); |
| 1265 | std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); | 1354 | std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); |
| @@ -1276,9 +1365,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { | |||
| 1276 | void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | 1365 | void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { |
| 1277 | IPC::RequestParser rp{ctx}; | 1366 | IPC::RequestParser rp{ctx}; |
| 1278 | struct Parameters { | 1367 | struct Parameters { |
| 1279 | Controller_NPad::DeviceHandle vibration_device_handle; | 1368 | Core::HID::VibrationDeviceHandle vibration_device_handle; |
| 1369 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 1280 | u64 applet_resource_user_id; | 1370 | u64 applet_resource_user_id; |
| 1281 | VibrationGcErmCommand gc_erm_command; | 1371 | Core::HID::VibrationGcErmCommand gc_erm_command; |
| 1282 | }; | 1372 | }; |
| 1283 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | 1373 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); |
| 1284 | 1374 | ||
| @@ -1292,26 +1382,26 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | |||
| 1292 | */ | 1382 | */ |
| 1293 | const auto vibration_value = [parameters] { | 1383 | const auto vibration_value = [parameters] { |
| 1294 | switch (parameters.gc_erm_command) { | 1384 | switch (parameters.gc_erm_command) { |
| 1295 | case VibrationGcErmCommand::Stop: | 1385 | case Core::HID::VibrationGcErmCommand::Stop: |
| 1296 | return Controller_NPad::VibrationValue{ | 1386 | return Core::HID::VibrationValue{ |
| 1297 | .amp_low = 0.0f, | 1387 | .low_amplitude = 0.0f, |
| 1298 | .freq_low = 160.0f, | 1388 | .low_frequency = 160.0f, |
| 1299 | .amp_high = 0.0f, | 1389 | .high_amplitude = 0.0f, |
| 1300 | .freq_high = 320.0f, | 1390 | .high_frequency = 320.0f, |
| 1301 | }; | 1391 | }; |
| 1302 | case VibrationGcErmCommand::Start: | 1392 | case Core::HID::VibrationGcErmCommand::Start: |
| 1303 | return Controller_NPad::VibrationValue{ | 1393 | return Core::HID::VibrationValue{ |
| 1304 | .amp_low = 1.0f, | 1394 | .low_amplitude = 1.0f, |
| 1305 | .freq_low = 160.0f, | 1395 | .low_frequency = 160.0f, |
| 1306 | .amp_high = 1.0f, | 1396 | .high_amplitude = 1.0f, |
| 1307 | .freq_high = 320.0f, | 1397 | .high_frequency = 320.0f, |
| 1308 | }; | 1398 | }; |
| 1309 | case VibrationGcErmCommand::StopHard: | 1399 | case Core::HID::VibrationGcErmCommand::StopHard: |
| 1310 | return Controller_NPad::VibrationValue{ | 1400 | return Core::HID::VibrationValue{ |
| 1311 | .amp_low = 0.0f, | 1401 | .low_amplitude = 0.0f, |
| 1312 | .freq_low = 0.0f, | 1402 | .low_frequency = 0.0f, |
| 1313 | .amp_high = 0.0f, | 1403 | .high_amplitude = 0.0f, |
| 1314 | .freq_high = 0.0f, | 1404 | .high_frequency = 0.0f, |
| 1315 | }; | 1405 | }; |
| 1316 | default: | 1406 | default: |
| 1317 | return Controller_NPad::DEFAULT_VIBRATION_VALUE; | 1407 | return Controller_NPad::DEFAULT_VIBRATION_VALUE; |
| @@ -1336,7 +1426,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | |||
| 1336 | void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | 1426 | void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { |
| 1337 | IPC::RequestParser rp{ctx}; | 1427 | IPC::RequestParser rp{ctx}; |
| 1338 | struct Parameters { | 1428 | struct Parameters { |
| 1339 | Controller_NPad::DeviceHandle vibration_device_handle; | 1429 | Core::HID::VibrationDeviceHandle vibration_device_handle; |
| 1340 | INSERT_PADDING_WORDS_NOINIT(1); | 1430 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1341 | u64 applet_resource_user_id; | 1431 | u64 applet_resource_user_id; |
| 1342 | }; | 1432 | }; |
| @@ -1347,8 +1437,8 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | |||
| 1347 | .GetLastVibration(parameters.vibration_device_handle); | 1437 | .GetLastVibration(parameters.vibration_device_handle); |
| 1348 | 1438 | ||
| 1349 | const auto gc_erm_command = [last_vibration] { | 1439 | const auto gc_erm_command = [last_vibration] { |
| 1350 | if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { | 1440 | if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { |
| 1351 | return VibrationGcErmCommand::Start; | 1441 | return Core::HID::VibrationGcErmCommand::Start; |
| 1352 | } | 1442 | } |
| 1353 | 1443 | ||
| 1354 | /** | 1444 | /** |
| @@ -1357,11 +1447,11 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { | |||
| 1357 | * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. | 1447 | * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. |
| 1358 | * This is done to reuse the controller vibration functions made for regular controllers. | 1448 | * This is done to reuse the controller vibration functions made for regular controllers. |
| 1359 | */ | 1449 | */ |
| 1360 | if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { | 1450 | if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { |
| 1361 | return VibrationGcErmCommand::StopHard; | 1451 | return Core::HID::VibrationGcErmCommand::StopHard; |
| 1362 | } | 1452 | } |
| 1363 | 1453 | ||
| 1364 | return VibrationGcErmCommand::Stop; | 1454 | return Core::HID::VibrationGcErmCommand::Stop; |
| 1365 | }(); | 1455 | }(); |
| 1366 | 1456 | ||
| 1367 | LOG_DEBUG(Service_HID, | 1457 | LOG_DEBUG(Service_HID, |
| @@ -1401,10 +1491,11 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | |||
| 1401 | void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { | 1491 | void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { |
| 1402 | IPC::RequestParser rp{ctx}; | 1492 | IPC::RequestParser rp{ctx}; |
| 1403 | struct Parameters { | 1493 | struct Parameters { |
| 1404 | Controller_NPad::DeviceHandle vibration_device_handle; | 1494 | Core::HID::VibrationDeviceHandle vibration_device_handle; |
| 1405 | INSERT_PADDING_WORDS_NOINIT(1); | 1495 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1406 | u64 applet_resource_user_id; | 1496 | u64 applet_resource_user_id; |
| 1407 | }; | 1497 | }; |
| 1498 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1408 | 1499 | ||
| 1409 | const auto parameters{rp.PopRaw<Parameters>()}; | 1500 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1410 | 1501 | ||
| @@ -1435,18 +1526,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 1435 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1526 | void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 1436 | IPC::RequestParser rp{ctx}; | 1527 | IPC::RequestParser rp{ctx}; |
| 1437 | struct Parameters { | 1528 | struct Parameters { |
| 1438 | Controller_NPad::DeviceHandle sixaxis_handle; | 1529 | Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; |
| 1439 | INSERT_PADDING_WORDS_NOINIT(1); | 1530 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1440 | u64 applet_resource_user_id; | 1531 | u64 applet_resource_user_id; |
| 1441 | }; | 1532 | }; |
| 1533 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1442 | 1534 | ||
| 1443 | const auto parameters{rp.PopRaw<Parameters>()}; | 1535 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1444 | 1536 | ||
| 1445 | LOG_WARNING( | 1537 | LOG_WARNING(Service_HID, |
| 1446 | Service_HID, | 1538 | "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", |
| 1447 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 1539 | parameters.console_sixaxis_handle.unknown_1, |
| 1448 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | 1540 | parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); |
| 1449 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 1450 | 1541 | ||
| 1451 | IPC::ResponseBuilder rb{ctx, 2}; | 1542 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1452 | rb.Push(ResultSuccess); | 1543 | rb.Push(ResultSuccess); |
| @@ -1455,18 +1546,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 1455 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 1546 | void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 1456 | IPC::RequestParser rp{ctx}; | 1547 | IPC::RequestParser rp{ctx}; |
| 1457 | struct Parameters { | 1548 | struct Parameters { |
| 1458 | Controller_NPad::DeviceHandle sixaxis_handle; | 1549 | Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; |
| 1459 | INSERT_PADDING_WORDS_NOINIT(1); | 1550 | INSERT_PADDING_WORDS_NOINIT(1); |
| 1460 | u64 applet_resource_user_id; | 1551 | u64 applet_resource_user_id; |
| 1461 | }; | 1552 | }; |
| 1553 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 1462 | 1554 | ||
| 1463 | const auto parameters{rp.PopRaw<Parameters>()}; | 1555 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1464 | 1556 | ||
| 1465 | LOG_WARNING( | 1557 | LOG_WARNING(Service_HID, |
| 1466 | Service_HID, | 1558 | "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", |
| 1467 | "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 1559 | parameters.console_sixaxis_handle.unknown_1, |
| 1468 | parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, | 1560 | parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); |
| 1469 | parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); | ||
| 1470 | 1561 | ||
| 1471 | IPC::ResponseBuilder rb{ctx, 2}; | 1562 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1472 | rb.Push(ResultSuccess); | 1563 | rb.Push(ResultSuccess); |
| @@ -1620,10 +1711,8 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { | |||
| 1620 | 1711 | ||
| 1621 | void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { | 1712 | void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { |
| 1622 | IPC::RequestParser rp{ctx}; | 1713 | IPC::RequestParser rp{ctx}; |
| 1623 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 1624 | 1714 | ||
| 1625 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | 1715 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 1626 | applet_resource_user_id); | ||
| 1627 | 1716 | ||
| 1628 | IPC::ResponseBuilder rb{ctx, 4}; | 1717 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1629 | rb.Push(ResultSuccess); | 1718 | rb.Push(ResultSuccess); |
| @@ -1825,7 +1914,7 @@ public: | |||
| 1825 | {317, nullptr, "GetNpadLeftRightInterfaceType"}, | 1914 | {317, nullptr, "GetNpadLeftRightInterfaceType"}, |
| 1826 | {318, nullptr, "HasBattery"}, | 1915 | {318, nullptr, "HasBattery"}, |
| 1827 | {319, nullptr, "HasLeftRightBattery"}, | 1916 | {319, nullptr, "HasLeftRightBattery"}, |
| 1828 | {321, nullptr, "GetUniquePadsFromNpad"}, | 1917 | {321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, |
| 1829 | {322, nullptr, "GetIrSensorState"}, | 1918 | {322, nullptr, "GetIrSensorState"}, |
| 1830 | {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, | 1919 | {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, |
| 1831 | {324, nullptr, "GetUniquePadButtonSet"}, | 1920 | {324, nullptr, "GetUniquePadButtonSet"}, |
| @@ -1996,6 +2085,18 @@ private: | |||
| 1996 | IPC::ResponseBuilder rb{ctx, 2}; | 2085 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1997 | rb.Push(ResultSuccess); | 2086 | rb.Push(ResultSuccess); |
| 1998 | } | 2087 | } |
| 2088 | |||
| 2089 | void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) { | ||
| 2090 | IPC::RequestParser rp{ctx}; | ||
| 2091 | const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()}; | ||
| 2092 | |||
| 2093 | const s64 total_entries = 0; | ||
| 2094 | LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type); | ||
| 2095 | |||
| 2096 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 2097 | rb.Push(ResultSuccess); | ||
| 2098 | rb.Push(total_entries); | ||
| 2099 | } | ||
| 1999 | }; | 2100 | }; |
| 2000 | 2101 | ||
| 2001 | class HidTmp final : public ServiceFramework<HidTmp> { | 2102 | class HidTmp final : public ServiceFramework<HidTmp> { |
| @@ -2037,10 +2138,6 @@ public: | |||
| 2037 | } | 2138 | } |
| 2038 | }; | 2139 | }; |
| 2039 | 2140 | ||
| 2040 | void ReloadInputDevices() { | ||
| 2041 | Settings::values.is_device_reload_pending.store(true); | ||
| 2042 | } | ||
| 2043 | |||
| 2044 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { | 2141 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 2045 | std::make_shared<Hid>(system)->InstallAsService(service_manager); | 2142 | std::make_shared<Hid>(system)->InstallAsService(service_manager); |
| 2046 | std::make_shared<HidBus>(system)->InstallAsService(service_manager); | 2143 | std::make_shared<HidBus>(system)->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index b1fe75e94..d290df161 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -60,21 +60,23 @@ public: | |||
| 60 | private: | 60 | private: |
| 61 | template <typename T> | 61 | template <typename T> |
| 62 | void MakeController(HidController controller) { | 62 | void MakeController(HidController controller) { |
| 63 | controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); | 63 | controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); |
| 64 | } | 64 | } |
| 65 | template <typename T> | 65 | template <typename T> |
| 66 | void MakeControllerWithServiceContext(HidController controller) { | 66 | void MakeControllerWithServiceContext(HidController controller) { |
| 67 | controllers[static_cast<std::size_t>(controller)] = | 67 | controllers[static_cast<std::size_t>(controller)] = |
| 68 | std::make_unique<T>(system, service_context); | 68 | std::make_unique<T>(system.HIDCore(), service_context); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 71 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| 72 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 72 | void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 73 | void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | ||
| 73 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); | 74 | void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); |
| 74 | 75 | ||
| 75 | KernelHelpers::ServiceContext& service_context; | 76 | KernelHelpers::ServiceContext& service_context; |
| 76 | 77 | ||
| 77 | std::shared_ptr<Core::Timing::EventType> pad_update_event; | 78 | std::shared_ptr<Core::Timing::EventType> pad_update_event; |
| 79 | std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; | ||
| 78 | std::shared_ptr<Core::Timing::EventType> motion_update_event; | 80 | std::shared_ptr<Core::Timing::EventType> motion_update_event; |
| 79 | 81 | ||
| 80 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> | 82 | std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> |
| @@ -134,6 +136,8 @@ private: | |||
| 134 | void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); | 136 | void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); |
| 135 | void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); | 137 | void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); |
| 136 | void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx); | 138 | void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx); |
| 139 | void SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); | ||
| 140 | void ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx); | ||
| 137 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); | 141 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx); |
| 138 | void SendVibrationValue(Kernel::HLERequestContext& ctx); | 142 | void SendVibrationValue(Kernel::HLERequestContext& ctx); |
| 139 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx); | 143 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx); |
| @@ -161,38 +165,11 @@ private: | |||
| 161 | void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); | 165 | void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); |
| 162 | void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); | 166 | void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); |
| 163 | 167 | ||
| 164 | enum class VibrationDeviceType : u32 { | ||
| 165 | Unknown = 0, | ||
| 166 | LinearResonantActuator = 1, | ||
| 167 | GcErm = 2, | ||
| 168 | }; | ||
| 169 | |||
| 170 | enum class VibrationDevicePosition : u32 { | ||
| 171 | None = 0, | ||
| 172 | Left = 1, | ||
| 173 | Right = 2, | ||
| 174 | }; | ||
| 175 | |||
| 176 | enum class VibrationGcErmCommand : u64 { | ||
| 177 | Stop = 0, | ||
| 178 | Start = 1, | ||
| 179 | StopHard = 2, | ||
| 180 | }; | ||
| 181 | |||
| 182 | struct VibrationDeviceInfo { | ||
| 183 | VibrationDeviceType type{}; | ||
| 184 | VibrationDevicePosition position{}; | ||
| 185 | }; | ||
| 186 | static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); | ||
| 187 | |||
| 188 | std::shared_ptr<IAppletResource> applet_resource; | 168 | std::shared_ptr<IAppletResource> applet_resource; |
| 189 | 169 | ||
| 190 | KernelHelpers::ServiceContext service_context; | 170 | KernelHelpers::ServiceContext service_context; |
| 191 | }; | 171 | }; |
| 192 | 172 | ||
| 193 | /// Reload input devices. Used when input configuration changed | ||
| 194 | void ReloadInputDevices(); | ||
| 195 | |||
| 196 | /// Registers all HID services with the specified service manager. | 173 | /// Registers all HID services with the specified service manager. |
| 197 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); | 174 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 198 | 175 | ||
diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h new file mode 100644 index 000000000..44c20d967 --- /dev/null +++ b/src/core/hle/service/hid/ring_lifo.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Service::HID { | ||
| 12 | |||
| 13 | template <typename State> | ||
| 14 | struct AtomicStorage { | ||
| 15 | s64 sampling_number; | ||
| 16 | State state; | ||
| 17 | }; | ||
| 18 | |||
| 19 | template <typename State, std::size_t max_buffer_size> | ||
| 20 | struct Lifo { | ||
| 21 | s64 timestamp{}; | ||
| 22 | s64 total_buffer_count = static_cast<s64>(max_buffer_size); | ||
| 23 | s64 buffer_tail{}; | ||
| 24 | s64 buffer_count{}; | ||
| 25 | std::array<AtomicStorage<State>, max_buffer_size> entries{}; | ||
| 26 | |||
| 27 | const AtomicStorage<State>& ReadCurrentEntry() const { | ||
| 28 | return entries[buffer_tail]; | ||
| 29 | } | ||
| 30 | |||
| 31 | const AtomicStorage<State>& ReadPreviousEntry() const { | ||
| 32 | return entries[GetPreviousEntryIndex()]; | ||
| 33 | } | ||
| 34 | |||
| 35 | std::size_t GetPreviousEntryIndex() const { | ||
| 36 | return static_cast<size_t>((buffer_tail + total_buffer_count - 1) % total_buffer_count); | ||
| 37 | } | ||
| 38 | |||
| 39 | std::size_t GetNextEntryIndex() const { | ||
| 40 | return static_cast<size_t>((buffer_tail + 1) % total_buffer_count); | ||
| 41 | } | ||
| 42 | |||
| 43 | void WriteNextEntry(const State& new_state) { | ||
| 44 | if (buffer_count < total_buffer_count - 1) { | ||
| 45 | buffer_count++; | ||
| 46 | } | ||
| 47 | buffer_tail = GetNextEntryIndex(); | ||
| 48 | const auto& previous_entry = ReadPreviousEntry(); | ||
| 49 | entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1; | ||
| 50 | entries[buffer_tail].state = new_state; | ||
| 51 | } | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace Service::HID | ||
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 32eff3b2a..3782703d2 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -396,12 +396,12 @@ public: | |||
| 396 | CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, | 396 | CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, |
| 397 | nro_header.segment_headers[DATA_INDEX].memory_size); | 397 | nro_header.segment_headers[DATA_INDEX].memory_size); |
| 398 | 398 | ||
| 399 | CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( | 399 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |
| 400 | text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); | 400 | text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); |
| 401 | CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start, | 401 | CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( |
| 402 | Kernel::KMemoryPermission::Read)); | 402 | ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); |
| 403 | 403 | ||
| 404 | return process->PageTable().SetCodeMemoryPermission( | 404 | return process->PageTable().SetProcessMemoryPermission( |
| 405 | data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); | 405 | data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); |
| 406 | } | 406 | } |
| 407 | 407 | ||
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 64ffc8572..382ddcae5 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "core/hle/service/ns/errors.h" | 12 | #include "core/hle/service/ns/errors.h" |
| 13 | #include "core/hle/service/ns/language.h" | 13 | #include "core/hle/service/ns/language.h" |
| 14 | #include "core/hle/service/ns/ns.h" | 14 | #include "core/hle/service/ns/ns.h" |
| 15 | #include "core/hle/service/ns/pdm_qry.h" | ||
| 15 | #include "core/hle/service/ns/pl_u.h" | 16 | #include "core/hle/service/ns/pl_u.h" |
| 16 | #include "core/hle/service/set/set.h" | 17 | #include "core/hle/service/set/set.h" |
| 17 | 18 | ||
| @@ -570,11 +571,29 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_) | |||
| 570 | 571 | ||
| 571 | IFactoryResetInterface::~IFactoryResetInterface() = default; | 572 | IFactoryResetInterface::~IFactoryResetInterface() = default; |
| 572 | 573 | ||
| 574 | IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( | ||
| 575 | Core::System& system_) | ||
| 576 | : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { | ||
| 577 | // clang-format off | ||
| 578 | static const FunctionInfo functions[] = { | ||
| 579 | {0, nullptr, "GetApplicationControlData"}, | ||
| 580 | {1, nullptr, "GetApplicationDesiredLanguage"}, | ||
| 581 | {2, nullptr, "ConvertApplicationLanguageToLanguageCode"}, | ||
| 582 | {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"}, | ||
| 583 | {4, nullptr, "SelectApplicationDesiredLanguage"}, | ||
| 584 | }; | ||
| 585 | // clang-format on | ||
| 586 | |||
| 587 | RegisterHandlers(functions); | ||
| 588 | } | ||
| 589 | |||
| 590 | IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default; | ||
| 591 | |||
| 573 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { | 592 | NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} { |
| 574 | // clang-format off | 593 | // clang-format off |
| 575 | static const FunctionInfo functions[] = { | 594 | static const FunctionInfo functions[] = { |
| 576 | {7988, nullptr, "GetDynamicRightsInterface"}, | 595 | {7988, nullptr, "GetDynamicRightsInterface"}, |
| 577 | {7989, nullptr, "GetReadOnlyApplicationControlDataInterface"}, | 596 | {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, |
| 578 | {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, | 597 | {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, |
| 579 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, | 598 | {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, |
| 580 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, | 599 | {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, |
| @@ -738,6 +757,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system | |||
| 738 | std::make_shared<NS_SU>(system)->InstallAsService(service_manager); | 757 | std::make_shared<NS_SU>(system)->InstallAsService(service_manager); |
| 739 | std::make_shared<NS_VM>(system)->InstallAsService(service_manager); | 758 | std::make_shared<NS_VM>(system)->InstallAsService(service_manager); |
| 740 | 759 | ||
| 760 | std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager); | ||
| 761 | |||
| 741 | std::make_shared<PL_U>(system)->InstallAsService(service_manager); | 762 | std::make_shared<PL_U>(system)->InstallAsService(service_manager); |
| 742 | } | 763 | } |
| 743 | 764 | ||
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h index 218eec3ec..43540b0fb 100644 --- a/src/core/hle/service/ns/ns.h +++ b/src/core/hle/service/ns/ns.h | |||
| @@ -74,6 +74,13 @@ public: | |||
| 74 | ~IFactoryResetInterface() override; | 74 | ~IFactoryResetInterface() override; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | class IReadOnlyApplicationControlDataInterface final | ||
| 78 | : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { | ||
| 79 | public: | ||
| 80 | explicit IReadOnlyApplicationControlDataInterface(Core::System& system_); | ||
| 81 | ~IReadOnlyApplicationControlDataInterface() override; | ||
| 82 | }; | ||
| 83 | |||
| 77 | class NS final : public ServiceFramework<NS> { | 84 | class NS final : public ServiceFramework<NS> { |
| 78 | public: | 85 | public: |
| 79 | explicit NS(const char* name, Core::System& system_); | 86 | explicit NS(const char* name, Core::System& system_); |
diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp new file mode 100644 index 000000000..e2fab5c3f --- /dev/null +++ b/src/core/hle/service/ns/pdm_qry.cpp | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | |||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "common/uuid.h" | ||
| 9 | #include "core/hle/ipc_helpers.h" | ||
| 10 | #include "core/hle/service/ns/pdm_qry.h" | ||
| 11 | #include "core/hle/service/service.h" | ||
| 12 | #include "core/hle/service/sm/sm.h" | ||
| 13 | |||
| 14 | namespace Service::NS { | ||
| 15 | |||
| 16 | PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} { | ||
| 17 | // clang-format off | ||
| 18 | static const FunctionInfo functions[] = { | ||
| 19 | {0, nullptr, "QueryAppletEvent"}, | ||
| 20 | {1, nullptr, "QueryPlayStatistics"}, | ||
| 21 | {2, nullptr, "QueryPlayStatisticsByUserAccountId"}, | ||
| 22 | {3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"}, | ||
| 23 | {4, nullptr, "QueryPlayStatisticsByApplicationId"}, | ||
| 24 | {5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"}, | ||
| 25 | {6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"}, | ||
| 26 | {7, nullptr, "QueryLastPlayTimeV0"}, | ||
| 27 | {8, nullptr, "QueryPlayEvent"}, | ||
| 28 | {9, nullptr, "GetAvailablePlayEventRange"}, | ||
| 29 | {10, nullptr, "QueryAccountEvent"}, | ||
| 30 | {11, nullptr, "QueryAccountPlayEvent"}, | ||
| 31 | {12, nullptr, "GetAvailableAccountPlayEventRange"}, | ||
| 32 | {13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"}, | ||
| 33 | {14, nullptr, "QueryRecentlyPlayedApplication"}, | ||
| 34 | {15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"}, | ||
| 35 | {16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"}, | ||
| 36 | {17, nullptr, "QueryLastPlayTime"}, | ||
| 37 | {18, nullptr, "QueryApplicationPlayStatisticsForSystem"}, | ||
| 38 | {19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"}, | ||
| 39 | }; | ||
| 40 | // clang-format on | ||
| 41 | |||
| 42 | RegisterHandlers(functions); | ||
| 43 | } | ||
| 44 | |||
| 45 | PDM_QRY::~PDM_QRY() = default; | ||
| 46 | |||
| 47 | void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx) { | ||
| 48 | IPC::RequestParser rp{ctx}; | ||
| 49 | const auto unknown = rp.Pop<bool>(); | ||
| 50 | rp.Pop<u8>(); // Padding | ||
| 51 | const auto application_id = rp.Pop<u64>(); | ||
| 52 | const auto user_account_uid = rp.PopRaw<Common::UUID>(); | ||
| 53 | |||
| 54 | // TODO(German77): Read statistics of the game | ||
| 55 | PlayStatistics statistics{ | ||
| 56 | .application_id = application_id, | ||
| 57 | .total_launches = 1, | ||
| 58 | }; | ||
| 59 | |||
| 60 | LOG_WARNING(Service_NS, | ||
| 61 | "(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}", | ||
| 62 | unknown, application_id, user_account_uid.Format()); | ||
| 63 | |||
| 64 | IPC::ResponseBuilder rb{ctx, 12}; | ||
| 65 | rb.Push(ResultSuccess); | ||
| 66 | rb.PushRaw(statistics); | ||
| 67 | } | ||
| 68 | |||
| 69 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/ns/pdm_qry.h b/src/core/hle/service/ns/pdm_qry.h new file mode 100644 index 000000000..516136314 --- /dev/null +++ b/src/core/hle/service/ns/pdm_qry.h | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::NS { | ||
| 10 | |||
| 11 | struct PlayStatistics { | ||
| 12 | u64 application_id{}; | ||
| 13 | u32 first_entry_index{}; | ||
| 14 | u32 first_timestamp_user{}; | ||
| 15 | u32 first_timestamp_network{}; | ||
| 16 | u32 last_entry_index{}; | ||
| 17 | u32 last_timestamp_user{}; | ||
| 18 | u32 last_timestamp_network{}; | ||
| 19 | u32 play_time_in_minutes{}; | ||
| 20 | u32 total_launches{}; | ||
| 21 | }; | ||
| 22 | static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size"); | ||
| 23 | |||
| 24 | class PDM_QRY final : public ServiceFramework<PDM_QRY> { | ||
| 25 | public: | ||
| 26 | explicit PDM_QRY(Core::System& system_); | ||
| 27 | ~PDM_QRY() override; | ||
| 28 | |||
| 29 | private: | ||
| 30 | void QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx); | ||
| 31 | }; | ||
| 32 | |||
| 33 | } // namespace Service::NS | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 0d7d4ad03..8314d1ec2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -20,8 +20,12 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& | |||
| 20 | switch (command.group) { | 20 | switch (command.group) { |
| 21 | case 0x0: | 21 | case 0x0: |
| 22 | switch (command.cmd) { | 22 | switch (command.cmd) { |
| 23 | case 0x1: | 23 | case 0x1: { |
| 24 | return Submit(input, output); | 24 | if (!fd_to_id.contains(fd)) { |
| 25 | fd_to_id[fd] = next_id++; | ||
| 26 | } | ||
| 27 | return Submit(fd, input, output); | ||
| 28 | } | ||
| 25 | case 0x2: | 29 | case 0x2: |
| 26 | return GetSyncpoint(input, output); | 30 | return GetSyncpoint(input, output); |
| 27 | case 0x3: | 31 | case 0x3: |
| @@ -66,7 +70,10 @@ void nvhost_nvdec::OnOpen(DeviceFD fd) {} | |||
| 66 | 70 | ||
| 67 | void nvhost_nvdec::OnClose(DeviceFD fd) { | 71 | void nvhost_nvdec::OnClose(DeviceFD fd) { |
| 68 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); | 72 | LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); |
| 69 | system.GPU().ClearCdmaInstance(); | 73 | const auto iter = fd_to_id.find(fd); |
| 74 | if (iter != fd_to_id.end()) { | ||
| 75 | system.GPU().ClearCdmaInstance(iter->second); | ||
| 76 | } | ||
| 70 | } | 77 | } |
| 71 | 78 | ||
| 72 | } // namespace Service::Nvidia::Devices | 79 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h index 523d96e3a..a507c4d0a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | |||
| @@ -24,6 +24,9 @@ public: | |||
| 24 | 24 | ||
| 25 | void OnOpen(DeviceFD fd) override; | 25 | void OnOpen(DeviceFD fd) override; |
| 26 | void OnClose(DeviceFD fd) override; | 26 | void OnClose(DeviceFD fd) override; |
| 27 | |||
| 28 | private: | ||
| 29 | u32 next_id{}; | ||
| 27 | }; | 30 | }; |
| 28 | 31 | ||
| 29 | } // namespace Service::Nvidia::Devices | 32 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index e61261f98..8a05f0668 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | |||
| @@ -59,7 +59,8 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { | |||
| 59 | return NvResult::Success; | 59 | return NvResult::Success; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | 62 | NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input, |
| 63 | std::vector<u8>& output) { | ||
| 63 | IoctlSubmit params{}; | 64 | IoctlSubmit params{}; |
| 64 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | 65 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); |
| 65 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); | 66 | LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); |
| @@ -93,7 +94,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u | |||
| 93 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); | 94 | Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); |
| 94 | system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(), | 95 | system.Memory().ReadBlock(object->addr + cmd_buffer.offset, cmdlist.data(), |
| 95 | cmdlist.size() * sizeof(u32)); | 96 | cmdlist.size() * sizeof(u32)); |
| 96 | gpu.PushCommandBuffer(cmdlist); | 97 | gpu.PushCommandBuffer(fd_to_id[fd], cmdlist); |
| 97 | } | 98 | } |
| 98 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); | 99 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); |
| 99 | // Some games expect command_buffers to be written back | 100 | // Some games expect command_buffers to be written back |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 351625c17..e28c54df6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | |||
| @@ -104,13 +104,14 @@ protected: | |||
| 104 | 104 | ||
| 105 | /// Ioctl command implementations | 105 | /// Ioctl command implementations |
| 106 | NvResult SetNVMAPfd(const std::vector<u8>& input); | 106 | NvResult SetNVMAPfd(const std::vector<u8>& input); |
| 107 | NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output); | 107 | NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output); |
| 108 | NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); | 108 | NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); |
| 109 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); | 109 | NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); |
| 110 | NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 110 | NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 111 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); | 111 | NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); |
| 112 | NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); | 112 | NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); |
| 113 | 113 | ||
| 114 | std::unordered_map<DeviceFD, u32> fd_to_id{}; | ||
| 114 | s32_le nvmap_fd{}; | 115 | s32_le nvmap_fd{}; |
| 115 | u32_le submit_timeout{}; | 116 | u32_le submit_timeout{}; |
| 116 | std::shared_ptr<nvmap> nvmap_dev; | 117 | std::shared_ptr<nvmap> nvmap_dev; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index eac4dd530..76b39806f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -21,7 +21,10 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i | |||
| 21 | case 0x0: | 21 | case 0x0: |
| 22 | switch (command.cmd) { | 22 | switch (command.cmd) { |
| 23 | case 0x1: | 23 | case 0x1: |
| 24 | return Submit(input, output); | 24 | if (!fd_to_id.contains(fd)) { |
| 25 | fd_to_id[fd] = next_id++; | ||
| 26 | } | ||
| 27 | return Submit(fd, input, output); | ||
| 25 | case 0x2: | 28 | case 0x2: |
| 26 | return GetSyncpoint(input, output); | 29 | return GetSyncpoint(input, output); |
| 27 | case 0x3: | 30 | case 0x3: |
| @@ -65,7 +68,10 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i | |||
| 65 | void nvhost_vic::OnOpen(DeviceFD fd) {} | 68 | void nvhost_vic::OnOpen(DeviceFD fd) {} |
| 66 | 69 | ||
| 67 | void nvhost_vic::OnClose(DeviceFD fd) { | 70 | void nvhost_vic::OnClose(DeviceFD fd) { |
| 68 | system.GPU().ClearCdmaInstance(); | 71 | const auto iter = fd_to_id.find(fd); |
| 72 | if (iter != fd_to_id.end()) { | ||
| 73 | system.GPU().ClearCdmaInstance(iter->second); | ||
| 74 | } | ||
| 69 | } | 75 | } |
| 70 | 76 | ||
| 71 | } // namespace Service::Nvidia::Devices | 77 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h index 6d7fda9d1..c9732c037 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h | |||
| @@ -23,5 +23,8 @@ public: | |||
| 23 | 23 | ||
| 24 | void OnOpen(DeviceFD fd) override; | 24 | void OnOpen(DeviceFD fd) override; |
| 25 | void OnClose(DeviceFD fd) override; | 25 | void OnClose(DeviceFD fd) override; |
| 26 | |||
| 27 | private: | ||
| 28 | u32 next_id{}; | ||
| 26 | }; | 29 | }; |
| 27 | } // namespace Service::Nvidia::Devices | 30 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 3294bc0e7..5ab221fc1 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 1 | #pragma once | 5 | #pragma once |
| 2 | 6 | ||
| 3 | #include <array> | 7 | #include <array> |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 88fc5b5cc..277abc17a 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -13,7 +13,12 @@ namespace Service::PM { | |||
| 13 | 13 | ||
| 14 | namespace { | 14 | namespace { |
| 15 | 15 | ||
| 16 | constexpr ResultCode ERROR_PROCESS_NOT_FOUND{ErrorModule::PM, 1}; | 16 | constexpr ResultCode ResultProcessNotFound{ErrorModule::PM, 1}; |
| 17 | [[maybe_unused]] constexpr ResultCode ResultAlreadyStarted{ErrorModule::PM, 2}; | ||
| 18 | [[maybe_unused]] constexpr ResultCode ResultNotTerminated{ErrorModule::PM, 3}; | ||
| 19 | [[maybe_unused]] constexpr ResultCode ResultDebugHookInUse{ErrorModule::PM, 4}; | ||
| 20 | [[maybe_unused]] constexpr ResultCode ResultApplicationRunning{ErrorModule::PM, 5}; | ||
| 21 | [[maybe_unused]] constexpr ResultCode ResultInvalidSize{ErrorModule::PM, 6}; | ||
| 17 | 22 | ||
| 18 | constexpr u64 NO_PROCESS_FOUND_PID{0}; | 23 | constexpr u64 NO_PROCESS_FOUND_PID{0}; |
| 19 | 24 | ||
| @@ -95,18 +100,18 @@ public: | |||
| 95 | private: | 100 | private: |
| 96 | void GetProcessId(Kernel::HLERequestContext& ctx) { | 101 | void GetProcessId(Kernel::HLERequestContext& ctx) { |
| 97 | IPC::RequestParser rp{ctx}; | 102 | IPC::RequestParser rp{ctx}; |
| 98 | const auto title_id = rp.PopRaw<u64>(); | 103 | const auto program_id = rp.PopRaw<u64>(); |
| 99 | 104 | ||
| 100 | LOG_DEBUG(Service_PM, "called, title_id={:016X}", title_id); | 105 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); |
| 101 | 106 | ||
| 102 | const auto process = | 107 | const auto process = |
| 103 | SearchProcessList(kernel.GetProcessList(), [title_id](const auto& proc) { | 108 | SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { |
| 104 | return proc->GetProgramID() == title_id; | 109 | return proc->GetProgramID() == program_id; |
| 105 | }); | 110 | }); |
| 106 | 111 | ||
| 107 | if (!process.has_value()) { | 112 | if (!process.has_value()) { |
| 108 | IPC::ResponseBuilder rb{ctx, 2}; | 113 | IPC::ResponseBuilder rb{ctx, 2}; |
| 109 | rb.Push(ERROR_PROCESS_NOT_FOUND); | 114 | rb.Push(ResultProcessNotFound); |
| 110 | return; | 115 | return; |
| 111 | } | 116 | } |
| 112 | 117 | ||
| @@ -128,13 +133,16 @@ public: | |||
| 128 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) | 133 | explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) |
| 129 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | 134 | : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { |
| 130 | static const FunctionInfo functions[] = { | 135 | static const FunctionInfo functions[] = { |
| 131 | {0, &Info::GetTitleId, "GetTitleId"}, | 136 | {0, &Info::GetProgramId, "GetProgramId"}, |
| 137 | {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | ||
| 138 | {65001, nullptr, "AtmosphereHasLaunchedProgram"}, | ||
| 139 | {65002, nullptr, "AtmosphereGetProcessInfo"}, | ||
| 132 | }; | 140 | }; |
| 133 | RegisterHandlers(functions); | 141 | RegisterHandlers(functions); |
| 134 | } | 142 | } |
| 135 | 143 | ||
| 136 | private: | 144 | private: |
| 137 | void GetTitleId(Kernel::HLERequestContext& ctx) { | 145 | void GetProgramId(Kernel::HLERequestContext& ctx) { |
| 138 | IPC::RequestParser rp{ctx}; | 146 | IPC::RequestParser rp{ctx}; |
| 139 | const auto process_id = rp.PopRaw<u64>(); | 147 | const auto process_id = rp.PopRaw<u64>(); |
| 140 | 148 | ||
| @@ -146,7 +154,7 @@ private: | |||
| 146 | 154 | ||
| 147 | if (!process.has_value()) { | 155 | if (!process.has_value()) { |
| 148 | IPC::ResponseBuilder rb{ctx, 2}; | 156 | IPC::ResponseBuilder rb{ctx, 2}; |
| 149 | rb.Push(ERROR_PROCESS_NOT_FOUND); | 157 | rb.Push(ResultProcessNotFound); |
| 150 | return; | 158 | return; |
| 151 | } | 159 | } |
| 152 | 160 | ||
| @@ -155,6 +163,27 @@ private: | |||
| 155 | rb.Push((*process)->GetProgramID()); | 163 | rb.Push((*process)->GetProgramID()); |
| 156 | } | 164 | } |
| 157 | 165 | ||
| 166 | void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) { | ||
| 167 | IPC::RequestParser rp{ctx}; | ||
| 168 | const auto program_id = rp.PopRaw<u64>(); | ||
| 169 | |||
| 170 | LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||
| 171 | |||
| 172 | const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { | ||
| 173 | return proc->GetProgramID() == program_id; | ||
| 174 | }); | ||
| 175 | |||
| 176 | if (!process.has_value()) { | ||
| 177 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 178 | rb.Push(ResultProcessNotFound); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 183 | rb.Push(ResultSuccess); | ||
| 184 | rb.Push((*process)->GetProcessID()); | ||
| 185 | } | ||
| 186 | |||
| 158 | const std::vector<Kernel::KProcess*>& process_list; | 187 | const std::vector<Kernel::KProcess*>& process_list; |
| 159 | }; | 188 | }; |
| 160 | 189 | ||