diff options
Diffstat (limited to 'src/core/hle')
346 files changed, 14653 insertions, 18138 deletions
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index ef3f61321..d2b7e9a66 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -81,12 +81,12 @@ enum class KMemoryState : u32 { ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, - Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | - FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | + FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | @@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09); static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); -static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); -static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); +static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D); +static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E); static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index 58a1e7216..f08a6e448 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp @@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, } void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, - HostUnmapCallback&& host_unmap_callback) { + BlockCallback&& block_callback) { // Erase every block until we have none left. auto it = m_memory_block_tree.begin(); while (it != m_memory_block_tree.end()) { KMemoryBlock* block = std::addressof(*it); it = m_memory_block_tree.erase(it); + block_callback(block->GetAddress(), block->GetSize()); slab_manager->Free(block); - host_unmap_callback(block->GetAddress(), block->GetSize()); } ASSERT(m_memory_block_tree.empty()); diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index cb7b6f430..377628504 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h @@ -85,11 +85,11 @@ public: public: KMemoryBlockManager(); - using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; + using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; Result Initialize(KProcessAddress st, KProcessAddress nd, KMemoryBlockSlabManager* slab_manager); - void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); + void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); iterator end() { return m_memory_block_tree.end(); diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 8c1549559..1dd86fb3c 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp @@ -69,9 +69,14 @@ public: }; template <typename AddressType> -void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size) { +void InvalidateInstructionCache(KernelCore& kernel, KPageTableBase* table, AddressType addr, + u64 size) { // TODO: lock the process list for (auto& process : kernel.GetProcessList()) { + if (std::addressof(process->GetPageTable().GetBasePageTable()) != table) { + continue; + } + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { auto* interface = process->GetArmInterface(i); if (interface) { @@ -431,15 +436,43 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool m_memory_block_slab_manager)); } +Result KPageTableBase::FinalizeProcess() { + // Only process tables should be finalized. + ASSERT(!this->IsKernel()); + + // NOTE: Here Nintendo calls an unknown OnFinalize function. + // this->OnFinalize(); + + // NOTE: Here Nintendo calls a second unknown OnFinalize function. + // this->OnFinalize2(); + + // NOTE: Here Nintendo does a page table walk to discover heap pages to free. + // We will use the block manager finalization below to free them. + + R_SUCCEED(); +} + void KPageTableBase::Finalize() { - auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { - if (Settings::IsFastmemEnabled()) { + this->FinalizeProcess(); + + auto BlockCallback = [&](KProcessAddress addr, u64 size) { + if (m_impl->fastmem_arena) { m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); } + + // Get physical pages. + KPageGroup pg(m_kernel, m_block_info_manager); + this->MakePageGroup(pg, addr, size / PageSize); + + // Free the pages. + pg.CloseAndReset(); }; // Finalize memory blocks. - m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); + { + KScopedLightLock lk(m_general_lock); + m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback)); + } // Free any unsafe mapped memory. if (m_mapped_unsafe_physical_memory) { @@ -486,8 +519,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const { case Svc::MemoryState::Shared: case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCodeData: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: @@ -522,8 +555,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const { case Svc::MemoryState::Shared: case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCodeData: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: @@ -564,8 +597,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::Stack: case Svc::MemoryState::ThreadLocal: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: @@ -1274,7 +1307,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr bool reprotected_pages = false; SCOPE_EXIT({ if (reprotected_pages && any_code_pages) { - InvalidateInstructionCache(m_kernel, dst_address, size); + InvalidateInstructionCache(m_kernel, this, dst_address, size); } }); @@ -2008,7 +2041,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s for (const auto& block : pg) { StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize()); } - InvalidateInstructionCache(m_kernel, addr, size); + InvalidateInstructionCache(m_kernel, this, addr, size); } R_SUCCEED(); @@ -3249,7 +3282,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd R_TRY(PerformCopy()); // Invalidate the instruction cache, as this svc allows modifying executable pages. - InvalidateInstructionCache(m_kernel, dst_address, size); + InvalidateInstructionCache(m_kernel, this, dst_address, size); R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_page_table_base.h b/src/core/hle/kernel/k_page_table_base.h index 077cafc96..748419f86 100644 --- a/src/core/hle/kernel/k_page_table_base.h +++ b/src/core/hle/kernel/k_page_table_base.h @@ -241,6 +241,7 @@ public: KResourceLimit* resource_limit, Core::Memory::Memory& memory, KProcessAddress aslr_space_start); + Result FinalizeProcess(); void Finalize(); bool IsKernel() const { diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 068e71dff..0b08e877e 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -5,6 +5,7 @@ #include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" +#include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_shared_memory.h" @@ -171,6 +172,12 @@ void KProcess::Finalize() { m_resource_limit->Close(); } + // Clear expensive resources, as the destructor is not called for guest objects. + for (auto& interface : m_arm_interfaces) { + interface.reset(); + } + m_exclusive_monitor.reset(); + // Perform inherited finalization. KSynchronizationObject::Finalize(); } @@ -314,7 +321,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa // Ensure our memory is initialized. m_memory.SetCurrentPageTable(*this); - m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); + m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager()); // Ensure we can insert the code region. R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, @@ -411,7 +418,7 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, // Ensure our memory is initialized. m_memory.SetCurrentPageTable(*this); - m_memory.SetGPUDirtyManagers(m_dirty_memory_managers); + m_memory.SetGPUDirtyManagers(m_kernel.System().GetGPUDirtyMemoryManager()); // Ensure we can insert the code region. R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), @@ -1135,8 +1142,7 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {} KProcess::KProcess(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, - m_handle_table{kernel}, m_dirty_memory_managers{}, - m_exclusive_monitor{}, m_memory{kernel.System()} {} + m_handle_table{kernel}, m_exclusive_monitor{}, m_memory{kernel.System()} {} KProcess::~KProcess() = default; Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, @@ -1233,10 +1239,10 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); #ifdef HAS_NCE - if (this->IsApplication() && Settings::IsNceEnabled()) { + const auto& patch = code_set.PatchSegment(); + if (this->IsApplication() && Settings::IsNceEnabled() && patch.size != 0) { auto& buffer = m_kernel.System().DeviceMemory().buffer; const auto& code = code_set.CodeSegment(); - const auto& patch = code_set.PatchSegment(); buffer.Protect(GetInteger(base_addr + code.addr), code.size, Common::MemoryPermission::Read | Common::MemoryPermission::Execute); buffer.Protect(GetInteger(base_addr + patch.addr), patch.size, @@ -1318,10 +1324,4 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT return true; } -void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { - for (auto& manager : m_dirty_memory_managers) { - manager.Gather(callback); - } -} - } // namespace Kernel diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 53c0e3316..ab1358a12 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -7,7 +7,6 @@ #include "core/arm/arm_interface.h" #include "core/file_sys/program_metadata.h" -#include "core/gpu_dirty_memory_manager.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_capabilities.h" @@ -128,7 +127,6 @@ private: #ifdef HAS_NCE std::unordered_map<u64, u64> m_post_handlers{}; #endif - std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers; std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor; Core::Memory::Memory m_memory; @@ -511,8 +509,6 @@ public: return m_memory; } - void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); - Core::ExclusiveMonitor& GetExclusiveMonitor() const { return *m_exclusive_monitor; } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 24394d222..8a360a839 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -543,7 +543,8 @@ void KThread::Unpin() { ASSERT(m_parent != nullptr); // Resume any threads that began waiting on us while we were pinned. - for (auto it = m_pinned_waiter_list.begin(); it != m_pinned_waiter_list.end(); ++it) { + for (auto it = m_pinned_waiter_list.begin(); it != m_pinned_waiter_list.end(); + it = m_pinned_waiter_list.erase(it)) { it->EndWait(ResultSuccess); } } @@ -1258,11 +1259,11 @@ ThreadState KThread::RequestTerminate() { // Change the thread's priority to be higher than any system thread's. this->IncreaseBasePriority(TerminatingThreadPriority); - // If the thread is runnable, send a termination interrupt to other cores. + // If the thread is runnable, send a termination interrupt to cores it may be running on. if (this->GetState() == ThreadState::Runnable) { - if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask() & - ~(1ULL << GetCurrentCoreId(m_kernel)); - core_mask != 0) { + // NOTE: We do not mask the "current core", because this code may not actually be + // executing from the thread representing the "current core". + if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask(); core_mask != 0) { Kernel::KInterruptManager::SendInterProcessorInterrupt(m_kernel, core_mask); } } diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index 0e2e11743..cbb1b02bb 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer // Map the memory. const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) - ? KMemoryState::Transfered - : KMemoryState::SharedTransfered; + ? KMemoryState::Transferred + : KMemoryState::SharedTransferred; R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( address, *m_page_group, state, KMemoryPermission::UserReadWrite)); @@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) { // Unmap the memory. const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) - ? KMemoryState::Transfered - : KMemoryState::SharedTransfered; + ? KMemoryState::Transferred + : KMemoryState::SharedTransferred; R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); // Mark ourselves as unmapped. diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1030f0c12..f3683cdcc 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -112,7 +112,14 @@ struct KernelCore::Impl { old_process->Close(); } - process_list.clear(); + { + std::scoped_lock lk{process_list_lock}; + for (auto* const process : process_list) { + process->Terminate(); + process->Close(); + } + process_list.clear(); + } next_object_id = 0; next_kernel_process_id = KProcess::InitialProcessIdMin; @@ -770,6 +777,7 @@ struct KernelCore::Impl { std::atomic<u64> next_thread_id{1}; // Lists all processes that exist in the current session. + std::mutex process_list_lock; std::vector<KProcess*> process_list; std::atomic<KProcess*> application_process{}; std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; @@ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { } void KernelCore::AppendNewProcess(KProcess* process) { + process->Open(); + + std::scoped_lock lk{impl->process_list_lock}; impl->process_list.push_back(process); } +void KernelCore::RemoveProcess(KProcess* process) { + std::scoped_lock lk{impl->process_list_lock}; + if (std::erase(impl->process_list, process)) { + process->Close(); + } +} + void KernelCore::MakeApplicationProcess(KProcess* process) { impl->MakeApplicationProcess(process); } @@ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const { return impl->application_process; } -const std::vector<KProcess*>& KernelCore::GetProcessList() const { - return impl->process_list; +std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { + std::list<KScopedAutoObject<KProcess>> processes; + std::scoped_lock lk{impl->process_list_lock}; + + for (auto* const process : impl->process_list) { + processes.emplace_back(process); + } + + return processes; } Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d4102145..8ea5bed1c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -5,6 +5,7 @@ #include <array> #include <functional> +#include <list> #include <memory> #include <string> #include <unordered_map> @@ -116,8 +117,9 @@ public: /// Retrieves a shared pointer to the system resource limit instance. KResourceLimit* GetSystemResourceLimit(); - /// Adds the given shared pointer to an internal list of active processes. + /// Adds/removes the given pointer to an internal list of active processes. void AppendNewProcess(KProcess* process); + void RemoveProcess(KProcess* process); /// Makes the given process the new application process. void MakeApplicationProcess(KProcess* process); @@ -129,7 +131,7 @@ public: const KProcess* ApplicationProcess() const; /// Retrieves the list of processes. - const std::vector<KProcess*>& GetProcessList() const; + std::list<KScopedAutoObject<KProcess>> GetProcessList(); /// Gets the sole instance of the global scheduler Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index caa8bee9a..5c3e8829f 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc } auto& memory = GetCurrentMemory(kernel); - const auto& process_list = kernel.GetProcessList(); + auto process_list = kernel.GetProcessList(); + auto it = process_list.begin(); + const auto num_processes = process_list.size(); const auto copy_amount = std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); - for (std::size_t i = 0; i < copy_amount; ++i) { - memory.Write64(out_process_ids, process_list[i]->GetProcessId()); + for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { + memory.Write64(out_process_ids, (*it)->GetProcessId()); out_process_ids += sizeof(u64); } diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp index 1f97121b3..671bca23f 100644 --- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp @@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add // Verify that the mapping is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) .GetPageTable() - .CanContain(address, size, KMemoryState::Transfered), + .CanContain(address, size, KMemoryState::Transferred), ResultInvalidMemoryRegion); // Map the transfer memory. @@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a // Verify that the mapping is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) .GetPageTable() - .CanContain(address, size, KMemoryState::Transfered), + .CanContain(address, size, KMemoryState::Transferred), ResultInvalidMemoryRegion); // Unmap the transfer memory. diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 50de02e36..ab432ea78 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -27,8 +27,8 @@ enum class MemoryState : u32 { Ipc = 0x0A, Stack = 0x0B, ThreadLocal = 0x0C, - Transfered = 0x0D, - SharedTransfered = 0x0E, + Transferred = 0x0D, + SharedTransferred = 0x0E, SharedCode = 0x0F, Inaccessible = 0x10, NonSecureIpc = 0x11, diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 749f51f69..316370266 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -189,14 +189,14 @@ enum class ErrorModule : u32 { union Result { u32 raw; - BitField<0, 9, ErrorModule> module; - BitField<9, 13, u32> description; + using Module = BitField<0, 9, ErrorModule>; + using Description = BitField<9, 13, u32>; Result() = default; constexpr explicit Result(u32 raw_) : raw(raw_) {} constexpr Result(ErrorModule module_, u32 description_) - : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} + : raw(Module::FormatValue(module_) | Description::FormatValue(description_)) {} [[nodiscard]] constexpr bool IsSuccess() const { return raw == 0; @@ -211,7 +211,15 @@ union Result { } [[nodiscard]] constexpr u32 GetInnerValue() const { - return static_cast<u32>(module.Value()) | (description << module.bits); + return raw; + } + + [[nodiscard]] constexpr ErrorModule GetModule() const { + return Module::ExtractValue(raw); + } + + [[nodiscard]] constexpr u32 GetDescription() const { + return Description::ExtractValue(raw); } [[nodiscard]] constexpr bool Includes(Result result) const { @@ -274,8 +282,9 @@ public: } [[nodiscard]] constexpr bool Includes(Result other) const { - return code.module == other.module && code.description <= other.description && - other.description <= description_end; + return code.GetModule() == other.GetModule() && + code.GetDescription() <= other.GetDescription() && + other.GetDescription() <= description_end; } private: @@ -330,6 +339,16 @@ constexpr bool EvaluateResultFailure(const Result& r) { return R_FAILED(r); } +template <auto... R> +constexpr bool EvaluateAnyResultIncludes(const Result& r) { + return ((r == R) || ...); +} + +template <auto... R> +constexpr bool EvaluateResultNotIncluded(const Result& r) { + return !EvaluateAnyResultIncludes<R...>(r); +} + template <typename T> constexpr void UpdateCurrentResultReference(T result_reference, Result result) = delete; // Intentionally not defined @@ -371,6 +390,13 @@ constexpr void UpdateCurrentResultReference<const Result>(Result result_referenc DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ ON_RESULT_SUCCESS_2 +#define ON_RESULT_INCLUDED_2(...) \ + ON_RESULT_RETURN_IMPL(ResultImpl::EvaluateAnyResultIncludes<__VA_ARGS__>) + +#define ON_RESULT_INCLUDED(...) \ + DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(__COUNTER__); \ + ON_RESULT_INCLUDED_2(__VA_ARGS__) + constexpr inline Result __TmpCurrentResultReference = ResultSuccess; /// Returns a result. diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 5542d6cbc..29a10ad13 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -11,6 +11,7 @@ #include "common/fs/path_util.h" #include "common/polyfill_ranges.h" #include "common/settings.h" +#include "common/string_util.h" #include "core/hle/service/acc/profile_manager.h" namespace Service::Account { @@ -61,9 +62,7 @@ ProfileManager::ProfileManager() { OpenUser(*GetUser(current)); } -ProfileManager::~ProfileManager() { - WriteUserSaveFile(); -} +ProfileManager::~ProfileManager() = default; /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the /// internal management of the users profiles @@ -113,6 +112,8 @@ Result ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& username) return ERROR_USER_ALREADY_EXISTS; } + is_save_needed = true; + return AddUser({ .user_uuid = uuid, .username = username, @@ -164,6 +165,22 @@ std::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) return GetUserIndex(user.user_uuid); } +/// Returns the first user profile seen based on username (which does not enforce uniqueness) +std::optional<std::size_t> ProfileManager::GetUserIndex(const std::string& username) const { + const auto iter = + std::find_if(profiles.begin(), profiles.end(), [&username](const ProfileInfo& p) { + const std::string profile_username = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast<const char*>(p.username.data()), p.username.size()); + + return username.compare(profile_username) == 0; + }); + if (iter == profiles.end()) { + return std::nullopt; + } + + return static_cast<std::size_t>(std::distance(profiles.begin(), iter)); +} + /// Returns the data structure used by the switch when GetProfileBase is called on acc:* bool ProfileManager::GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const { if (!index || index >= MAX_USERS) { @@ -326,6 +343,9 @@ bool ProfileManager::RemoveUser(UUID uuid) { profiles[*index] = ProfileInfo{}; std::stable_partition(profiles.begin(), profiles.end(), [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); + + is_save_needed = true; + return true; } @@ -340,6 +360,8 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { profile.username = profile_new.username; profile.creation_time = profile_new.timestamp; + is_save_needed = true; + return true; } @@ -348,6 +370,7 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& const auto index = GetUserIndex(uuid); if (index.has_value() && SetProfileBase(uuid, profile_new)) { profiles[*index].data = data_new; + is_save_needed = true; return true; } @@ -391,6 +414,10 @@ void ProfileManager::ParseUserSaveFile() { } void ProfileManager::WriteUserSaveFile() { + if (!is_save_needed) { + return; + } + ProfileDataRaw raw{}; for (std::size_t i = 0; i < MAX_USERS; ++i) { @@ -423,7 +450,10 @@ void ProfileManager::WriteUserSaveFile() { if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " "made in current session will be saved."); + return; } + + is_save_needed = false; } }; // namespace Service::Account diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 900e32200..f94157300 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -70,6 +70,7 @@ public: std::optional<Common::UUID> GetUser(std::size_t index) const; std::optional<std::size_t> GetUserIndex(const Common::UUID& uuid) const; std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; + std::optional<std::size_t> GetUserIndex(const std::string& username) const; bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const; bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const; bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; @@ -103,6 +104,7 @@ private: std::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); bool RemoveProfileAtIndex(std::size_t index); + bool is_save_needed{}; std::array<ProfileInfo, MAX_USERS> profiles{}; std::array<ProfileInfo, MAX_USERS> stored_opened_profiles{}; std::size_t user_count{}; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 97eb56ff0..a768bdc54 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -13,7 +13,6 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/savedata_factory.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/result.h" @@ -37,7 +36,7 @@ #include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/nvnflinger/fb_share_buffer_manager.h" @@ -48,6 +47,8 @@ #include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi_results.h" #include "core/memory.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad.h" namespace Service::AM { @@ -2178,7 +2179,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) { attribute.type = FileSys::SaveDataType::SaveData; FileSys::VirtualDir save_data{}; - const auto res = system.GetFileSystemController().CreateSaveData( + const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData( &save_data, FileSys::SaveDataSpaceId::NandUser, attribute); IPC::ResponseBuilder rb{ctx, 4}; @@ -2353,7 +2354,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) { "new_journal={:016X}", static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); - system.GetFileSystemController().WriteSaveDataSize( + system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize( type, system.GetApplicationProcessProgramID(), user_id, {new_normal_size, new_journal_size}); @@ -2378,7 +2379,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1], user_id[0]); - const auto size = system.GetFileSystemController().ReadSaveDataSize( + const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize( type, system.GetApplicationProcessProgramID(), user_id); IPC::ResponseBuilder rb{ctx, 6}; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 3906c0fa4..c2ff444a6 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -5,13 +5,13 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/frontend/applets/cabinet.h" -#include "core/hid/hid_core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/nfc/common/device.h" +#include "hid_core/hid_core.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 9840d2547..0e4d9cc39 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -9,13 +9,13 @@ #include "common/string_util.h" #include "core/core.h" #include "core/frontend/applets/controller.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" -#include "core/hle/service/hid/controllers/npad.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index 5d17c353f..084bc138c 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -27,8 +27,8 @@ struct ErrorCode { static constexpr ErrorCode FromResult(Result result) { return { - .error_category{2000 + static_cast<u32>(result.module.Value())}, - .error_number{result.description.Value()}, + .error_category{2000 + static_cast<u32>(result.GetModule())}, + .error_number{result.GetDescription()}, }; } diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index 50adc7c02..e83e931c5 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp @@ -59,7 +59,7 @@ void MiiEdit::Initialize() { break; } - manager = system.ServiceManager().GetService<Mii::MiiDBModule>("mii:e")->GetMiiManager(); + manager = system.ServiceManager().GetService<Mii::IStaticService>("mii:e")->GetMiiManager(); if (manager == nullptr) { manager = std::make_shared<Mii::MiiManager>(); } diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h index 369f9250f..673eed516 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/applets/applet_profile_select.h @@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions { bool is_system_or_launcher; bool is_registration_permitted; bool show_skip_button; - bool aditional_select; + bool additional_select; bool show_user_selector; bool is_unqualified_user_selectable; }; diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index b0ea2b381..19057ad7b 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -9,13 +9,13 @@ #include "common/string_util.h" #include "core/core.h" #include "core/file_sys/content_archive.h" -#include "core/file_sys/mode.h" +#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs_vector.h" +#include "core/file_sys/vfs/vfs_vector.h" #include "core/frontend/applets/web_browser.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" @@ -213,7 +213,7 @@ void ExtractSharedFonts(Core::System& system) { std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite); + Common::FS::PathToUTF8String(fonts_dir), FileSys::OpenMode::ReadWrite); const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); @@ -333,7 +333,7 @@ void WebBrowser::ExtractOfflineRomFS() { const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); const auto temp_dir = system.GetFilesystem()->CreateDirectory( - Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); + Common::FS::PathToUTF8String(offline_cache_dir), FileSys::OpenMode::ReadWrite); FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); } diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h index 99fe18659..36adb2510 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.h +++ b/src/core/hle/service/am/applets/applet_web_browser.h @@ -7,7 +7,7 @@ #include <optional> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" #include "core/hle/service/am/applets/applet_web_browser_types.h" #include "core/hle/service/am/applets/applets.h" diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp index 66dd64fd1..3101cf447 100644 --- a/src/core/hle/service/audio/audctl.cpp +++ b/src/core/hle/service/audio/audctl.cpp @@ -4,6 +4,8 @@ #include "common/logging/log.h" #include "core/hle/service/audio/audctl.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" namespace Service::Audio { @@ -19,15 +21,15 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { {6, nullptr, "IsTargetConnected"}, {7, nullptr, "SetDefaultTarget"}, {8, nullptr, "GetDefaultTarget"}, - {9, nullptr, "GetAudioOutputMode"}, - {10, nullptr, "SetAudioOutputMode"}, + {9, &AudCtl::GetAudioOutputMode, "GetAudioOutputMode"}, + {10, &AudCtl::SetAudioOutputMode, "SetAudioOutputMode"}, {11, nullptr, "SetForceMutePolicy"}, {12, &AudCtl::GetForceMutePolicy, "GetForceMutePolicy"}, {13, &AudCtl::GetOutputModeSetting, "GetOutputModeSetting"}, - {14, nullptr, "SetOutputModeSetting"}, + {14, &AudCtl::SetOutputModeSetting, "SetOutputModeSetting"}, {15, nullptr, "SetOutputTarget"}, {16, nullptr, "SetInputTargetForceEnabled"}, - {17, nullptr, "SetHeadphoneOutputLevelMode"}, + {17, &AudCtl::SetHeadphoneOutputLevelMode, "SetHeadphoneOutputLevelMode"}, {18, &AudCtl::GetHeadphoneOutputLevelMode, "GetHeadphoneOutputLevelMode"}, {19, nullptr, "AcquireAudioVolumeUpdateEventForPlayReport"}, {20, nullptr, "AcquireAudioOutputDeviceUpdateEventForPlayReport"}, @@ -40,7 +42,7 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { {27, nullptr, "SetVolumeMappingTableForDev"}, {28, nullptr, "GetAudioOutputChannelCountForPlayReport"}, {29, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, - {30, nullptr, "SetSpeakerAutoMuteEnabled"}, + {30, &AudCtl::SetSpeakerAutoMuteEnabled, "SetSpeakerAutoMuteEnabled"}, {31, &AudCtl::IsSpeakerAutoMuteEnabled, "IsSpeakerAutoMuteEnabled"}, {32, nullptr, "GetActiveOutputTarget"}, {33, nullptr, "GetTargetDeviceInfo"}, @@ -68,6 +70,9 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} { // clang-format on RegisterHandlers(functions); + + m_set_sys = + system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); } AudCtl::~AudCtl() = default; @@ -96,6 +101,33 @@ void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) { rb.Push(target_max_volume); } +void AudCtl::GetAudioOutputMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; + + Set::AudioOutputMode output_mode{}; + const auto result = m_set_sys->GetAudioOutputMode(output_mode, target); + + LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.PushEnum(output_mode); +} + +void AudCtl::SetAudioOutputMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; + const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()}; + + const auto result = m_set_sys->SetAudioOutputMode(target, output_mode); + + LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) { LOG_WARNING(Audio, "(STUBBED) called"); @@ -106,13 +138,31 @@ void AudCtl::GetForceMutePolicy(HLERequestContext& ctx) { void AudCtl::GetOutputModeSetting(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto value = rp.Pop<u32>(); + const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; - LOG_WARNING(Audio, "(STUBBED) called, value={}", value); + LOG_WARNING(Audio, "(STUBBED) called, target={}", target); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(AudioOutputMode::PcmAuto); + rb.PushEnum(Set::AudioOutputMode::ch_7_1); +} + +void AudCtl::SetOutputModeSetting(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto target{rp.PopEnum<Set::AudioOutputModeTarget>()}; + const auto output_mode{rp.PopEnum<Set::AudioOutputMode>()}; + + LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void AudCtl::SetHeadphoneOutputLevelMode(HLERequestContext& ctx) { + LOG_WARNING(Audio, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); } void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) { @@ -123,14 +173,28 @@ void AudCtl::GetHeadphoneOutputLevelMode(HLERequestContext& ctx) { rb.PushEnum(HeadphoneOutputLevelMode::Normal); } +void AudCtl::SetSpeakerAutoMuteEnabled(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_speaker_auto_mute_enabled{rp.Pop<bool>()}; + + LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}", + is_speaker_auto_mute_enabled); + + const auto result = m_set_sys->SetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + void AudCtl::IsSpeakerAutoMuteEnabled(HLERequestContext& ctx) { - const bool is_speaker_auto_mute_enabled = false; + bool is_speaker_auto_mute_enabled{}; + const auto result = m_set_sys->GetSpeakerAutoMuteFlag(is_speaker_auto_mute_enabled); LOG_WARNING(Audio, "(STUBBED) called, is_speaker_auto_mute_enabled={}", is_speaker_auto_mute_enabled); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); + rb.Push(result); rb.Push<u8>(is_speaker_auto_mute_enabled); } diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h index d57abb383..4c90ead70 100644 --- a/src/core/hle/service/audio/audctl.h +++ b/src/core/hle/service/audio/audctl.h @@ -9,6 +9,10 @@ namespace Core { class System; } +namespace Service::Set { +class ISystemSettingsServer; +} + namespace Service::Audio { class AudCtl final : public ServiceFramework<AudCtl> { @@ -17,14 +21,6 @@ public: ~AudCtl() override; private: - enum class AudioOutputMode { - Invalid, - Pcm1ch, - Pcm2ch, - Pcm6ch, - PcmAuto, - }; - enum class ForceMutePolicy { Disable, SpeakerMuteOnHeadphoneUnplugged, @@ -37,10 +33,18 @@ private: void GetTargetVolumeMin(HLERequestContext& ctx); void GetTargetVolumeMax(HLERequestContext& ctx); + void GetAudioOutputMode(HLERequestContext& ctx); + void SetAudioOutputMode(HLERequestContext& ctx); void GetForceMutePolicy(HLERequestContext& ctx); void GetOutputModeSetting(HLERequestContext& ctx); + void SetOutputModeSetting(HLERequestContext& ctx); + void SetHeadphoneOutputLevelMode(HLERequestContext& ctx); void GetHeadphoneOutputLevelMode(HLERequestContext& ctx); + void SetSpeakerAutoMuteEnabled(HLERequestContext& ctx); void IsSpeakerAutoMuteEnabled(HLERequestContext& ctx); + void AcquireTargetNotification(HLERequestContext& ctx); + + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; }; } // namespace Service::Audio diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 56fee4591..de2aa6906 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -18,11 +18,11 @@ using namespace AudioCore::AudioIn; class IAudioIn final : public ServiceFramework<IAudioIn> { public: explicit IAudioIn(Core::System& system_, Manager& manager, size_t session_id, - const std::string& device_name, const AudioInParameter& in_params, u32 handle, - u64 applet_resource_user_id) + const std::string& device_name, const AudioInParameter& in_params, + Kernel::KProcess* handle, u64 applet_resource_user_id) : ServiceFramework{system_, "IAudioIn"}, service_context{system_, "IAudioIn"}, event{service_context.CreateEvent("AudioInEvent")}, - impl{std::make_shared<In>(system_, manager, event, session_id)} { + process{handle}, impl{std::make_shared<In>(system_, manager, event, session_id)} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioIn::GetAudioInState, "GetAudioInState"}, @@ -45,6 +45,8 @@ public: RegisterHandlers(functions); + process->Open(); + if (impl->GetSystem() .Initialize(device_name, in_params, handle, applet_resource_user_id) .IsError()) { @@ -55,6 +57,7 @@ public: ~IAudioIn() override { impl->Free(); service_context.CloseEvent(event); + process->Close(); } [[nodiscard]] std::shared_ptr<In> GetImpl() { @@ -196,6 +199,7 @@ private: KernelHelpers::ServiceContext service_context; Kernel::KEvent* event; + Kernel::KProcess* process; std::shared_ptr<AudioCore::AudioIn::In> impl; Common::ScratchBuffer<u64> released_buffer; }; @@ -267,6 +271,14 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { auto device_name = Common::StringFromBuffer(device_name_data); auto handle{ctx.GetCopyHandle(0)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; + if (process.IsNull()) { + LOG_ERROR(Service_Audio, "Failed to get process handle"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + std::scoped_lock l{impl->mutex}; auto link{impl->LinkToManager()}; if (link.IsError()) { @@ -287,8 +299,9 @@ void AudInU::OpenAudioIn(HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, impl->num_free_sessions); - auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, - in_params, handle, applet_resource_user_id); + auto audio_in = + std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, + process.GetPointerUnsafe(), applet_resource_user_id); impl->sessions[new_session_id] = audio_in->GetImpl(); impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; @@ -318,6 +331,14 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { auto device_name = Common::StringFromBuffer(device_name_data); auto handle{ctx.GetCopyHandle(0)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; + if (process.IsNull()) { + LOG_ERROR(Service_Audio, "Failed to get process handle"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + std::scoped_lock l{impl->mutex}; auto link{impl->LinkToManager()}; if (link.IsError()) { @@ -338,8 +359,9 @@ void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "Opening new AudioIn, sessionid={}, free sessions={}", new_session_id, impl->num_free_sessions); - auto audio_in = std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, - in_params, handle, applet_resource_user_id); + auto audio_in = + std::make_shared<IAudioIn>(system, *impl, new_session_id, device_name, in_params, + process.GetPointerUnsafe(), applet_resource_user_id); impl->sessions[new_session_id] = audio_in->GetImpl(); impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id; diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index ca683d72c..8cc7b69f4 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -26,9 +26,10 @@ class IAudioOut final : public ServiceFramework<IAudioOut> { public: explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager, size_t session_id, const std::string& device_name, - const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id) + const AudioOutParameter& in_params, Kernel::KProcess* handle, + u64 applet_resource_user_id) : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"}, - event{service_context.CreateEvent("AudioOutEvent")}, + event{service_context.CreateEvent("AudioOutEvent")}, process{handle}, impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} { // clang-format off @@ -50,11 +51,14 @@ public: }; // clang-format on RegisterHandlers(functions); + + process->Open(); } ~IAudioOut() override { impl->Free(); service_context.CloseEvent(event); + process->Close(); } [[nodiscard]] std::shared_ptr<AudioCore::AudioOut::Out> GetImpl() { @@ -206,6 +210,7 @@ private: KernelHelpers::ServiceContext service_context; Kernel::KEvent* event; + Kernel::KProcess* process; std::shared_ptr<AudioCore::AudioOut::Out> impl; Common::ScratchBuffer<u64> released_buffer; }; @@ -257,6 +262,14 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { auto device_name = Common::StringFromBuffer(device_name_data); auto handle{ctx.GetCopyHandle(0)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(handle)}; + if (process.IsNull()) { + LOG_ERROR(Service_Audio, "Failed to get process handle"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + auto link{impl->LinkToManager()}; if (link.IsError()) { LOG_ERROR(Service_Audio, "Failed to link Audio Out to Audio Manager"); @@ -276,10 +289,11 @@ void AudOutU::OpenAudioOut(HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "Opening new AudioOut, sessionid={}, free sessions={}", new_session_id, impl->num_free_sessions); - auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, - in_params, handle, applet_resource_user_id); - result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle, - applet_resource_user_id); + auto audio_out = + std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name, in_params, + process.GetPointerUnsafe(), applet_resource_user_id); + result = audio_out->GetImpl()->GetSystem().Initialize( + device_name, in_params, process.GetPointerUnsafe(), applet_resource_user_id); if (result.IsError()) { LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!"); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index bd4ca753b..10108abc0 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -35,10 +35,11 @@ public: explicit IAudioRenderer(Core::System& system_, Manager& manager_, AudioCore::AudioRendererParameterInternal& params, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, - u32 process_handle, u64 applet_resource_user_id, s32 session_id) + u32 process_handle, Kernel::KProcess& process_, + u64 applet_resource_user_id, s32 session_id) : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_}, - impl{std::make_unique<Renderer>(system_, manager, rendered_event)} { + impl{std::make_unique<Renderer>(system_, manager, rendered_event)}, process{process_} { // clang-format off static const FunctionInfo functions[] = { {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, @@ -59,13 +60,15 @@ public: // clang-format on RegisterHandlers(functions); - impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, + process.Open(); + impl->Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, applet_resource_user_id, session_id); } ~IAudioRenderer() override { impl->Finalize(); service_context.CloseEvent(rendered_event); + process.Close(); } private: @@ -139,7 +142,8 @@ private: ctx.WriteBufferC(performance_buffer.data(), performance_buffer.size(), 1); } } else { - LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); + LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", + result.GetDescription()); } IPC::ResponseBuilder rb{ctx, 2}; @@ -234,6 +238,7 @@ private: Kernel::KEvent* rendered_event; Manager& manager; std::unique_ptr<Renderer> impl; + Kernel::KProcess& process; Common::ScratchBuffer<u8> output_buffer; Common::ScratchBuffer<u8> performance_buffer; }; @@ -454,7 +459,7 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { return; } - auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; + auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle).GetPointerUnsafe()}; auto transfer_memory{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(transfer_memory_handle)}; const auto session_id{impl->GetSessionId()}; @@ -471,7 +476,7 @@ void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); rb.PushIpcInterface<IAudioRenderer>(system, *impl, params, transfer_memory.GetPointerUnsafe(), - transfer_memory_size, process_handle, + transfer_memory_size, process_handle, *process, applet_resource_user_id, session_id); } @@ -521,7 +526,7 @@ void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) { } void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) { - LOG_DEBUG(Service_Audio, "called"); + LOG_ERROR(Service_Audio, "called. Implement me!"); } void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) { diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h index 205ed0702..aa36d29d5 100644 --- a/src/core/hle/service/bcat/backend/backend.h +++ b/src/core/hle/service/bcat/backend/backend.h @@ -8,7 +8,7 @@ #include <string> #include "common/common_types.h" -#include "core/file_sys/vfs_types.h" +#include "core/file_sys/vfs/vfs_types.h" #include "core/hle/result.h" #include "core/hle/service/kernel_helpers.h" diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp index a6281913a..76d7bb139 100644 --- a/src/core/hle/service/bcat/bcat_module.cpp +++ b/src/core/hle/service/bcat/bcat_module.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/bcat/backend/backend.h" #include "core/hle/service/bcat/bcat.h" diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index c65e32489..2dc23e674 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -283,7 +283,7 @@ public: {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"}, {18, nullptr, "DisconnectAudioDevice"}, {19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"}, - {20, nullptr, "GetPairedAudioDevices"}, + {20, &IBtmSystemCore::GetPairedAudioDevices, "GetPairedAudioDevices"}, {21, nullptr, "RemoveAudioDevicePairing"}, {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"}, {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"} @@ -327,6 +327,13 @@ private: rb.Push<u32>(0); } + void GetPairedAudioDevices(HLERequestContext& ctx) { + LOG_WARNING(Service_BTM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); + } + void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) { LOG_WARNING(Service_BTM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp index 9925720a3..69acb3a8b 100644 --- a/src/core/hle/service/caps/caps_a.cpp +++ b/src/core/hle/service/caps/caps_a.cpp @@ -202,14 +202,14 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) { } if ((in_result.raw & 0x3801ff) == ResultUnknown1024.raw) { - if (in_result.description - 0x514 < 100) { + if (in_result.GetDescription() - 0x514 < 100) { return ResultInvalidFileData; } - if (in_result.description - 0x5dc < 100) { + if (in_result.GetDescription() - 0x5dc < 100) { return ResultInvalidFileData; } - if (in_result.description - 0x578 < 100) { + if (in_result.GetDescription() - 0x578 < 100) { if (in_result == ResultFileCountLimit) { return ResultUnknown22; } @@ -244,9 +244,10 @@ Result IAlbumAccessorService::TranslateResult(Result in_result) { return ResultUnknown1024; } - if (in_result.module == ErrorModule::FS) { - if ((in_result.description >> 0xc < 0x7d) || (in_result.description - 1000 < 2000) || - (((in_result.description - 3000) >> 3) < 0x271)) { + if (in_result.GetModule() == ErrorModule::FS) { + if ((in_result.GetDescription() >> 0xc < 0x7d) || + (in_result.GetDescription() - 1000 < 2000) || + (((in_result.GetDescription() - 3000) >> 3) < 0x271)) { // TODO: Translate FS error return in_result; } diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 96b225d5f..e3b8ecf3e 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -10,8 +10,10 @@ #include "core/core.h" #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_result.h" -#include "core/hle/service/time/time_manager.h" -#include "core/hle/service/time/time_zone_content_manager.h" +#include "core/hle/service/glue/time/static.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" namespace Service::Capture { @@ -85,7 +87,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu } Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType contex_type, s64 start_posix_time, + ContentType content_type, s64 start_posix_time, s64 end_posix_time, u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; @@ -94,7 +96,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou std::vector<ApplicationAlbumEntry> album_entries; const auto start_date = ConvertToAlbumDateTime(start_posix_time); const auto end_date = ConvertToAlbumDateTime(end_posix_time); - const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); + const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid); if (result.IsError()) { return result; @@ -113,14 +115,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou } Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, - ContentType contex_type, AlbumFileDateTime start_date, + ContentType content_type, AlbumFileDateTime start_date, AlbumFileDateTime end_date, u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; } for (auto& [file_id, path] : album_files) { - if (file_id.type != contex_type) { + if (file_id.type != content_type) { continue; } if (file_id.date > start_date) { @@ -139,7 +141,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en .hash{}, .datetime = file_id.date, .storage = file_id.storage, - .content = contex_type, + .content = content_type, .unknown = 1, }; out_entries.push_back(entry); @@ -239,10 +241,15 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) { const u64 title_id = system.GetApplicationProcessProgramID(); - const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); + + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; + static_service->GetStandardUserSystemClock(user_clock); s64 posix_time{}; - Result result = user_clock.GetCurrentTime(system, posix_time); + auto result = user_clock->GetCurrentTime(posix_time); if (result.IsError()) { return result; @@ -257,10 +264,14 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, const AlbumFileId& file_id, std::span<const u8> image_data) { - const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore(); + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; + static_service->GetStandardUserSystemClock(user_clock); s64 posix_time{}; - Result result = user_clock.GetCurrentTime(system, posix_time); + auto result = user_clock->GetCurrentTime(posix_time); if (result.IsError()) { return result; @@ -455,19 +466,23 @@ Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const } AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { - Time::TimeZone::CalendarInfo calendar_date{}; - const auto& time_zone_manager = - system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; + static_service->GetTimeZoneService(timezone_service); - time_zone_manager.ToCalendarTimeWithMyRules(posix_time, calendar_date); + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo additional_info{}; + timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time); return { - .year = calendar_date.time.year, - .month = calendar_date.time.month, - .day = calendar_date.time.day, - .hour = calendar_date.time.hour, - .minute = calendar_date.time.minute, - .second = calendar_date.time.second, + .year = calendar_time.year, + .month = calendar_time.month, + .day = calendar_time.day, + .hour = calendar_time.hour, + .minute = calendar_time.minute, + .second = calendar_time.second, .unique_id = 0, }; } diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index e20c70c7b..6fd34f589 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -45,10 +45,10 @@ public: Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, u8 flags) const; Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType contex_type, s64 start_posix_time, s64 end_posix_time, + ContentType content_type, s64 start_posix_time, s64 end_posix_time, u64 aruid) const; Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, - ContentType contex_type, AlbumFileDateTime start_date, + ContentType content_type, AlbumFileDateTime start_date, AlbumFileDateTime end_date, u64 aruid) const; Result GetAutoSavingStorage(bool& out_is_autosaving) const; Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, diff --git a/src/core/hle/service/caps/caps_result.h b/src/core/hle/service/caps/caps_result.h index c65e5fb9a..179ae4840 100644 --- a/src/core/hle/service/caps/caps_result.h +++ b/src/core/hle/service/caps/caps_result.h @@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5); constexpr Result ResultUnknown6(ErrorModule::Capture, 6); constexpr Result ResultUnknown7(ErrorModule::Capture, 7); constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); -constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); +constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12); constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h new file mode 100644 index 000000000..9eb10e816 --- /dev/null +++ b/src/core/hle/service/cmif_serialization.h @@ -0,0 +1,336 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/div_ceil.h" + +#include "core/hle/service/cmif_types.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/service.h" + +namespace Service { + +// clang-format off +struct RequestLayout { + u32 copy_handle_count; + u32 move_handle_count; + u32 cmif_raw_data_size; + u32 domain_interface_count; +}; + +template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> +constexpr u32 GetArgumentRawDataSize() { + if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { + return static_cast<u32>(DataOffset); + } else { + using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; + + if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) { + constexpr size_t ArgAlign = alignof(ArgType); + constexpr size_t ArgSize = sizeof(ArgType); + + static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment"); + + constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); + constexpr size_t ArgEnd = ArgOffset + ArgSize; + + return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); + } else { + return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); + } + } +} + +template <ArgumentType DataType, typename MethodArguments, size_t ArgCount = 0, size_t ArgIndex = 0> +constexpr u32 GetArgumentTypeCount() { + if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { + return static_cast<u32>(ArgCount); + } else { + using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; + + if constexpr (ArgumentTraits<ArgType>::Type == DataType) { + return GetArgumentTypeCount<DataType, MethodArguments, ArgCount + 1, ArgIndex + 1>(); + } else { + return GetArgumentTypeCount<DataType, MethodArguments, ArgCount, ArgIndex + 1>(); + } + } +} + +template <typename MethodArguments> +constexpr RequestLayout GetNonDomainReplyInLayout() { + return RequestLayout{ + .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), + .move_handle_count = 0, + .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), + .domain_interface_count = 0, + }; +} + +template <typename MethodArguments> +constexpr RequestLayout GetDomainReplyInLayout() { + return RequestLayout{ + .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), + .move_handle_count = 0, + .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), + .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(), + }; +} + +template <typename MethodArguments> +constexpr RequestLayout GetNonDomainReplyOutLayout() { + return RequestLayout{ + .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), + .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), + .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), + .domain_interface_count = 0, + }; +} + +template <typename MethodArguments> +constexpr RequestLayout GetDomainReplyOutLayout() { + return RequestLayout{ + .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), + .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(), + .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), + .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), + }; +} + +template <typename MethodArguments> +constexpr RequestLayout GetReplyInLayout(bool is_domain) { + return is_domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); +} + +template <typename MethodArguments> +constexpr RequestLayout GetReplyOutLayout(bool is_domain) { + return is_domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); +} + +using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; + +template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> +void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { + if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { + return; + } else { + using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; + + if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) { + constexpr size_t ArgAlign = alignof(ArgType); + constexpr size_t ArgSize = sizeof(ArgType); + + static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment"); + static_assert(!RawDataFinished, "All input interface arguments must appear after raw data"); + + constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); + constexpr size_t ArgEnd = ArgOffset + ArgSize; + + if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) { + // TODO: abort parsing if PID is not provided? + // TODO: validate against raw data value? + std::get<ArgIndex>(args).pid = ctx.GetPID(); + } else { + std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); + } + + return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { + constexpr size_t ArgAlign = alignof(u32); + constexpr size_t ArgSize = sizeof(u32); + constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); + constexpr size_t ArgEnd = ArgOffset + ArgSize; + + ASSERT(is_domain); + ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); + + u32 value{}; + std::memcpy(&value, raw_data + ArgOffset, ArgSize); + std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); + + return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { + std::get<ArgIndex>(args) = ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)).GetPointerUnsafe(); + + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { + constexpr size_t BufferSize = sizeof(ArgType); + + // Clear the existing data. + std::memset(&std::get<ArgIndex>(args), 0, BufferSize); + + std::span<const u8> buffer{}; + + ASSERT(ctx.CanReadBuffer(InBufferIndex)); + if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { + buffer = ctx.ReadBuffer(InBufferIndex); + } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { + buffer = ctx.ReadBufferA(InBufferIndex); + } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { + buffer = ctx.ReadBufferX(InBufferIndex); + } + + std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); + + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { + using ElementType = typename ArgType::Type; + + std::span<const u8> buffer{}; + + if (ctx.CanReadBuffer(InBufferIndex)) { + if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { + buffer = ctx.ReadBuffer(InBufferIndex); + } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { + buffer = ctx.ReadBufferA(InBufferIndex); + } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { + buffer = ctx.ReadBufferX(InBufferIndex); + } + } + + ElementType* ptr = (ElementType*) buffer.data(); + size_t size = buffer.size() / sizeof(ElementType); + + std::get<ArgIndex>(args) = std::span(ptr, size); + + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { + constexpr size_t BufferSize = sizeof(ArgType); + + // Clear the existing data. + std::memset(&std::get<ArgIndex>(args), 0, BufferSize); + + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { + using ElementType = typename ArgType::Type; + + // Set up scratch buffer. + auto& buffer = temp[OutBufferIndex]; + if (ctx.CanWriteBuffer(OutBufferIndex)) { + buffer.resize_destructive(ctx.GetWriteBufferSize(OutBufferIndex)); + } else { + buffer.resize_destructive(0); + } + + ElementType* ptr = (ElementType*) buffer.data(); + size_t size = buffer.size() / sizeof(ElementType); + + std::get<ArgIndex>(args) = std::span(ptr, size); + + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else { + return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } + } +} + +template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> +void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { + if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { + return; + } else { + using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; + + if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { + constexpr size_t ArgAlign = alignof(ArgType); + constexpr size_t ArgSize = sizeof(ArgType); + + static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); + static_assert(!RawDataFinished, "All output interface arguments must appear after raw data"); + + constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); + constexpr size_t ArgEnd = ArgOffset + ArgSize; + + std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); + + return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { + if (is_domain) { + ctx.AddDomainObject(std::get<ArgIndex>(args)); + } else { + ctx.AddMoveInterface(std::get<ArgIndex>(args)); + } + + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { + ctx.AddCopyObject(std::get<ArgIndex>(args)); + + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { + ctx.AddMoveObject(std::get<ArgIndex>(args)); + + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { + constexpr size_t BufferSize = sizeof(ArgType); + + ASSERT(ctx.CanWriteBuffer(OutBufferIndex)); + if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { + ctx.WriteBuffer(std::get<ArgIndex>(args), OutBufferIndex); + } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { + ctx.WriteBufferB(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); + } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { + ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); + } + + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { + auto& buffer = temp[OutBufferIndex]; + const size_t size = buffer.size(); + + if (ctx.CanWriteBuffer(OutBufferIndex)) { + if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { + ctx.WriteBuffer(buffer.data(), size, OutBufferIndex); + } else if constexpr (ArgType::Attr & BufferAttr_HipcMapAlias) { + ctx.WriteBufferB(buffer.data(), size, OutBufferIndex); + } else /* if (ArgType::Attr & BufferAttr_HipcPointer) */ { + ctx.WriteBufferC(buffer.data(), size, OutBufferIndex); + } + } + + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } else { + return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); + } + } +} + +template <bool Domain, typename T, typename... A> +void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { + // Verify domain state. + if constexpr (!Domain) { + ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); + } + const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; + + using MethodArguments = std::tuple<std::remove_reference_t<A>...>; + + OutTemporaryBuffers buffers{}; + auto call_arguments = std::tuple<typename RemoveOut<A>::Type...>(); + + // Read inputs. + const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; + ReadInArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); + + // Call. + const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { + return (t.*f)(args...); + }; + const Result res = std::apply(Callable, call_arguments); + + // Write result. + const RequestLayout layout = GetReplyOutLayout<MethodArguments>(is_domain); + IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count}; + rb.Push(res); + + // Write out arguments. + WriteOutArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); +} +// clang-format on + +template <typename Self> +template <bool Domain, auto F> +inline void ServiceFramework<Self>::CmifReplyWrap(HLERequestContext& ctx) { + return CmifReplyWrapImpl<Domain>(ctx, *static_cast<Self*>(this), F); +} + +} // namespace Service diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h new file mode 100644 index 000000000..2610c49f3 --- /dev/null +++ b/src/core/hle/service/cmif_types.h @@ -0,0 +1,294 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/service/hle_ipc.h" + +namespace Service { + +// clang-format off +template <typename T> +class Out { +public: + using Type = T; + + /* implicit */ Out(Type& t) : raw(&t) {} + ~Out() = default; + + Type* Get() const { + return raw; + } + + Type& operator*() { + return *raw; + } + +private: + Type* raw; +}; + +template <typename T> +using SharedPointer = std::shared_ptr<T>; + +struct ClientProcessId { + explicit operator bool() const { + return pid != 0; + } + + const u64& operator*() const { + return pid; + } + + u64 pid; +}; + +struct ProcessId { + explicit operator bool() const { + return pid != 0; + } + + const u64& operator*() const { + return pid; + } + + u64 pid; +}; + +using ClientAppletResourceUserId = ClientProcessId; +using AppletResourceUserId = ProcessId; + +template <typename T> +class InCopyHandle { +public: + using Type = T; + + /* implicit */ InCopyHandle(Type* t) : raw(t) {} + /* implicit */ InCopyHandle() : raw() {} + ~InCopyHandle() = default; + + InCopyHandle& operator=(Type* rhs) { + raw = rhs; + return *this; + } + + Type* Get() const { + return raw; + } + + Type& operator*() const { + return *raw; + } + + Type* operator->() const { + return raw; + } + + explicit operator bool() const { + return raw != nullptr; + } + +private: + Type* raw; +}; + +template <typename T> +class OutCopyHandle { +public: + using Type = T*; + + /* implicit */ OutCopyHandle(Type& t) : raw(&t) {} + ~OutCopyHandle() = default; + + Type* Get() const { + return raw; + } + + Type& operator*() { + return *raw; + } + +private: + Type* raw; +}; + +template <typename T> +class OutMoveHandle { +public: + using Type = T*; + + /* implicit */ OutMoveHandle(Type& t) : raw(&t) {} + ~OutMoveHandle() = default; + + Type* Get() const { + return raw; + } + + Type& operator*() { + return *raw; + } + +private: + Type* raw; +}; + +enum BufferAttr : int { + BufferAttr_In = (1U << 0), + BufferAttr_Out = (1U << 1), + BufferAttr_HipcMapAlias = (1U << 2), + BufferAttr_HipcPointer = (1U << 3), + BufferAttr_FixedSize = (1U << 4), + BufferAttr_HipcAutoSelect = (1U << 5), + BufferAttr_HipcMapTransferAllowsNonSecure = (1U << 6), + BufferAttr_HipcMapTransferAllowsNonDevice = (1U << 7), +}; + +template <typename T, int A> +struct Buffer : public std::span<T> { + static_assert(std::is_trivially_copyable_v<T>, "Buffer type must be trivially copyable"); + static_assert((A & BufferAttr_FixedSize) == 0, "Buffer attr must not contain FixedSize"); + static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "Buffer attr must be In or Out"); + static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); + using Type = T; + + /* implicit */ Buffer(const std::span<T>& rhs) : std::span<T>(rhs) {} + /* implicit */ Buffer() = default; + + Buffer& operator=(const std::span<T>& rhs) { + std::span<T>::operator=(rhs); + return *this; + } + + T& operator*() const { + return *this->data(); + } + + explicit operator bool() const { + return this->size() > 0; + } +}; + +template <BufferAttr A> +using InBuffer = Buffer<const u8, BufferAttr_In | A>; + +template <typename T, BufferAttr A> +using InArray = Buffer<T, BufferAttr_In | A>; + +template <BufferAttr A> +using OutBuffer = Buffer<u8, BufferAttr_Out | A>; + +template <typename T, BufferAttr A> +using OutArray = Buffer<T, BufferAttr_Out | A>; + +template <typename T, int A> +struct LargeData : public T { + static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable"); + static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize"); + static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out"); + static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); + using Type = T; + + /* implicit */ LargeData(const T& rhs) : T(rhs) {} + /* implicit */ LargeData() = default; +}; + +template <typename T, BufferAttr A> +using InLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_In | A>; + +template <typename T, BufferAttr A> +using OutLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_Out | A>; + +template <typename T> +struct RemoveOut { + using Type = std::remove_reference_t<T>; +}; + +template <typename T> +struct RemoveOut<Out<T>> { + using Type = typename Out<T>::Type; +}; + +template <typename T> +struct RemoveOut<OutCopyHandle<T>> { + using Type = typename OutCopyHandle<T>::Type; +}; + +template <typename T> +struct RemoveOut<OutMoveHandle<T>> { + using Type = typename OutMoveHandle<T>::Type; +}; + +enum class ArgumentType { + InProcessId, + InData, + InInterface, + InCopyHandle, + OutData, + OutInterface, + OutCopyHandle, + OutMoveHandle, + InBuffer, + InLargeData, + OutBuffer, + OutLargeData, +}; + +template <typename T> +struct ArgumentTraits; + +template <> +struct ArgumentTraits<ClientProcessId> { + static constexpr ArgumentType Type = ArgumentType::InProcessId; +}; + +template <typename T> +struct ArgumentTraits<SharedPointer<T>> { + static constexpr ArgumentType Type = ArgumentType::InInterface; +}; + +template <typename T> +struct ArgumentTraits<InCopyHandle<T>> { + static constexpr ArgumentType Type = ArgumentType::InCopyHandle; +}; + +template <typename T> +struct ArgumentTraits<Out<SharedPointer<T>>> { + static constexpr ArgumentType Type = ArgumentType::OutInterface; +}; + +template <typename T> +struct ArgumentTraits<Out<T>> { + static constexpr ArgumentType Type = ArgumentType::OutData; +}; + +template <typename T> +struct ArgumentTraits<OutCopyHandle<T>> { + static constexpr ArgumentType Type = ArgumentType::OutCopyHandle; +}; + +template <typename T> +struct ArgumentTraits<OutMoveHandle<T>> { + static constexpr ArgumentType Type = ArgumentType::OutMoveHandle; +}; + +template <typename T, int A> +struct ArgumentTraits<Buffer<T, A>> { + static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer; +}; + +template <typename T, int A> +struct ArgumentTraits<LargeData<T, A>> { + static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutLargeData : ArgumentType::InLargeData; +}; + +template <typename T> +struct ArgumentTraits { + static constexpr ArgumentType Type = ArgumentType::InData; +}; +// clang-format on + +} // namespace Service diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 31da86074..dfcac1ffd 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -73,8 +73,8 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F "Program entry point: 0x{:16X}\n" "\n", Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw, - 2000 + static_cast<u32>(error_code.module.Value()), - static_cast<u32>(error_code.description.Value()), info.set_flags, info.program_entry_point); + 2000 + static_cast<u32>(error_code.GetModule()), + static_cast<u32>(error_code.GetDescription()), info.set_flags, info.program_entry_point); if (info.backtrace_size != 0x0) { crash_report += "Registers:\n"; for (size_t i = 0; i < info.registers.size(); i++) { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 780f8c74d..ae230afc0 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -12,27 +12,24 @@ #include "core/file_sys/card_image.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/romfs_factory.h" #include "core/file_sys/savedata_factory.h" #include "core/file_sys/sdmc_factory.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_offset.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/file_sys/vfs/vfs_offset.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_ldr.h" -#include "core/hle/service/filesystem/fsp_pr.h" -#include "core/hle/service/filesystem/fsp_srv.h" +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" +#include "core/hle/service/filesystem/fsp/fsp_pr.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" +#include "core/hle/service/filesystem/romfs_controller.h" +#include "core/hle/service/filesystem/save_data_controller.h" #include "core/hle/service/server_manager.h" #include "core/loader/loader.h" namespace Service::FileSystem { -// A default size for normal/journal save data size if application control metadata cannot be found. -// This should be large enough to satisfy even the most extreme requirements (~4.2GB) -constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; - static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, std::string_view dir_name_) { std::string dir_name(Common::FS::SanitizePath(dir_name_)); @@ -55,12 +52,12 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type{}; + FileSys::DirectoryEntryType entry_type{}; if (GetEntryType(&entry_type, path) == ResultSuccess) { - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } auto file = dir->CreateFile(Common::FS::GetFilename(path)); @@ -84,7 +81,7 @@ Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (!dir->DeleteFile(Common::FS::GetFilename(path))) { // TODO(DarkLordZach): Find a better error code for this @@ -155,12 +152,12 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } if (dst && Common::FS::Exists(dst->GetFullPath())) { LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath()); - return FileSys::ERROR_PATH_ALREADY_EXISTS; + return FileSys::ResultPathAlreadyExists; } if (!src->Rename(Common::FS::GetFilename(dest_path))) { @@ -197,7 +194,7 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) { // Use more-optimized vfs implementation rename. if (src == nullptr) - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; if (!src->Rename(Common::FS::GetFilename(dest_path))) { // TODO(DarkLordZach): Find a better error code for this return ResultUnknown; @@ -216,7 +213,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, } Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, - const std::string& path_, FileSys::Mode mode) const { + const std::string& path_, + FileSys::OpenMode mode) const { const std::string path(Common::FS::SanitizePath(path_)); std::string_view npath = path; while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) { @@ -225,10 +223,10 @@ Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file, auto file = backing->GetFileRelative(npath); if (file == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - if (mode == FileSys::Mode::Append) { + if (mode == FileSys::OpenMode::AllowAppend) { *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()); } else { *out_file = file; @@ -243,50 +241,50 @@ Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_direct auto dir = GetDirectoryRelativeWrapped(backing, path); if (dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_directory = dir; return ResultSuccess; } -Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type, +Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path_) const { std::string path(Common::FS::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } auto filename = Common::FS::GetFilename(path); // TODO(Subv): Some games use the '/' path, find out what this means. if (filename.empty()) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } if (dir->GetFile(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::File; + *out_entry_type = FileSys::DirectoryEntryType::File; return ResultSuccess; } if (dir->GetSubdirectory(filename) != nullptr) { - *out_entry_type = FileSys::EntryType::Directory; + *out_entry_type = FileSys::DirectoryEntryType::Directory; return ResultSuccess; } - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw( FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const { auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); if (dir == nullptr) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } - FileSys::EntryType entry_type; + FileSys::DirectoryEntryType entry_type; if (GetEntryType(&entry_type, path) != ResultSuccess) { - return FileSys::ERROR_PATH_NOT_FOUND; + return FileSys::ResultPathNotFound; } *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path)); @@ -297,157 +295,77 @@ FileSystemController::FileSystemController(Core::System& system_) : system{syste FileSystemController::~FileSystemController() = default; -Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) { - romfs_factory = std::move(factory); - LOG_DEBUG(Service_FS, "Registered RomFS"); - return ResultSuccess; -} - -Result FileSystemController::RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) { - ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data"); - save_data_factory = std::move(factory); - LOG_DEBUG(Service_FS, "Registered save data"); - return ResultSuccess; -} +Result FileSystemController::RegisterProcess( + ProcessId process_id, ProgramId program_id, + std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) { + std::scoped_lock lk{registration_lock}; -Result FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { - ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC"); - sdmc_factory = std::move(factory); - LOG_DEBUG(Service_FS, "Registered SDMC"); - return ResultSuccess; -} + registrations.emplace(process_id, Registration{ + .program_id = program_id, + .romfs_factory = std::move(romfs_factory), + .save_data_factory = CreateSaveDataFactory(program_id), + }); -Result FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) { - ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS"); - bis_factory = std::move(factory); - LOG_DEBUG(Service_FS, "Registered BIS"); + LOG_DEBUG(Service_FS, "Registered for process {}", process_id); return ResultSuccess; } -void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) { - LOG_TRACE(Service_FS, "Setting packed update for romfs"); - - if (romfs_factory == nullptr) - return; - - romfs_factory->SetPackedUpdate(std::move(update_raw)); -} - -FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const { - LOG_TRACE(Service_FS, "Opening RomFS for current process"); - - if (romfs_factory == nullptr) { - return nullptr; - } - - return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID()); -} - -FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id, - FileSys::ContentRecordType type) const { - LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id); - - if (romfs_factory == nullptr) { - return nullptr; - } - - return romfs_factory->OpenPatchedRomFS(title_id, type); -} - -FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex( - u64 title_id, u8 program_index, FileSys::ContentRecordType type) const { - LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id, - program_index); - - if (romfs_factory == nullptr) { - return nullptr; - } - - return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); -} - -FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, - FileSys::ContentRecordType type) const { - LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", - title_id, storage_id, type); - - if (romfs_factory == nullptr) { - return nullptr; - } - - return romfs_factory->Open(title_id, storage_id, type); -} - -std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca( - u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { - return romfs_factory->GetEntry(title_id, storage_id, type); -} - -Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data, - FileSys::SaveDataSpaceId space, - const FileSys::SaveDataAttribute& save_struct) const { - LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, - save_struct.DebugInfo()); - - if (save_data_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; - } +Result FileSystemController::OpenProcess( + ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller, + std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) { + std::scoped_lock lk{registration_lock}; - auto save_data = save_data_factory->Create(space, save_struct); - if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + const auto it = registrations.find(process_id); + if (it == registrations.end()) { + return FileSys::ResultTargetNotFound; } - *out_save_data = save_data; + *out_program_id = it->second.program_id; + *out_save_data_controller = + std::make_shared<SaveDataController>(system, it->second.save_data_factory); + *out_romfs_controller = + std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id); return ResultSuccess; } -Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data, - FileSys::SaveDataSpaceId space, - const FileSys::SaveDataAttribute& attribute) const { - LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space, - attribute.DebugInfo()); - - if (save_data_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; - } +void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) { + LOG_TRACE(Service_FS, "Setting packed update for romfs"); - auto save_data = save_data_factory->Open(space, attribute); - if (save_data == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + std::scoped_lock lk{registration_lock}; + const auto it = registrations.find(process_id); + if (it == registrations.end()) { + return; } - *out_save_data = save_data; - return ResultSuccess; + it->second.romfs_factory->SetPackedUpdate(std::move(update_raw)); } -Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, - FileSys::SaveDataSpaceId space) const { - LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space); - - if (save_data_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; - } +std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() { + return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{})); +} - auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space); - if (save_data_space == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; - } +std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory( + ProgramId program_id) { + using YuzuPath = Common::FS::YuzuPath; + const auto rw_mode = FileSys::OpenMode::ReadWrite; - *out_save_data_space = save_data_space; - return ResultSuccess; + auto vfs = system.GetFilesystem(); + const auto nand_directory = + vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); + return std::make_shared<FileSys::SaveDataFactory>(system, program_id, + std::move(nand_directory)); } Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const { LOG_TRACE(Service_FS, "Opening SDMC"); if (sdmc_factory == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } auto sdmc = sdmc_factory->Open(); if (sdmc == nullptr) { - return FileSys::ERROR_SD_CARD_NOT_FOUND; + return FileSys::ResultPortSdCardNoDevice; } *out_sdmc = sdmc; @@ -459,12 +377,12 @@ Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_parti LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartition(id); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition = part; @@ -476,12 +394,12 @@ Result FileSystemController::OpenBISPartitionStorage( LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id); if (bis_factory == nullptr) { - return FileSys::ERROR_ENTITY_NOT_FOUND; + return FileSys::ResultTargetNotFound; } auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem()); if (part == nullptr) { - return FileSys::ERROR_INVALID_ARGUMENT; + return FileSys::ResultInvalidArgument; } *out_bis_partition_storage = part; @@ -540,48 +458,6 @@ u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const { return 0; } -FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type, - u64 title_id, u128 user_id) const { - if (save_data_factory == nullptr) { - return {0, 0}; - } - - const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id); - - if (value.normal == 0 && value.journal == 0) { - FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE}; - - FileSys::NACP nacp; - const auto res = system.GetAppLoader().ReadControlData(nacp); - - if (res != Loader::ResultStatus::Success) { - const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(), - system.GetFileSystemController(), - system.GetContentProvider()}; - const auto metadata = pm.GetControlMetadata(); - const auto& nacp_unique = metadata.first; - - if (nacp_unique != nullptr) { - new_size = {nacp_unique->GetDefaultNormalSaveSize(), - nacp_unique->GetDefaultJournalSaveSize()}; - } - } else { - new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()}; - } - - WriteSaveDataSize(type, title_id, user_id, new_size); - return new_size; - } - - return value; -} - -void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, - FileSys::SaveDataSize new_value) const { - if (save_data_factory != nullptr) - save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); -} - void FileSystemController::SetGameCard(FileSys::VirtualFile file) { gamecard = std::make_unique<FileSys::XCI>(file); const auto dir = gamecard->ConcatenatedPseudoDirectory(); @@ -801,29 +677,24 @@ FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const { return bis_factory->GetBCATDirectory(title_id); } -void FileSystemController::SetAutoSaveDataCreation(bool enable) { - save_data_factory->SetAutoCreate(enable); -} - void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { if (overwrite) { bis_factory = nullptr; - save_data_factory = nullptr; sdmc_factory = nullptr; } using YuzuPath = Common::FS::YuzuPath; const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir); const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents"; - const auto rw_mode = FileSys::Mode::ReadWrite; + const auto rw_mode = FileSys::OpenMode::ReadWrite; auto nand_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode); - auto load_directory = - vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); - auto sd_load_directory = - vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read); + auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), + FileSys::OpenMode::Read); + auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), + FileSys::OpenMode::Read); auto dump_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); @@ -836,11 +707,6 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove bis_factory->GetUserNANDContents()); } - if (save_data_factory == nullptr) { - save_data_factory = - std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory)); - } - if (sdmc_factory == nullptr) { sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory), std::move(sd_load_directory)); @@ -849,12 +715,19 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove } } +void FileSystemController::Reset() { + std::scoped_lock lk{registration_lock}; + registrations.clear(); +} + void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); + const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); }; + server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system)); server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system)); - server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system)); + server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 276d264e1..718500385 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -4,9 +4,11 @@ #pragma once #include <memory> +#include <mutex> #include "common/common_types.h" -#include "core/file_sys/directory.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/result.h" namespace Core { @@ -26,7 +28,6 @@ class XCI; enum class BisPartitionId : u32; enum class ContentRecordType : u8; -enum class Mode : u32; enum class SaveDataSpaceId : u8; enum class SaveDataType : u8; enum class StorageId : u8; @@ -43,6 +44,9 @@ class ServiceManager; namespace FileSystem { +class RomFsController; +class SaveDataController; + enum class ContentStorageId : u32 { System, User, @@ -54,39 +58,24 @@ enum class ImageDirectoryId : u32 { SdCard, }; -enum class OpenDirectoryMode : u64 { - Directory = (1 << 0), - File = (1 << 1), - All = Directory | File -}; -DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode); +using ProcessId = u64; +using ProgramId = u64; class FileSystemController { public: explicit FileSystemController(Core::System& system_); ~FileSystemController(); - Result RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); - Result RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory); - Result RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); - Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); - - void SetPackedUpdate(FileSys::VirtualFile update_raw); - FileSys::VirtualFile OpenRomFSCurrentProcess() const; - FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const; - FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, - FileSys::ContentRecordType type) const; - FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, - FileSys::ContentRecordType type) const; - std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, - FileSys::ContentRecordType type) const; - - Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, - const FileSys::SaveDataAttribute& save_struct) const; - Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, - const FileSys::SaveDataAttribute& save_struct) const; - Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, - FileSys::SaveDataSpaceId space) const; + Result RegisterProcess(ProcessId process_id, ProgramId program_id, + std::shared_ptr<FileSys::RomFSFactory>&& factory); + Result OpenProcess(ProgramId* out_program_id, + std::shared_ptr<SaveDataController>* out_save_data_controller, + std::shared_ptr<RomFsController>* out_romfs_controller, + ProcessId process_id); + void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw); + + std::shared_ptr<SaveDataController> OpenSaveDataController(); + Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const; Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition, FileSys::BisPartitionId id) const; @@ -96,11 +85,6 @@ public: u64 GetFreeSpaceSize(FileSys::StorageId id) const; u64 GetTotalSpaceSize(FileSys::StorageId id) const; - FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, - u128 user_id) const; - void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, - FileSys::SaveDataSize new_value) const; - void SetGameCard(FileSys::VirtualFile file); FileSys::XCI* GetGameCard() const; @@ -133,15 +117,24 @@ public: FileSys::VirtualDir GetBCATDirectory(u64 title_id) const; - void SetAutoSaveDataCreation(bool enable); - // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function // above is called. void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); + void Reset(); + private: - std::unique_ptr<FileSys::RomFSFactory> romfs_factory; - std::unique_ptr<FileSys::SaveDataFactory> save_data_factory; + std::shared_ptr<FileSys::SaveDataFactory> CreateSaveDataFactory(ProgramId program_id); + + struct Registration { + ProgramId program_id; + std::shared_ptr<FileSys::RomFSFactory> romfs_factory; + std::shared_ptr<FileSys::SaveDataFactory> save_data_factory; + }; + + std::mutex registration_lock; + std::map<ProcessId, Registration> registrations; + std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; std::unique_ptr<FileSys::BISFactory> bis_factory; @@ -238,7 +231,7 @@ public: * @return Opened file, or error code */ Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path, - FileSys::Mode mode) const; + FileSys::OpenMode mode) const; /** * Open a directory specified by its path @@ -251,7 +244,7 @@ public: * Get the type of the specified path * @return The type of the specified path or error code */ - Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const; + Result GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path) const; /** * Get the timestamp of the specified path diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp new file mode 100644 index 000000000..39690018b --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/savedata_factory.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +template <typename T> +static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries, + const std::vector<T>& new_data, FileSys::DirectoryEntryType type) { + entries.reserve(entries.size() + new_data.size()); + + for (const auto& new_entry : new_data) { + auto name = new_entry->GetName(); + + if (type == FileSys::DirectoryEntryType::File && + name == FileSys::GetSaveDataSizeFileName()) { + continue; + } + + entries.emplace_back(name, static_cast<s8>(type), + type == FileSys::DirectoryEntryType::Directory ? 0 + : new_entry->GetSize()); + } +} + +IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode) + : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IDirectory::Read, "Read"}, + {1, &IDirectory::GetEntryCount, "GetEntryCount"}, + }; + RegisterHandlers(functions); + + // TODO(DarkLordZach): Verify that this is the correct behavior. + // Build entry index now to save time later. + if (True(mode & FileSys::OpenDirectoryMode::Directory)) { + BuildEntryIndex(entries, backend->GetSubdirectories(), + FileSys::DirectoryEntryType::Directory); + } + if (True(mode & FileSys::OpenDirectoryMode::File)) { + BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File); + } +} + +void IDirectory::Read(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called."); + + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>(); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); + const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); + const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(actual_entries); +} + +void IDirectory::GetEntryCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + u64 count = entries.size() - next_entry_index; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(count); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h new file mode 100644 index 000000000..793ecfcd7 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace FileSys { +struct DirectoryEntry; +} + +namespace Service::FileSystem { + +class IDirectory final : public ServiceFramework<IDirectory> { +public: + explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, + FileSys::OpenDirectoryMode mode); + +private: + FileSys::VirtualDir backend; + std::vector<FileSys::DirectoryEntry> entries; + u64 next_entry_index = 0; + + void Read(HLERequestContext& ctx); + void GetEntryCount(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp new file mode 100644 index 000000000..9a18f6ec5 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IFile::Read, "Read"}, + {1, &IFile::Write, "Write"}, + {2, &IFile::Flush, "Flush"}, + {3, &IFile::SetSize, "SetSize"}, + {4, &IFile::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + {6, nullptr, "OperateRangeWithBuffer"}, + }; + RegisterHandlers(functions); +} + +void IFile::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u64>(output.size())); +} + +void IFile::Write(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 option = rp.Pop<u64>(); + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + const auto data = ctx.ReadBuffer(); + + ASSERT_MSG(static_cast<s64>(data.size()) <= length, + "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", + length, data.size()); + + // Write the data to the Storage backend + const auto write_size = + static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); + const std::size_t written = backend->Write(data.data(), write_size, offset); + + ASSERT_MSG(static_cast<s64>(written) == length, + "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, + written); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::Flush(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + // Exists for SDK compatibiltity -- No need to flush file. + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::SetSize(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const u64 size = rp.Pop<u64>(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + backend->Resize(size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFile::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h new file mode 100644 index 000000000..5e5430c67 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFile final : public ServiceFramework<IFile> { +public: + explicit IFile(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void Write(HLERequestContext& ctx); + void Flush(HLERequestContext& ctx); + void SetSize(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp new file mode 100644 index 000000000..efa394dd1 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp @@ -0,0 +1,262 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/string_util.h" +#include "core/hle/service/filesystem/fsp/fs_i_directory.h" +#include "core/hle/service/filesystem/fsp/fs_i_file.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) + : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( + size_)} { + static const FunctionInfo functions[] = { + {0, &IFileSystem::CreateFile, "CreateFile"}, + {1, &IFileSystem::DeleteFile, "DeleteFile"}, + {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, + {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, + {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, + {5, &IFileSystem::RenameFile, "RenameFile"}, + {6, nullptr, "RenameDirectory"}, + {7, &IFileSystem::GetEntryType, "GetEntryType"}, + {8, &IFileSystem::OpenFile, "OpenFile"}, + {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, + {10, &IFileSystem::Commit, "Commit"}, + {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, + {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, + {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, + {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, + {15, nullptr, "QueryEntry"}, + {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, + }; + RegisterHandlers(functions); +} + +void IFileSystem::CreateFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const u64 file_mode = rp.Pop<u64>(); + const u32 file_size = rp.Pop<u32>(); + + LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, + file_size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateFile(name, file_size)); +} + +void IFileSystem::DeleteFile(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteFile(name)); +} + +void IFileSystem::CreateDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CreateDirectory(name)); +} + +void IFileSystem::DeleteDirectory(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectory(name)); +} + +void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. directory={}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.DeleteDirectoryRecursively(name)); +} + +void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. Directory: {}", name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.CleanDirectoryRecursively(name)); +} + +void IFileSystem::RenameFile(HLERequestContext& ctx) { + const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); + const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); + + LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(backend.RenameFile(src_name, dst_name)); +} + +void IFileSystem::OpenFile(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>()); + + LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); + + FileSys::VirtualFile vfs_file{}; + auto result = backend.OpenFile(&vfs_file, name, mode); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto file = std::make_shared<IFile>(system, vfs_file); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFile>(std::move(file)); +} + +void IFileSystem::OpenDirectory(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>(); + + LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); + + FileSys::VirtualDir vfs_dir{}; + auto result = backend.OpenDirectory(&vfs_dir, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IDirectory>(std::move(directory)); +} + +void IFileSystem::GetEntryType(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_DEBUG(Service_FS, "called. file={}", name); + + FileSys::DirectoryEntryType vfs_entry_type{}; + auto result = backend.GetEntryType(&vfs_entry_type, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(static_cast<u32>(vfs_entry_type)); +} + +void IFileSystem::Commit(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_free_size()); +} + +void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(size.get_total_size()); +} + +void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) { + const auto file_buffer = ctx.ReadBuffer(); + const std::string name = Common::StringFromBuffer(file_buffer); + + LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); + + FileSys::FileTimeStampRaw vfs_timestamp{}; + auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(ResultSuccess); + rb.PushRaw(vfs_timestamp); +} + +void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + struct FileSystemAttribute { + u8 dir_entry_name_length_max_defined; + u8 file_entry_name_length_max_defined; + u8 dir_path_name_length_max_defined; + u8 file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x5); + u8 utf16_dir_entry_name_length_max_defined; + u8 utf16_file_entry_name_length_max_defined; + u8 utf16_dir_path_name_length_max_defined; + u8 utf16_file_path_name_length_max_defined; + INSERT_PADDING_BYTES_NOINIT(0x18); + s32 dir_entry_name_length_max; + s32 file_entry_name_length_max; + s32 dir_path_name_length_max; + s32 file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x5); + s32 utf16_dir_entry_name_length_max; + s32 utf16_file_entry_name_length_max; + s32 utf16_dir_path_name_length_max; + s32 utf16_file_path_name_length_max; + INSERT_PADDING_WORDS_NOINIT(0x18); + INSERT_PADDING_WORDS_NOINIT(0x1); + }; + static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size"); + + FileSystemAttribute savedata_attribute{}; + savedata_attribute.dir_entry_name_length_max_defined = true; + savedata_attribute.file_entry_name_length_max_defined = true; + savedata_attribute.dir_entry_name_length_max = 0x40; + savedata_attribute.file_entry_name_length_max = 0x40; + + IPC::ResponseBuilder rb{ctx, 50}; + rb.Push(ResultSuccess); + rb.PushRaw(savedata_attribute); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h new file mode 100644 index 000000000..b06b3ef0e --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp/fsp_util.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IFileSystem final : public ServiceFramework<IFileSystem> { +public: + explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_); + + void CreateFile(HLERequestContext& ctx); + void DeleteFile(HLERequestContext& ctx); + void CreateDirectory(HLERequestContext& ctx); + void DeleteDirectory(HLERequestContext& ctx); + void DeleteDirectoryRecursively(HLERequestContext& ctx); + void CleanDirectoryRecursively(HLERequestContext& ctx); + void RenameFile(HLERequestContext& ctx); + void OpenFile(HLERequestContext& ctx); + void OpenDirectory(HLERequestContext& ctx); + void GetEntryType(HLERequestContext& ctx); + void Commit(HLERequestContext& ctx); + void GetFreeSpaceSize(HLERequestContext& ctx); + void GetTotalSpaceSize(HLERequestContext& ctx); + void GetFileTimeStampRaw(HLERequestContext& ctx); + void GetFileSystemAttribute(HLERequestContext& ctx); + +private: + VfsDirectoryServiceWrapper backend; + SizeGetter size; +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp new file mode 100644 index 000000000..98223c1f9 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/file_sys/errors.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/ipc_helpers.h" + +namespace Service::FileSystem { + +IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_) + : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { + static const FunctionInfo functions[] = { + {0, &IStorage::Read, "Read"}, + {1, nullptr, "Write"}, + {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, + {4, &IStorage::GetSize, "GetSize"}, + {5, nullptr, "OperateRange"}, + }; + RegisterHandlers(functions); +} + +void IStorage::Read(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const s64 offset = rp.Pop<s64>(); + const s64 length = rp.Pop<s64>(); + + LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); + + // Error checking + if (length < 0) { + LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidSize); + return; + } + if (offset < 0) { + LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultInvalidOffset); + return; + } + + // Read the data from the Storage backend + std::vector<u8> output = backend->ReadBytes(length, offset); + // Write the data to memory + ctx.WriteBuffer(output); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IStorage::GetSize(HLERequestContext& ctx) { + const u64 size = backend->GetSize(); + LOG_DEBUG(Service_FS, "called, size={}", size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(size); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h new file mode 100644 index 000000000..cb5bebcc9 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/service.h" + +namespace Service::FileSystem { + +class IStorage final : public ServiceFramework<IStorage> { +public: + explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_); + +private: + FileSys::VirtualFile backend; + + void Read(HLERequestContext& ctx); + void GetSize(HLERequestContext& ctx); +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp new file mode 100644 index 000000000..8ee733f47 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/filesystem/fsp/fsp_ldr.h" + +namespace Service::FileSystem { + +FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "OpenCodeFileSystem"}, + {1, nullptr, "IsArchivedProgram"}, + {2, nullptr, "SetCurrentProcess"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +FSP_LDR::~FSP_LDR() = default; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp/fsp_ldr.h index 358739a87..358739a87 100644 --- a/src/core/hle/service/filesystem/fsp_ldr.h +++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.h diff --git a/src/core/hle/service/filesystem/fsp/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp new file mode 100644 index 000000000..7c03ebaea --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/filesystem/fsp/fsp_pr.h" + +namespace Service::FileSystem { + +FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "RegisterProgram"}, + {1, nullptr, "UnregisterProgram"}, + {2, nullptr, "SetCurrentProcess"}, + {256, nullptr, "SetEnabledProgramVerification"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +FSP_PR::~FSP_PR() = default; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp/fsp_pr.h index bd4e0a730..bd4e0a730 100644 --- a/src/core/hle/service/filesystem/fsp_pr.h +++ b/src/core/hle/service/filesystem/fsp/fsp_pr.h diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp new file mode 100644 index 000000000..2be72b021 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp @@ -0,0 +1,727 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <cinttypes> +#include <cstring> +#include <iterator> +#include <string> +#include <utility> +#include <vector> + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/hex_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_directory.h" +#include "core/file_sys/fs_filesystem.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/patch_manager.h" +#include "core/file_sys/romfs_factory.h" +#include "core/file_sys/savedata_factory.h" +#include "core/file_sys/system_archive/system_archive.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/result.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h" +#include "core/hle/service/filesystem/fsp/fs_i_storage.h" +#include "core/hle/service/filesystem/fsp/fsp_srv.h" +#include "core/hle/service/filesystem/romfs_controller.h" +#include "core/hle/service/filesystem/save_data_controller.h" +#include "core/hle/service/hle_ipc.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/reporter.h" + +namespace Service::FileSystem { +enum class FileSystemType : u8 { + Invalid0 = 0, + Invalid1 = 1, + Logo = 2, + ContentControl = 3, + ContentManual = 4, + ContentMeta = 5, + ContentData = 6, + ApplicationPackage = 7, +}; + +class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { +public: + explicit ISaveDataInfoReader(Core::System& system_, + std::shared_ptr<SaveDataController> save_data_controller_, + FileSys::SaveDataSpaceId space) + : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{ + save_data_controller_} { + static const FunctionInfo functions[] = { + {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, + }; + RegisterHandlers(functions); + + FindAllSaves(space); + } + + void ReadSaveDataInfo(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>(); + + // Cap at total number of entries. + const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); + + // Determine data start and end + const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index); + const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries); + const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); + + next_entry_index += actual_entries; + + // Write the data to memory + ctx.WriteBuffer(begin, range_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(actual_entries); + } + +private: + static u64 stoull_be(std::string_view str) { + if (str.size() != 16) + return 0; + + const auto bytes = Common::HexStringToArray<0x8>(str); + u64 out{}; + std::memcpy(&out, bytes.data(), sizeof(u64)); + + return Common::swap64(out); + } + + void FindAllSaves(FileSys::SaveDataSpaceId space) { + FileSys::VirtualDir save_root{}; + const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space); + + if (result != ResultSuccess || save_root == nullptr) { + LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); + return; + } + + for (const auto& type : save_root->GetSubdirectories()) { + if (type->GetName() == "save") { + for (const auto& save_id : type->GetSubdirectories()) { + for (const auto& user_id : save_id->GetSubdirectories()) { + const auto save_id_numeric = stoull_be(save_id->GetName()); + auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + + if (save_id_numeric != 0) { + // System Save Data + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::SystemSaveData, + {}, + user_id_numeric, + save_id_numeric, + 0, + user_id->GetSize(), + {}, + {}, + }); + + continue; + } + + for (const auto& title_id : user_id->GetSubdirectories()) { + const auto device = + std::all_of(user_id_numeric.begin(), user_id_numeric.end(), + [](u8 val) { return val == 0; }); + info.emplace_back(SaveDataInfo{ + 0, + space, + device ? FileSys::SaveDataType::DeviceSaveData + : FileSys::SaveDataType::SaveData, + {}, + user_id_numeric, + save_id_numeric, + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + {}, + }); + } + } + } + } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { + // Temporary Storage + for (const auto& user_id : type->GetSubdirectories()) { + for (const auto& title_id : user_id->GetSubdirectories()) { + if (!title_id->GetFiles().empty() || + !title_id->GetSubdirectories().empty()) { + auto user_id_numeric = + Common::HexStringToArray<0x10>(user_id->GetName()); + std::reverse(user_id_numeric.begin(), user_id_numeric.end()); + + info.emplace_back(SaveDataInfo{ + 0, + space, + FileSys::SaveDataType::TemporaryStorage, + {}, + user_id_numeric, + stoull_be(type->GetName()), + stoull_be(title_id->GetName()), + title_id->GetSize(), + {}, + {}, + }); + } + } + } + } + } + } + + struct SaveDataInfo { + u64_le save_id_unknown; + FileSys::SaveDataSpaceId space; + FileSys::SaveDataType type; + INSERT_PADDING_BYTES(0x6); + std::array<u8, 0x10> user_id; + u64_le save_id; + u64_le title_id; + u64_le save_image_size; + u16_le index; + FileSys::SaveDataRank rank; + INSERT_PADDING_BYTES(0x25); + }; + static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); + + ProcessId process_id = 0; + std::shared_ptr<SaveDataController> save_data_controller; + std::vector<SaveDataInfo> info; + u64 next_entry_index = 0; +}; + +FSP_SRV::FSP_SRV(Core::System& system_) + : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, + content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "OpenFileSystem"}, + {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, + {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, + {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, + {8, nullptr, "OpenFileSystemWithId"}, + {9, nullptr, "OpenDataFileSystemByApplicationId"}, + {11, nullptr, "OpenBisFileSystem"}, + {12, nullptr, "OpenBisStorage"}, + {13, nullptr, "InvalidateBisCache"}, + {17, nullptr, "OpenHostFileSystem"}, + {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, + {19, nullptr, "FormatSdCardFileSystem"}, + {21, nullptr, "DeleteSaveDataFileSystem"}, + {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, + {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, + {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, + {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, + {26, nullptr, "FormatSdCardDryRun"}, + {27, nullptr, "IsExFatSupported"}, + {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"}, + {30, nullptr, "OpenGameCardStorage"}, + {31, nullptr, "OpenGameCardFileSystem"}, + {32, nullptr, "ExtendSaveDataFileSystem"}, + {33, nullptr, "DeleteCacheStorage"}, + {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, + {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, + {36, nullptr, "OpenHostFileSystemWithOption"}, + {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, + {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, + {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, + {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, + {58, nullptr, "ReadSaveDataFileSystemExtraData"}, + {59, nullptr, "WriteSaveDataFileSystemExtraData"}, + {60, nullptr, "OpenSaveDataInfoReader"}, + {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, + {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, + {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, + {65, nullptr, "UpdateSaveDataMacForDebug"}, + {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, + {67, nullptr, "FindSaveDataWithFilter"}, + {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, + {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, + {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, + {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, + {80, nullptr, "OpenSaveDataMetaFile"}, + {81, nullptr, "OpenSaveDataTransferManager"}, + {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, + {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"}, + {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, + {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, + {86, nullptr, "OpenSaveDataMover"}, + {87, nullptr, "OpenSaveDataTransferManagerForRepair"}, + {100, nullptr, "OpenImageDirectoryFileSystem"}, + {101, nullptr, "OpenBaseFileSystem"}, + {102, nullptr, "FormatBaseFileSystem"}, + {110, nullptr, "OpenContentStorageFileSystem"}, + {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, + {130, nullptr, "OpenCustomStorageFileSystem"}, + {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, + {201, nullptr, "OpenDataStorageByProgramId"}, + {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, + {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, + {204, nullptr, "OpenDataFileSystemByProgramIndex"}, + {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, + {206, nullptr, "OpenDataStorageByPath"}, + {400, nullptr, "OpenDeviceOperator"}, + {500, nullptr, "OpenSdCardDetectionEventNotifier"}, + {501, nullptr, "OpenGameCardDetectionEventNotifier"}, + {510, nullptr, "OpenSystemDataUpdateEventNotifier"}, + {511, nullptr, "NotifySystemDataUpdateEvent"}, + {520, nullptr, "SimulateGameCardDetectionEvent"}, + {600, nullptr, "SetCurrentPosixTime"}, + {601, nullptr, "QuerySaveDataTotalSize"}, + {602, nullptr, "VerifySaveDataFileSystem"}, + {603, nullptr, "CorruptSaveDataFileSystem"}, + {604, nullptr, "CreatePaddingFile"}, + {605, nullptr, "DeleteAllPaddingFiles"}, + {606, nullptr, "GetRightsId"}, + {607, nullptr, "RegisterExternalKey"}, + {608, nullptr, "UnregisterAllExternalKey"}, + {609, nullptr, "GetRightsIdByPath"}, + {610, nullptr, "GetRightsIdAndKeyGenerationByPath"}, + {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"}, + {612, nullptr, "GetFreeSpaceSizeForSaveData"}, + {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"}, + {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"}, + {615, nullptr, "QuerySaveDataInternalStorageTotalSize"}, + {616, nullptr, "GetSaveDataCommitId"}, + {617, nullptr, "UnregisterExternalKey"}, + {620, nullptr, "SetSdCardEncryptionSeed"}, + {630, nullptr, "SetSdCardAccessibility"}, + {631, nullptr, "IsSdCardAccessible"}, + {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"}, + {700, nullptr, "OpenAccessFailureResolver"}, + {701, nullptr, "GetAccessFailureDetectionEvent"}, + {702, nullptr, "IsAccessFailureDetected"}, + {710, nullptr, "ResolveAccessFailure"}, + {720, nullptr, "AbandonAccessFailure"}, + {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"}, + {810, nullptr, "RegisterProgramIndexMapInfo"}, + {1000, nullptr, "SetBisRootForHost"}, + {1001, nullptr, "SetSaveDataSize"}, + {1002, nullptr, "SetSaveDataRootPath"}, + {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, + {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, + {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, + {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, + {1007, nullptr, "RegisterUpdatePartition"}, + {1008, nullptr, "OpenRegisteredUpdatePartition"}, + {1009, nullptr, "GetAndClearMemoryReportInfo"}, + {1010, nullptr, "SetDataStorageRedirectTarget"}, + {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, + {1012, nullptr, "GetFsStackUsage"}, + {1013, nullptr, "UnsetSaveDataRootPath"}, + {1014, nullptr, "OutputMultiProgramTagAccessLog"}, + {1016, nullptr, "FlushAccessLogOnSdCard"}, + {1017, nullptr, "OutputApplicationInfoAccessLog"}, + {1018, nullptr, "SetDebugOption"}, + {1019, nullptr, "UnsetDebugOption"}, + {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, + {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, + {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, + {1300, nullptr, "OpenBisWiper"}, + }; + // clang-format on + RegisterHandlers(functions); + + if (Settings::values.enable_fs_access_log) { + access_log_mode = AccessLogMode::SdCard; + } +} + +FSP_SRV::~FSP_SRV() = default; + +void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { + current_process_id = ctx.GetPID(); + + LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); + + const auto res = + fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto type = rp.PopRaw<FileSystemType>(); + const auto title_id = rp.PopRaw<u64>(); + LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); + + IPC::ResponseBuilder rb{ctx, 2, 0, 0}; + rb.Push(ResultUnknown); +} + +void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + FileSys::VirtualDir sdmc_dir{}; + fsc.OpenSDMC(&sdmc_dir); + + auto filesystem = std::make_shared<IFileSystem>( + system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); +} + +void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>(); + [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); + u128 uid = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), + uid[1], uid[0]); + + FileSys::VirtualDir save_data_dir{}; + save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, + save_struct); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>(); + [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); + + LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); + + FileSys::VirtualDir save_data_dir{}; + save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, + save_struct); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + FileSys::SaveDataSpaceId space_id; + FileSys::SaveDataAttribute attribute; + }; + + const auto parameters = rp.PopRaw<Parameters>(); + + LOG_INFO(Service_FS, "called."); + + FileSys::VirtualDir dir{}; + auto result = + save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute); + if (result != ResultSuccess) { + IPC::ResponseBuilder rb{ctx, 2, 0, 0}; + rb.Push(FileSys::ResultTargetNotFound); + return; + } + + FileSys::StorageId id{}; + switch (parameters.space_id) { + case FileSys::SaveDataSpaceId::NandUser: + id = FileSys::StorageId::NandUser; + break; + case FileSys::SaveDataSpaceId::SdCardSystem: + case FileSys::SaveDataSpaceId::SdCardUser: + id = FileSys::StorageId::SdCard; + break; + case FileSys::SaveDataSpaceId::NandSystem: + id = FileSys::StorageId::NandSystem; + break; + case FileSys::SaveDataSpaceId::TemporaryStorage: + case FileSys::SaveDataSpaceId::ProperSystem: + case FileSys::SaveDataSpaceId::SafeMode: + ASSERT(false); + } + + auto filesystem = + std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); +} + +void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); + OpenSaveDataFileSystem(ctx); +} + +void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); + OpenSaveDataFileSystem(ctx); +} + +void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); + LOG_INFO(Service_FS, "called, space={}", space); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISaveDataInfoReader>( + std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space)); +} + +void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller, + FileSys::SaveDataSpaceId::TemporaryStorage); +} + +void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + struct Parameters { + FileSys::SaveDataSpaceId space_id; + FileSys::SaveDataAttribute attribute; + }; + + const auto parameters = rp.PopRaw<Parameters>(); + // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData + constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); + + LOG_WARNING(Service_FS, + "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" + "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" + "attribute.type={}, attribute.rank={}, attribute.index={}", + flags, parameters.space_id, parameters.attribute.title_id, + parameters.attribute.user_id[1], parameters.attribute.user_id[0], + parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, + parameters.attribute.index); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(flags); +} + +void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + if (!romfs) { + auto current_romfs = romfs_controller->OpenRomFSCurrentProcess(); + if (!current_romfs) { + // TODO (bunnei): Find the right error code to use here + LOG_CRITICAL(Service_FS, "no file system interface available!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + romfs = current_romfs; + } + + auto storage = std::make_shared<IStorage>(system, romfs); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(std::move(storage)); +} + +void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto storage_id = rp.PopRaw<FileSys::StorageId>(); + const auto unknown = rp.PopRaw<u32>(); + const auto title_id = rp.PopRaw<u64>(); + + LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", + storage_id, unknown, title_id); + + auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); + + if (!data) { + const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); + + if (archive != nullptr) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface(std::make_shared<IStorage>(system, archive)); + return; + } + + // TODO(DarkLordZach): Find the right error code to use here + LOG_ERROR(Service_FS, + "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, + storage_id); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + const FileSys::PatchManager pm{title_id, fsc, content_provider}; + + auto base = + romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); + auto storage = std::make_shared<IStorage>( + system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(std::move(storage)); +} + +void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto storage_id = rp.PopRaw<FileSys::StorageId>(); + const auto title_id = rp.PopRaw<u64>(); + + LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(FileSys::ResultTargetNotFound); +} + +void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto program_index = rp.PopRaw<u8>(); + + LOG_DEBUG(Service_FS, "called, program_index={}", program_index); + + auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex( + program_id, program_index, FileSys::ContentRecordType::Program); + + if (!patched_romfs) { + // TODO: Find the right error code to use here + LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } + + auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IStorage>(std::move(storage)); +} + +void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + save_data_controller->SetAutoCreate(false); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + access_log_mode = rp.PopEnum<AccessLogMode>(); + + LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(access_log_mode); +} + +void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { + const auto raw = ctx.ReadBufferCopy(); + auto log = Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast<const char*>(raw.data()), raw.size()); + + LOG_DEBUG(Service_FS, "called"); + + reporter.SaveFSAccessLog(log); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushEnum(AccessLogVersion::Latest); + rb.Push(access_log_program_index); +} + +void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto index{rp.Pop<s32>()}; + + LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.Push(s64{0}); + rb.Push(s64{0}); +} + +class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { +public: + explicit IMultiCommitManager(Core::System& system_) + : ServiceFramework{system_, "IMultiCommitManager"} { + static const FunctionInfo functions[] = { + {1, &IMultiCommitManager::Add, "Add"}, + {2, &IMultiCommitManager::Commit, "Commit"}, + }; + RegisterHandlers(functions); + } + +private: + FileSys::VirtualFile backend; + + void Add(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Commit(HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } +}; + +void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { + LOG_DEBUG(Service_FS, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h new file mode 100644 index 000000000..26980af99 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include "core/hle/service/service.h" + +namespace Core { +class Reporter; +} + +namespace FileSys { +class ContentProvider; +class FileSystemBackend; +} // namespace FileSys + +namespace Service::FileSystem { + +class RomFsController; +class SaveDataController; + +enum class AccessLogVersion : u32 { + V7_0_0 = 2, + + Latest = V7_0_0, +}; + +enum class AccessLogMode : u32 { + None, + Log, + SdCard, +}; + +class FSP_SRV final : public ServiceFramework<FSP_SRV> { +public: + explicit FSP_SRV(Core::System& system_); + ~FSP_SRV() override; + +private: + void SetCurrentProcess(HLERequestContext& ctx); + void OpenFileSystemWithPatch(HLERequestContext& ctx); + void OpenSdCardFileSystem(HLERequestContext& ctx); + void CreateSaveDataFileSystem(HLERequestContext& ctx); + void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); + void OpenSaveDataFileSystem(HLERequestContext& ctx); + void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); + void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); + void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); + void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); + void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); + void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); + void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); + void OpenDataStorageByDataId(HLERequestContext& ctx); + void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); + void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); + void DisableAutoSaveDataCreation(HLERequestContext& ctx); + void SetGlobalAccessLogMode(HLERequestContext& ctx); + void GetGlobalAccessLogMode(HLERequestContext& ctx); + void OutputAccessLogToSdCard(HLERequestContext& ctx); + void GetProgramIndexForAccessLog(HLERequestContext& ctx); + void OpenMultiCommitManager(HLERequestContext& ctx); + void GetCacheStorageSize(HLERequestContext& ctx); + + FileSystemController& fsc; + const FileSys::ContentProvider& content_provider; + const Core::Reporter& reporter; + + FileSys::VirtualFile romfs; + u64 current_process_id = 0; + u32 access_log_program_index = 0; + AccessLogMode access_log_mode = AccessLogMode::None; + u64 program_id = 0; + std::shared_ptr<SaveDataController> save_data_controller; + std::shared_ptr<RomFsController> romfs_controller; +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_util.h new file mode 100644 index 000000000..253f866db --- /dev/null +++ b/src/core/hle/service/filesystem/fsp/fsp_util.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/filesystem/filesystem.h" + +namespace Service::FileSystem { + +struct SizeGetter { + std::function<u64()> get_free_size; + std::function<u64()> get_total_size; + + static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { + return { + [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, + [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, + }; + } +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp deleted file mode 100644 index 1e3366e71..000000000 --- a/src/core/hle/service/filesystem/fsp_ldr.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/filesystem/fsp_ldr.h" - -namespace Service::FileSystem { - -FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "OpenCodeFileSystem"}, - {1, nullptr, "IsArchivedProgram"}, - {2, nullptr, "SetCurrentProcess"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -FSP_LDR::~FSP_LDR() = default; - -} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp deleted file mode 100644 index 4ffc31977..000000000 --- a/src/core/hle/service/filesystem/fsp_pr.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/filesystem/fsp_pr.h" - -namespace Service::FileSystem { - -FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "RegisterProgram"}, - {1, nullptr, "UnregisterProgram"}, - {2, nullptr, "SetCurrentProcess"}, - {256, nullptr, "SetEnabledProgramVerification"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -FSP_PR::~FSP_PR() = default; - -} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp deleted file mode 100644 index 82ecc1b90..000000000 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ /dev/null @@ -1,1250 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <cinttypes> -#include <cstring> -#include <iterator> -#include <string> -#include <utility> -#include <vector> - -#include "common/assert.h" -#include "common/common_types.h" -#include "common/hex_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/file_sys/directory.h" -#include "core/file_sys/errors.h" -#include "core/file_sys/mode.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/patch_manager.h" -#include "core/file_sys/romfs_factory.h" -#include "core/file_sys/savedata_factory.h" -#include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs.h" -#include "core/hle/result.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/filesystem/fsp_srv.h" -#include "core/hle/service/hle_ipc.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/reporter.h" - -namespace Service::FileSystem { - -struct SizeGetter { - std::function<u64()> get_free_size; - std::function<u64()> get_total_size; - - static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) { - return { - [&fsc, id] { return fsc.GetFreeSpaceSize(id); }, - [&fsc, id] { return fsc.GetTotalSpaceSize(id); }, - }; - } -}; - -enum class FileSystemType : u8 { - Invalid0 = 0, - Invalid1 = 1, - Logo = 2, - ContentControl = 3, - ContentManual = 4, - ContentMeta = 5, - ContentData = 6, - ApplicationPackage = 7, -}; - -class IStorage final : public ServiceFramework<IStorage> { -public: - explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IStorage::Read, "Read"}, - {1, nullptr, "Write"}, - {2, nullptr, "Flush"}, - {3, nullptr, "SetSize"}, - {4, &IStorage::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -class IFile final : public ServiceFramework<IFile> { -public: - explicit IFile(Core::System& system_, FileSys::VirtualFile backend_) - : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IFile::Read, "Read"}, - {1, &IFile::Write, "Write"}, - {2, &IFile::Flush, "Flush"}, - {3, &IFile::SetSize, "SetSize"}, - {4, &IFile::GetSize, "GetSize"}, - {5, nullptr, "OperateRange"}, - {6, nullptr, "OperateRangeWithBuffer"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Read(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - // Read the data from the Storage backend - std::vector<u8> output = backend->ReadBytes(length, offset); - - // Write the data to memory - ctx.WriteBuffer(output); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u64>(output.size())); - } - - void Write(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 option = rp.Pop<u64>(); - const s64 offset = rp.Pop<s64>(); - const s64 length = rp.Pop<s64>(); - - LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, - length); - - // Error checking - if (length < 0) { - LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_SIZE); - return; - } - if (offset < 0) { - LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_INVALID_OFFSET); - return; - } - - const auto data = ctx.ReadBuffer(); - - ASSERT_MSG( - static_cast<s64>(data.size()) <= length, - "Attempting to write more data than requested (requested={:016X}, actual={:016X}).", - length, data.size()); - - // Write the data to the Storage backend - const auto write_size = - static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length)); - const std::size_t written = backend->Write(data.data(), write_size, offset); - - ASSERT_MSG(static_cast<s64>(written) == length, - "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length, - written); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Flush(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - // Exists for SDK compatibiltity -- No need to flush file. - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void SetSize(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 size = rp.Pop<u64>(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - backend->Resize(size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetSize(HLERequestContext& ctx) { - const u64 size = backend->GetSize(); - LOG_DEBUG(Service_FS, "called, size={}", size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(size); - } -}; - -template <typename T> -static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, - FileSys::EntryType type) { - entries.reserve(entries.size() + new_data.size()); - - for (const auto& new_entry : new_data) { - auto name = new_entry->GetName(); - - if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) { - continue; - } - - entries.emplace_back(name, type, - type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); - } -} - -class IDirectory final : public ServiceFramework<IDirectory> { -public: - explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode) - : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) { - static const FunctionInfo functions[] = { - {0, &IDirectory::Read, "Read"}, - {1, &IDirectory::GetEntryCount, "GetEntryCount"}, - }; - RegisterHandlers(functions); - - // TODO(DarkLordZach): Verify that this is the correct behavior. - // Build entry index now to save time later. - if (True(mode & OpenDirectoryMode::Directory)) { - BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory); - } - if (True(mode & OpenDirectoryMode::File)) { - BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File); - } - } - -private: - FileSys::VirtualDir backend; - std::vector<FileSys::Entry> entries; - u64 next_entry_index = 0; - - void Read(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called."); - - // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>(); - - // Cap at total number of entries. - const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); - - // Determine data start and end - const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index); - const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries); - const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); - - next_entry_index += actual_entries; - - // Write the data to memory - ctx.WriteBuffer(begin, range_size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(actual_entries); - } - - void GetEntryCount(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - u64 count = entries.size() - next_entry_index; - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(count); - } -}; - -class IFileSystem final : public ServiceFramework<IFileSystem> { -public: - explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_) - : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move( - size_)} { - static const FunctionInfo functions[] = { - {0, &IFileSystem::CreateFile, "CreateFile"}, - {1, &IFileSystem::DeleteFile, "DeleteFile"}, - {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, - {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, - {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, - {5, &IFileSystem::RenameFile, "RenameFile"}, - {6, nullptr, "RenameDirectory"}, - {7, &IFileSystem::GetEntryType, "GetEntryType"}, - {8, &IFileSystem::OpenFile, "OpenFile"}, - {9, &IFileSystem::OpenDirectory, "OpenDirectory"}, - {10, &IFileSystem::Commit, "Commit"}, - {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"}, - {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"}, - {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"}, - {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"}, - {15, nullptr, "QueryEntry"}, - {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"}, - }; - RegisterHandlers(functions); - } - - void CreateFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const u64 file_mode = rp.Pop<u64>(); - const u32 file_size = rp.Pop<u32>(); - - LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode, - file_size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateFile(name, file_size)); - } - - void DeleteFile(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteFile(name)); - } - - void CreateDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CreateDirectory(name)); - } - - void DeleteDirectory(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectory(name)); - } - - void DeleteDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. directory={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.DeleteDirectoryRecursively(name)); - } - - void CleanDirectoryRecursively(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. Directory: {}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.CleanDirectoryRecursively(name)); - } - - void RenameFile(HLERequestContext& ctx) { - const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0)); - const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1)); - - LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(backend.RenameFile(src_name, dst_name)); - } - - void OpenFile(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); - - LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode); - - FileSys::VirtualFile vfs_file{}; - auto result = backend.OpenFile(&vfs_file, name, mode); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto file = std::make_shared<IFile>(system, vfs_file); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IFile>(std::move(file)); - } - - void OpenDirectory(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - const auto mode = rp.PopRaw<OpenDirectoryMode>(); - - LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode); - - FileSys::VirtualDir vfs_dir{}; - auto result = backend.OpenDirectory(&vfs_dir, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDirectory>(std::move(directory)); - } - - void GetEntryType(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_DEBUG(Service_FS, "called. file={}", name); - - FileSys::EntryType vfs_entry_type{}; - auto result = backend.GetEntryType(&vfs_entry_type, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(static_cast<u32>(vfs_entry_type)); - } - - void Commit(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void GetFreeSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_free_size()); - } - - void GetTotalSpaceSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(size.get_total_size()); - } - - void GetFileTimeStampRaw(HLERequestContext& ctx) { - const auto file_buffer = ctx.ReadBuffer(); - const std::string name = Common::StringFromBuffer(file_buffer); - - LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name); - - FileSys::FileTimeStampRaw vfs_timestamp{}; - auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(ResultSuccess); - rb.PushRaw(vfs_timestamp); - } - - void GetFileSystemAttribute(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - struct FileSystemAttribute { - u8 dir_entry_name_length_max_defined; - u8 file_entry_name_length_max_defined; - u8 dir_path_name_length_max_defined; - u8 file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x5); - u8 utf16_dir_entry_name_length_max_defined; - u8 utf16_file_entry_name_length_max_defined; - u8 utf16_dir_path_name_length_max_defined; - u8 utf16_file_path_name_length_max_defined; - INSERT_PADDING_BYTES_NOINIT(0x18); - s32 dir_entry_name_length_max; - s32 file_entry_name_length_max; - s32 dir_path_name_length_max; - s32 file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x5); - s32 utf16_dir_entry_name_length_max; - s32 utf16_file_entry_name_length_max; - s32 utf16_dir_path_name_length_max; - s32 utf16_file_path_name_length_max; - INSERT_PADDING_WORDS_NOINIT(0x18); - INSERT_PADDING_WORDS_NOINIT(0x1); - }; - static_assert(sizeof(FileSystemAttribute) == 0xc0, - "FileSystemAttribute has incorrect size"); - - FileSystemAttribute savedata_attribute{}; - savedata_attribute.dir_entry_name_length_max_defined = true; - savedata_attribute.file_entry_name_length_max_defined = true; - savedata_attribute.dir_entry_name_length_max = 0x40; - savedata_attribute.file_entry_name_length_max = 0x40; - - IPC::ResponseBuilder rb{ctx, 50}; - rb.Push(ResultSuccess); - rb.PushRaw(savedata_attribute); - } - -private: - VfsDirectoryServiceWrapper backend; - SizeGetter size; -}; - -class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { -public: - explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space, - FileSystemController& fsc_) - : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} { - static const FunctionInfo functions[] = { - {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, - }; - RegisterHandlers(functions); - - FindAllSaves(space); - } - - void ReadSaveDataInfo(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>(); - - // Cap at total number of entries. - const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); - - // Determine data start and end - const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index); - const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries); - const auto range_size = static_cast<std::size_t>(std::distance(begin, end)); - - next_entry_index += actual_entries; - - // Write the data to memory - ctx.WriteBuffer(begin, range_size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(actual_entries); - } - -private: - static u64 stoull_be(std::string_view str) { - if (str.size() != 16) - return 0; - - const auto bytes = Common::HexStringToArray<0x8>(str); - u64 out{}; - std::memcpy(&out, bytes.data(), sizeof(u64)); - - return Common::swap64(out); - } - - void FindAllSaves(FileSys::SaveDataSpaceId space) { - FileSys::VirtualDir save_root{}; - const auto result = fsc.OpenSaveDataSpace(&save_root, space); - - if (result != ResultSuccess || save_root == nullptr) { - LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space); - return; - } - - for (const auto& type : save_root->GetSubdirectories()) { - if (type->GetName() == "save") { - for (const auto& save_id : type->GetSubdirectories()) { - for (const auto& user_id : save_id->GetSubdirectories()) { - const auto save_id_numeric = stoull_be(save_id->GetName()); - auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName()); - std::reverse(user_id_numeric.begin(), user_id_numeric.end()); - - if (save_id_numeric != 0) { - // System Save Data - info.emplace_back(SaveDataInfo{ - 0, - space, - FileSys::SaveDataType::SystemSaveData, - {}, - user_id_numeric, - save_id_numeric, - 0, - user_id->GetSize(), - {}, - {}, - }); - - continue; - } - - for (const auto& title_id : user_id->GetSubdirectories()) { - const auto device = - std::all_of(user_id_numeric.begin(), user_id_numeric.end(), - [](u8 val) { return val == 0; }); - info.emplace_back(SaveDataInfo{ - 0, - space, - device ? FileSys::SaveDataType::DeviceSaveData - : FileSys::SaveDataType::SaveData, - {}, - user_id_numeric, - save_id_numeric, - stoull_be(title_id->GetName()), - title_id->GetSize(), - {}, - {}, - }); - } - } - } - } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) { - // Temporary Storage - for (const auto& user_id : type->GetSubdirectories()) { - for (const auto& title_id : user_id->GetSubdirectories()) { - if (!title_id->GetFiles().empty() || - !title_id->GetSubdirectories().empty()) { - auto user_id_numeric = - Common::HexStringToArray<0x10>(user_id->GetName()); - std::reverse(user_id_numeric.begin(), user_id_numeric.end()); - - info.emplace_back(SaveDataInfo{ - 0, - space, - FileSys::SaveDataType::TemporaryStorage, - {}, - user_id_numeric, - stoull_be(type->GetName()), - stoull_be(title_id->GetName()), - title_id->GetSize(), - {}, - {}, - }); - } - } - } - } - } - } - - struct SaveDataInfo { - u64_le save_id_unknown; - FileSys::SaveDataSpaceId space; - FileSys::SaveDataType type; - INSERT_PADDING_BYTES(0x6); - std::array<u8, 0x10> user_id; - u64_le save_id; - u64_le title_id; - u64_le save_image_size; - u16_le index; - FileSys::SaveDataRank rank; - INSERT_PADDING_BYTES(0x25); - }; - static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); - - FileSystemController& fsc; - std::vector<SaveDataInfo> info; - u64 next_entry_index = 0; -}; - -FSP_SRV::FSP_SRV(Core::System& system_) - : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()}, - content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "OpenFileSystem"}, - {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"}, - {2, nullptr, "OpenDataFileSystemByCurrentProcess"}, - {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"}, - {8, nullptr, "OpenFileSystemWithId"}, - {9, nullptr, "OpenDataFileSystemByApplicationId"}, - {11, nullptr, "OpenBisFileSystem"}, - {12, nullptr, "OpenBisStorage"}, - {13, nullptr, "InvalidateBisCache"}, - {17, nullptr, "OpenHostFileSystem"}, - {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"}, - {19, nullptr, "FormatSdCardFileSystem"}, - {21, nullptr, "DeleteSaveDataFileSystem"}, - {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"}, - {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"}, - {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"}, - {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"}, - {26, nullptr, "FormatSdCardDryRun"}, - {27, nullptr, "IsExFatSupported"}, - {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"}, - {30, nullptr, "OpenGameCardStorage"}, - {31, nullptr, "OpenGameCardFileSystem"}, - {32, nullptr, "ExtendSaveDataFileSystem"}, - {33, nullptr, "DeleteCacheStorage"}, - {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"}, - {35, nullptr, "CreateSaveDataFileSystemByHashSalt"}, - {36, nullptr, "OpenHostFileSystemWithOption"}, - {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"}, - {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"}, - {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"}, - {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"}, - {58, nullptr, "ReadSaveDataFileSystemExtraData"}, - {59, nullptr, "WriteSaveDataFileSystemExtraData"}, - {60, nullptr, "OpenSaveDataInfoReader"}, - {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, - {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"}, - {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, - {65, nullptr, "UpdateSaveDataMacForDebug"}, - {66, nullptr, "WriteSaveDataFileSystemExtraData2"}, - {67, nullptr, "FindSaveDataWithFilter"}, - {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, - {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, - {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, - {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, - {80, nullptr, "OpenSaveDataMetaFile"}, - {81, nullptr, "OpenSaveDataTransferManager"}, - {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, - {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"}, - {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"}, - {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"}, - {86, nullptr, "OpenSaveDataMover"}, - {87, nullptr, "OpenSaveDataTransferManagerForRepair"}, - {100, nullptr, "OpenImageDirectoryFileSystem"}, - {101, nullptr, "OpenBaseFileSystem"}, - {102, nullptr, "FormatBaseFileSystem"}, - {110, nullptr, "OpenContentStorageFileSystem"}, - {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"}, - {130, nullptr, "OpenCustomStorageFileSystem"}, - {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, - {201, nullptr, "OpenDataStorageByProgramId"}, - {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, - {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, - {204, nullptr, "OpenDataFileSystemByProgramIndex"}, - {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"}, - {206, nullptr, "OpenDataStorageByPath"}, - {400, nullptr, "OpenDeviceOperator"}, - {500, nullptr, "OpenSdCardDetectionEventNotifier"}, - {501, nullptr, "OpenGameCardDetectionEventNotifier"}, - {510, nullptr, "OpenSystemDataUpdateEventNotifier"}, - {511, nullptr, "NotifySystemDataUpdateEvent"}, - {520, nullptr, "SimulateGameCardDetectionEvent"}, - {600, nullptr, "SetCurrentPosixTime"}, - {601, nullptr, "QuerySaveDataTotalSize"}, - {602, nullptr, "VerifySaveDataFileSystem"}, - {603, nullptr, "CorruptSaveDataFileSystem"}, - {604, nullptr, "CreatePaddingFile"}, - {605, nullptr, "DeleteAllPaddingFiles"}, - {606, nullptr, "GetRightsId"}, - {607, nullptr, "RegisterExternalKey"}, - {608, nullptr, "UnregisterAllExternalKey"}, - {609, nullptr, "GetRightsIdByPath"}, - {610, nullptr, "GetRightsIdAndKeyGenerationByPath"}, - {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"}, - {612, nullptr, "GetFreeSpaceSizeForSaveData"}, - {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"}, - {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"}, - {615, nullptr, "QuerySaveDataInternalStorageTotalSize"}, - {616, nullptr, "GetSaveDataCommitId"}, - {617, nullptr, "UnregisterExternalKey"}, - {620, nullptr, "SetSdCardEncryptionSeed"}, - {630, nullptr, "SetSdCardAccessibility"}, - {631, nullptr, "IsSdCardAccessible"}, - {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"}, - {700, nullptr, "OpenAccessFailureResolver"}, - {701, nullptr, "GetAccessFailureDetectionEvent"}, - {702, nullptr, "IsAccessFailureDetected"}, - {710, nullptr, "ResolveAccessFailure"}, - {720, nullptr, "AbandonAccessFailure"}, - {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"}, - {810, nullptr, "RegisterProgramIndexMapInfo"}, - {1000, nullptr, "SetBisRootForHost"}, - {1001, nullptr, "SetSaveDataSize"}, - {1002, nullptr, "SetSaveDataRootPath"}, - {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"}, - {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"}, - {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, - {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"}, - {1007, nullptr, "RegisterUpdatePartition"}, - {1008, nullptr, "OpenRegisteredUpdatePartition"}, - {1009, nullptr, "GetAndClearMemoryReportInfo"}, - {1010, nullptr, "SetDataStorageRedirectTarget"}, - {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"}, - {1012, nullptr, "GetFsStackUsage"}, - {1013, nullptr, "UnsetSaveDataRootPath"}, - {1014, nullptr, "OutputMultiProgramTagAccessLog"}, - {1016, nullptr, "FlushAccessLogOnSdCard"}, - {1017, nullptr, "OutputApplicationInfoAccessLog"}, - {1018, nullptr, "SetDebugOption"}, - {1019, nullptr, "UnsetDebugOption"}, - {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, - {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, - {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, - {1300, nullptr, "OpenBisWiper"}, - }; - // clang-format on - RegisterHandlers(functions); - - if (Settings::values.enable_fs_access_log) { - access_log_mode = AccessLogMode::SdCard; - } - - // This should be true on creation - fsc.SetAutoSaveDataCreation(true); -} - -FSP_SRV::~FSP_SRV() = default; - -void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - current_process_id = rp.Pop<u64>(); - - LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto type = rp.PopRaw<FileSystemType>(); - const auto title_id = rp.PopRaw<u64>(); - LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); - - IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultUnknown); -} - -void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - FileSys::VirtualDir sdmc_dir{}; - fsc.OpenSDMC(&sdmc_dir); - - auto filesystem = std::make_shared<IFileSystem>( - system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); -} - -void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>(); - [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); - u128 uid = rp.PopRaw<u128>(); - - LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(), - uid[1], uid[0]); - - FileSys::VirtualDir save_data_dir{}; - fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>(); - [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); - - LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo()); - - FileSys::VirtualDir save_data_dir{}; - fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - struct Parameters { - FileSys::SaveDataSpaceId space_id; - FileSys::SaveDataAttribute attribute; - }; - - const auto parameters = rp.PopRaw<Parameters>(); - - LOG_INFO(Service_FS, "called."); - - FileSys::VirtualDir dir{}; - auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute); - if (result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); - return; - } - - FileSys::StorageId id{}; - switch (parameters.space_id) { - case FileSys::SaveDataSpaceId::NandUser: - id = FileSys::StorageId::NandUser; - break; - case FileSys::SaveDataSpaceId::SdCardSystem: - case FileSys::SaveDataSpaceId::SdCardUser: - id = FileSys::StorageId::SdCard; - break; - case FileSys::SaveDataSpaceId::NandSystem: - id = FileSys::StorageId::NandSystem; - break; - case FileSys::SaveDataSpaceId::TemporaryStorage: - case FileSys::SaveDataSpaceId::ProperSystem: - case FileSys::SaveDataSpaceId::SafeMode: - ASSERT(false); - } - - auto filesystem = - std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IFileSystem>(std::move(filesystem)); -} - -void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); - OpenSaveDataFileSystem(ctx); -} - -void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem"); - OpenSaveDataFileSystem(ctx); -} - -void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); - LOG_INFO(Service_FS, "called, space={}", space); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISaveDataInfoReader>( - std::make_shared<ISaveDataInfoReader>(system, space, fsc)); -} - -void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage, - fsc); -} - -void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called."); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - struct Parameters { - FileSys::SaveDataSpaceId space_id; - FileSys::SaveDataAttribute attribute; - }; - - const auto parameters = rp.PopRaw<Parameters>(); - // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData - constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None); - - LOG_WARNING(Service_FS, - "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" - "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" - "attribute.type={}, attribute.rank={}, attribute.index={}", - flags, parameters.space_id, parameters.attribute.title_id, - parameters.attribute.user_id[1], parameters.attribute.user_id[0], - parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank, - parameters.attribute.index); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(flags); -} - -void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - if (!romfs) { - auto current_romfs = fsc.OpenRomFSCurrentProcess(); - if (!current_romfs) { - // TODO (bunnei): Find the right error code to use here - LOG_CRITICAL(Service_FS, "no file system interface available!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - romfs = current_romfs; - } - - auto storage = std::make_shared<IStorage>(system, romfs); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(std::move(storage)); -} - -void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto storage_id = rp.PopRaw<FileSys::StorageId>(); - const auto unknown = rp.PopRaw<u32>(); - const auto title_id = rp.PopRaw<u64>(); - - LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", - storage_id, unknown, title_id); - - auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); - - if (!data) { - const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); - - if (archive != nullptr) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface(std::make_shared<IStorage>(system, archive)); - return; - } - - // TODO(DarkLordZach): Find the right error code to use here - LOG_ERROR(Service_FS, - "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, - storage_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - const FileSys::PatchManager pm{title_id, fsc, content_provider}; - - auto base = fsc.OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data); - auto storage = std::make_shared<IStorage>( - system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(std::move(storage)); -} - -void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto storage_id = rp.PopRaw<FileSys::StorageId>(); - const auto title_id = rp.PopRaw<u64>(); - - LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); -} - -void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto program_index = rp.PopRaw<u8>(); - - LOG_DEBUG(Service_FS, "called, program_index={}", program_index); - - auto patched_romfs = - fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index, - FileSys::ContentRecordType::Program); - - if (!patched_romfs) { - // TODO: Find the right error code to use here - LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs)); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IStorage>(std::move(storage)); -} - -void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - fsc.SetAutoSaveDataCreation(false); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - access_log_mode = rp.PopEnum<AccessLogMode>(); - - LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(access_log_mode); -} - -void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) { - const auto raw = ctx.ReadBufferCopy(); - auto log = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast<const char*>(raw.data()), raw.size()); - - LOG_DEBUG(Service_FS, "called"); - - reporter.SaveFSAccessLog(log); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushEnum(AccessLogVersion::Latest); - rb.Push(access_log_program_index); -} - -void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto index{rp.Pop<s32>()}; - - LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(s64{0}); - rb.Push(s64{0}); -} - -class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { -public: - explicit IMultiCommitManager(Core::System& system_) - : ServiceFramework{system_, "IMultiCommitManager"} { - static const FunctionInfo functions[] = { - {1, &IMultiCommitManager::Add, "Add"}, - {2, &IMultiCommitManager::Commit, "Commit"}, - }; - RegisterHandlers(functions); - } - -private: - FileSys::VirtualFile backend; - - void Add(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void Commit(HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } -}; - -void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) { - LOG_DEBUG(Service_FS, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system)); -} - -} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h deleted file mode 100644 index 280bc9867..000000000 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> -#include "core/hle/service/service.h" - -namespace Core { -class Reporter; -} - -namespace FileSys { -class ContentProvider; -class FileSystemBackend; -} // namespace FileSys - -namespace Service::FileSystem { - -enum class AccessLogVersion : u32 { - V7_0_0 = 2, - - Latest = V7_0_0, -}; - -enum class AccessLogMode : u32 { - None, - Log, - SdCard, -}; - -class FSP_SRV final : public ServiceFramework<FSP_SRV> { -public: - explicit FSP_SRV(Core::System& system_); - ~FSP_SRV() override; - -private: - void SetCurrentProcess(HLERequestContext& ctx); - void OpenFileSystemWithPatch(HLERequestContext& ctx); - void OpenSdCardFileSystem(HLERequestContext& ctx); - void CreateSaveDataFileSystem(HLERequestContext& ctx); - void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); - void OpenSaveDataFileSystem(HLERequestContext& ctx); - void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx); - void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx); - void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx); - void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx); - void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx); - void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx); - void OpenDataStorageByCurrentProcess(HLERequestContext& ctx); - void OpenDataStorageByDataId(HLERequestContext& ctx); - void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx); - void OpenDataStorageWithProgramIndex(HLERequestContext& ctx); - void DisableAutoSaveDataCreation(HLERequestContext& ctx); - void SetGlobalAccessLogMode(HLERequestContext& ctx); - void GetGlobalAccessLogMode(HLERequestContext& ctx); - void OutputAccessLogToSdCard(HLERequestContext& ctx); - void GetProgramIndexForAccessLog(HLERequestContext& ctx); - void OpenMultiCommitManager(HLERequestContext& ctx); - void GetCacheStorageSize(HLERequestContext& ctx); - - FileSystemController& fsc; - const FileSys::ContentProvider& content_provider; - const Core::Reporter& reporter; - - FileSys::VirtualFile romfs; - u64 current_process_id = 0; - u32 access_log_program_index = 0; - AccessLogMode access_log_mode = AccessLogMode::None; -}; - -} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/romfs_controller.cpp b/src/core/hle/service/filesystem/romfs_controller.cpp new file mode 100644 index 000000000..19c9cec72 --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.cpp @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/filesystem/romfs_controller.h" + +namespace Service::FileSystem { + +RomFsController::RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_) + : factory{std::move(factory_)}, program_id{program_id_} {} +RomFsController::~RomFsController() = default; + +FileSys::VirtualFile RomFsController::OpenRomFSCurrentProcess() { + return factory->OpenCurrentProcess(program_id); +} + +FileSys::VirtualFile RomFsController::OpenPatchedRomFS(u64 title_id, + FileSys::ContentRecordType type) { + return factory->OpenPatchedRomFS(title_id, type); +} + +FileSys::VirtualFile RomFsController::OpenPatchedRomFSWithProgramIndex( + u64 title_id, u8 program_index, FileSys::ContentRecordType type) { + return factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type); +} + +FileSys::VirtualFile RomFsController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id, + FileSys::ContentRecordType type) { + return factory->Open(title_id, storage_id, type); +} + +std::shared_ptr<FileSys::NCA> RomFsController::OpenBaseNca(u64 title_id, + FileSys::StorageId storage_id, + FileSys::ContentRecordType type) { + return factory->GetEntry(title_id, storage_id, type); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h new file mode 100644 index 000000000..3c3ead344 --- /dev/null +++ b/src/core/hle/service/filesystem/romfs_controller.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/romfs_factory.h" +#include "core/file_sys/vfs/vfs_types.h" + +namespace Service::FileSystem { + +class RomFsController { +public: + explicit RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_); + ~RomFsController(); + + FileSys::VirtualFile OpenRomFSCurrentProcess(); + FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type); + FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index, + FileSys::ContentRecordType type); + FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id, + FileSys::ContentRecordType type); + std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id, + FileSys::ContentRecordType type); + +private: + const std::shared_ptr<FileSys::RomFSFactory> factory; + const u64 program_id; +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp new file mode 100644 index 000000000..03e45f7f9 --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.cpp @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/patch_manager.h" +#include "core/hle/service/filesystem/save_data_controller.h" +#include "core/loader/loader.h" + +namespace Service::FileSystem { + +namespace { + +// A default size for normal/journal save data size if application control metadata cannot be found. +// This should be large enough to satisfy even the most extreme requirements (~4.2GB) +constexpr u64 SufficientSaveDataSize = 0xF0000000; + +FileSys::SaveDataSize GetDefaultSaveDataSize(Core::System& system, u64 program_id) { + const FileSys::PatchManager pm{program_id, system.GetFileSystemController(), + system.GetContentProvider()}; + const auto metadata = pm.GetControlMetadata(); + const auto& nacp = metadata.first; + + if (nacp != nullptr) { + return {nacp->GetDefaultNormalSaveSize(), nacp->GetDefaultJournalSaveSize()}; + } + + return {SufficientSaveDataSize, SufficientSaveDataSize}; +} + +} // namespace + +SaveDataController::SaveDataController(Core::System& system_, + std::shared_ptr<FileSys::SaveDataFactory> factory_) + : system{system_}, factory{std::move(factory_)} {} +SaveDataController::~SaveDataController() = default; + +Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data, + FileSys::SaveDataSpaceId space, + const FileSys::SaveDataAttribute& attribute) { + LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space, + attribute.DebugInfo()); + + auto save_data = factory->Create(space, attribute); + if (save_data == nullptr) { + return FileSys::ResultTargetNotFound; + } + + *out_save_data = save_data; + return ResultSuccess; +} + +Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data, + FileSys::SaveDataSpaceId space, + const FileSys::SaveDataAttribute& attribute) { + auto save_data = factory->Open(space, attribute); + if (save_data == nullptr) { + return FileSys::ResultTargetNotFound; + } + + *out_save_data = save_data; + return ResultSuccess; +} + +Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, + FileSys::SaveDataSpaceId space) { + auto save_data_space = factory->GetSaveDataSpaceDirectory(space); + if (save_data_space == nullptr) { + return FileSys::ResultTargetNotFound; + } + + *out_save_data_space = save_data_space; + return ResultSuccess; +} + +FileSys::SaveDataSize SaveDataController::ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, + u128 user_id) { + const auto value = factory->ReadSaveDataSize(type, title_id, user_id); + + if (value.normal == 0 && value.journal == 0) { + const auto size = GetDefaultSaveDataSize(system, title_id); + factory->WriteSaveDataSize(type, title_id, user_id, size); + return size; + } + + return value; +} + +void SaveDataController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value) { + factory->WriteSaveDataSize(type, title_id, user_id, new_value); +} + +void SaveDataController::SetAutoCreate(bool state) { + factory->SetAutoCreate(state); +} + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h new file mode 100644 index 000000000..dc9d713df --- /dev/null +++ b/src/core/hle/service/filesystem/save_data_controller.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/savedata_factory.h" +#include "core/file_sys/vfs/vfs_types.h" + +namespace Service::FileSystem { + +class SaveDataController { +public: + explicit SaveDataController(Core::System& system, + std::shared_ptr<FileSys::SaveDataFactory> factory_); + ~SaveDataController(); + + Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, + const FileSys::SaveDataAttribute& attribute); + Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space, + const FileSys::SaveDataAttribute& attribute); + Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space, + FileSys::SaveDataSpaceId space); + + FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); + void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, + FileSys::SaveDataSize new_value); + void SetAutoCreate(bool state); + +private: + Core::System& system; + const std::shared_ptr<FileSys::SaveDataFactory> factory; +}; + +} // namespace Service::FileSystem diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 0507b14e7..aeb849efa 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -131,7 +131,7 @@ private: u8 is_favorite; u8 same_app; u8 same_app_played; - u8 arbitary_app_played; + u8 arbitrary_app_played; u64 group_id; }; static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp index 6f1151b03..1254b6d49 100644 --- a/src/core/hle/service/glue/arp.cpp +++ b/src/core/hle/service/glue/arp.cpp @@ -15,9 +15,10 @@ namespace Service::Glue { namespace { -std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) { - const auto& list = system.Kernel().GetProcessList(); - const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { +std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { + auto list = system.Kernel().GetProcessList(); + + const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) { return process->GetProcessId() == process_id; }); diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp index 993c3d21d..10376bfac 100644 --- a/src/core/hle/service/glue/glue.cpp +++ b/src/core/hle/service/glue/glue.cpp @@ -8,6 +8,9 @@ #include "core/hle/service/glue/ectx.h" #include "core/hle/service/glue/glue.h" #include "core/hle/service/glue/notif.h" +#include "core/hle/service/glue/time/manager.h" +#include "core/hle/service/glue/time/static.h" +#include "core/hle/service/psc/time/common.h" #include "core/hle/service/server_manager.h" namespace Service::Glue { @@ -31,6 +34,22 @@ void LoopProcess(Core::System& system) { // Notification Services for application server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system)); + // Time + auto time = std::make_shared<Time::TimeManager>(system); + + server_manager->RegisterNamedService( + "time:u", + std::make_shared<Time::StaticService>( + system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, time, "time:u")); + server_manager->RegisterNamedService( + "time:a", + std::make_shared<Time::StaticService>( + system, Service::PSC::Time::StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, time, "time:a")); + server_manager->RegisterNamedService( + "time:r", + std::make_shared<Time::StaticService>( + system, Service::PSC::Time::StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, time, "time:r")); + ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/glue/time/alarm_worker.cpp b/src/core/hle/service/glue/time/alarm_worker.cpp new file mode 100644 index 000000000..f549ed00a --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.cpp @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/service/glue/time/alarm_worker.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Glue::Time { + +AlarmWorker::AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource) + : m_system{system}, m_ctx{system, "Glue:AlarmWorker"}, m_steady_clock_resource{ + steady_clock_resource} {} + +AlarmWorker::~AlarmWorker() { + m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); + + m_ctx.CloseEvent(m_timer_event); +} + +void AlarmWorker::Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m) { + m_time_m = std::move(time_m); + + m_timer_event = m_ctx.CreateEvent("Glue:AlarmWorker:TimerEvent"); + m_timer_timing_event = Core::Timing::CreateEvent( + "Glue:AlarmWorker::AlarmTimer", + [this](s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { + m_timer_event->Signal(); + return std::nullopt; + }); + + AttachToClosestAlarmEvent(); +} + +bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, + s64& out_time) { + bool is_valid{}; + Service::PSC::Time::AlarmInfo alarm_info{}; + s64 closest_time{}; + + auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time); + ASSERT(res == ResultSuccess); + + if (is_valid) { + out_alarm_info = alarm_info; + out_time = closest_time; + } + + return is_valid; +} + +void AlarmWorker::OnPowerStateChanged() { + Service::PSC::Time::AlarmInfo closest_alarm_info{}; + s64 closest_time{}; + if (!GetClosestAlarmInfo(closest_alarm_info, closest_time)) { + m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); + m_timer_event->Clear(); + return; + } + + if (closest_alarm_info.alert_time <= closest_time) { + m_time_m->CheckAndSignalAlarms(); + } else { + auto next_time{closest_alarm_info.alert_time - closest_time}; + + m_system.CoreTiming().UnscheduleEvent(m_timer_timing_event); + m_timer_event->Clear(); + + m_system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds(next_time), + m_timer_timing_event); + } +} + +Result AlarmWorker::AttachToClosestAlarmEvent() { + m_time_m->GetClosestAlarmUpdatedEvent(&m_event); + R_SUCCEED(); +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/alarm_worker.h b/src/core/hle/service/glue/time/alarm_worker.h new file mode 100644 index 000000000..f269cffdb --- /dev/null +++ b/src/core/hle/service/glue/time/alarm_worker.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class ServiceManager; +} + +namespace Service::Glue::Time { +class StandardSteadyClockResource; + +class AlarmWorker { +public: + explicit AlarmWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource); + ~AlarmWorker(); + + void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m); + + Kernel::KEvent& GetEvent() { + return *m_event; + } + + Kernel::KEvent& GetTimerEvent() { + return *m_timer_event; + } + + void OnPowerStateChanged(); + +private: + bool GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_info, s64& out_time); + Result AttachToClosestAlarmEvent(); + + Core::System& m_system; + KernelHelpers::ServiceContext m_ctx; + std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; + + Kernel::KEvent* m_event{}; + Kernel::KEvent* m_timer_event{}; + std::shared_ptr<Core::Timing::EventType> m_timer_timing_event; + StandardSteadyClockResource& m_steady_clock_resource; +}; + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.cpp b/src/core/hle/service/glue/time/file_timestamp_worker.cpp new file mode 100644 index 000000000..5a6309549 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.cpp @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/glue/time/file_timestamp_worker.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/psc/time/time_zone_service.h" + +namespace Service::Glue::Time { + +void FileTimestampWorker::SetFilesystemPosixTime() { + s64 time{}; + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo additional_info{}; + + if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess && + m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) == + ResultSuccess) { + // TODO IFileSystemProxy::SetCurrentPosixTime + } +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.h b/src/core/hle/service/glue/time/file_timestamp_worker.h new file mode 100644 index 000000000..5f8b9b049 --- /dev/null +++ b/src/core/hle/service/glue/time/file_timestamp_worker.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> + +#include "common/common_types.h" + +namespace Service::PSC::Time { +class SystemClock; +class TimeZoneService; +} // namespace Service::PSC::Time + +namespace Service::Glue::Time { + +class FileTimestampWorker { +public: + FileTimestampWorker() = default; + + void SetFilesystemPosixTime(); + + std::shared_ptr<Service::PSC::Time::SystemClock> m_system_clock{}; + std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone{}; + bool m_initialized{}; +}; + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp new file mode 100644 index 000000000..b56762941 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.cpp @@ -0,0 +1,277 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "core/core.h" +#include "core/core_timing.h" + +#include "common/settings.h" +#include "common/time_zone.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/service/glue/time/manager.h" +#include "core/hle/service/glue/time/time_zone_binary.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/psc/time/static.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/psc/time/time_zone_service.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Glue::Time { +namespace { + +template <typename T> +T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, + const char* category, const char* name) { + std::vector<u8> interval_buf; + auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); + ASSERT(res == ResultSuccess); + + T v{}; + std::memcpy(&v, interval_buf.data(), sizeof(T)); + return v; +} + +s64 CalendarTimeToEpoch(Service::PSC::Time::CalendarTime calendar) { + constexpr auto is_leap = [](s32 year) -> bool { + return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0)); + }; + constexpr std::array<s32, 12> MonthStartDayOfYear{ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + }; + + s16 month_s16{calendar.month}; + s8 month{static_cast<s8>(((month_s16 * 43) & ~std::numeric_limits<s16>::max()) + + ((month_s16 * 43) >> 9))}; + s8 month_index{static_cast<s8>(calendar.month - 12 * month)}; + if (month_index == 0) { + month_index = 12; + } + s32 year{(month + calendar.year) - !month_index}; + s32 v8{year >= 0 ? year : year + 3}; + + s64 days_since_epoch = calendar.day + MonthStartDayOfYear[month_index - 1]; + days_since_epoch += (year * 365) + (v8 / 4) - (year / 100) + (year / 400) - 365; + + if (month_index <= 2 && is_leap(year)) { + days_since_epoch--; + } + auto epoch_s{((24ll * days_since_epoch + calendar.hour) * 60ll + calendar.minute) * 60ll + + calendar.second}; + return epoch_s - 62135683200ll; +} + +s64 GetEpochTimeFromInitialYear(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys) { + Service::PSC::Time::CalendarTime calendar{ + .year = GetSettingsItemValue<s16>(set_sys, "time", "standard_user_clock_initial_year"), + .month = 1, + .day = 1, + .hour = 0, + .minute = 0, + .second = 0, + }; + return CalendarTimeToEpoch(calendar); +} + +Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationName& in_name) { + auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); + + Service::PSC::Time::LocationName configured_name{}; + std::memcpy(configured_name.name.data(), configured_zone.data(), + std::min(configured_name.name.size(), configured_zone.size())); + + if (!IsTimeZoneBinaryValid(configured_name)) { + configured_zone = Common::TimeZone::FindSystemTimeZone(); + configured_name = {}; + std::memcpy(configured_name.name.data(), configured_zone.data(), + std::min(configured_name.name.size(), configured_zone.size())); + } + + ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!", + configured_name.name.data()); + + return configured_name; +} + +} // namespace + +TimeManager::TimeManager(Core::System& system) + : m_steady_clock_resource{system}, m_worker{system, m_steady_clock_resource, + m_file_timestamp_worker} { + m_time_m = + system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); + + auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm); + ASSERT(res == ResultSuccess); + + m_set_sys = + system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); + + res = MountTimeZoneBinary(system); + ASSERT(res == ResultSuccess); + + m_worker.Initialize(m_time_sm, m_set_sys); + + res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock); + ASSERT(res == ResultSuccess); + + res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone); + ASSERT(res == ResultSuccess); + + res = SetupStandardSteadyClockCore(); + ASSERT(res == ResultSuccess); + + Service::PSC::Time::SystemClockContext user_clock_context{}; + res = m_set_sys->GetUserSystemClockContext(user_clock_context); + ASSERT(res == ResultSuccess); + + // TODO the local clock should initialise with this epoch time, and be updated somewhere else on + // first boot to update it, but I haven't been able to find that point (likely via ntc's auto + // correct as it's defaulted to be enabled). So to get a time that isn't stuck in the past for + // first boot, grab the current real seconds. + auto epoch_time{GetEpochTimeFromInitialYear(m_set_sys)}; + if (user_clock_context == Service::PSC::Time::SystemClockContext{}) { + m_steady_clock_resource.GetRtcTimeInSeconds(epoch_time); + } + + res = m_time_m->SetupStandardLocalSystemClockCore(user_clock_context, epoch_time); + ASSERT(res == ResultSuccess); + + Service::PSC::Time::SystemClockContext network_clock_context{}; + res = m_set_sys->GetNetworkSystemClockContext(network_clock_context); + ASSERT(res == ResultSuccess); + + auto network_accuracy_m{GetSettingsItemValue<s32>( + m_set_sys, "time", "standard_network_clock_sufficient_accuracy_minutes")}; + auto one_minute_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; + s64 network_accuracy_ns{network_accuracy_m * one_minute_ns}; + + res = m_time_m->SetupStandardNetworkSystemClockCore(network_clock_context, network_accuracy_ns); + ASSERT(res == ResultSuccess); + + bool is_automatic_correction_enabled{}; + res = m_set_sys->IsUserSystemClockAutomaticCorrectionEnabled(is_automatic_correction_enabled); + ASSERT(res == ResultSuccess); + + Service::PSC::Time::SteadyClockTimePoint automatic_correction_time_point{}; + res = m_set_sys->GetUserSystemClockAutomaticCorrectionUpdatedTime( + automatic_correction_time_point); + ASSERT(res == ResultSuccess); + + res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point, + is_automatic_correction_enabled); + ASSERT(res == ResultSuccess); + + res = m_time_m->SetupEphemeralNetworkSystemClockCore(); + ASSERT(res == ResultSuccess); + + res = SetupTimeZoneServiceCore(); + ASSERT(res == ResultSuccess); + + s64 rtc_time_s{}; + res = m_steady_clock_resource.GetRtcTimeInSeconds(rtc_time_s); + ASSERT(res == ResultSuccess); + + // TODO system report "launch" + // "rtc_reset" = m_steady_clock_resource.m_rtc_reset + // "rtc_value" = rtc_time_s + + m_worker.StartThread(); + + m_file_timestamp_worker.m_initialized = true; + + s64 system_clock_time{}; + if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) == + ResultSuccess) { + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo calendar_additional{}; + if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule( + calendar_time, calendar_additional, system_clock_time) == ResultSuccess) { + // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time, + // calendar_additional.ut_offset) + } + } +} + +Result TimeManager::SetupStandardSteadyClockCore() { + Common::UUID external_clock_source_id{}; + auto res = m_set_sys->GetExternalSteadyClockSourceId(external_clock_source_id); + ASSERT(res == ResultSuccess); + + s64 external_steady_clock_internal_offset_s{}; + res = m_set_sys->GetExternalSteadyClockInternalOffset(external_steady_clock_internal_offset_s); + ASSERT(res == ResultSuccess); + + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + s64 external_steady_clock_internal_offset_ns{external_steady_clock_internal_offset_s * + one_second_ns}; + + s32 standard_steady_clock_test_offset_m{ + GetSettingsItemValue<s32>(m_set_sys, "time", "standard_steady_clock_test_offset_minutes")}; + auto one_minute_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; + s64 standard_steady_clock_test_offset_ns{standard_steady_clock_test_offset_m * one_minute_ns}; + + auto reset_detected = m_steady_clock_resource.GetResetDetected(); + if (reset_detected) { + external_clock_source_id = {}; + } + + Common::UUID clock_source_id{}; + m_steady_clock_resource.Initialize(&clock_source_id, &external_clock_source_id); + + if (clock_source_id != external_clock_source_id) { + m_set_sys->SetExternalSteadyClockSourceId(clock_source_id); + } + + res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(), + external_steady_clock_internal_offset_ns, + standard_steady_clock_test_offset_ns, + reset_detected); + ASSERT(res == ResultSuccess); + R_SUCCEED(); +} + +Result TimeManager::SetupTimeZoneServiceCore() { + Service::PSC::Time::LocationName name{}; + auto res = m_set_sys->GetDeviceTimeZoneLocationName(name); + ASSERT(res == ResultSuccess); + + auto configured_zone = GetTimeZoneString(name); + + if (configured_zone.name != name.name) { + m_set_sys->SetDeviceTimeZoneLocationName(configured_zone); + name = configured_zone; + + std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; + m_time_sm->GetStandardLocalSystemClock(local_clock); + Service::PSC::Time::SystemClockContext context{}; + local_clock->GetSystemClockContext(context); + m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point); + } + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + res = m_set_sys->GetDeviceTimeZoneLocationUpdatedTime(time_point); + ASSERT(res == ResultSuccess); + + auto location_count = GetTimeZoneCount(); + Service::PSC::Time::RuleVersion rule_version{}; + GetTimeZoneVersion(rule_version); + + std::span<const u8> rule_buffer{}; + size_t rule_size{}; + res = GetTimeZoneRule(rule_buffer, rule_size, name); + ASSERT(res == ResultSuccess); + + res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count, + rule_buffer); + ASSERT(res == ResultSuccess); + + R_SUCCEED(); +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/manager.h b/src/core/hle/service/glue/time/manager.h new file mode 100644 index 000000000..1de93f8f9 --- /dev/null +++ b/src/core/hle/service/glue/time/manager.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <functional> +#include <string> + +#include "common/common_types.h" +#include "core/file_sys/vfs/vfs_types.h" +#include "core/hle/service/glue/time/file_timestamp_worker.h" +#include "core/hle/service/glue/time/standard_steady_clock_resource.h" +#include "core/hle/service/glue/time/worker.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class ServiceManager; +class StaticService; +} // namespace Service::PSC::Time + +namespace Service::Glue::Time { +class TimeManager { +public: + explicit TimeManager(Core::System& system); + + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; + + std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m{}; + std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm{}; + StandardSteadyClockResource m_steady_clock_resource; + FileTimestampWorker m_file_timestamp_worker; + TimeWorker m_worker; + +private: + Result SetupStandardSteadyClockCore(); + Result SetupTimeZoneServiceCore(); +}; +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.cpp b/src/core/hle/service/glue/time/pm_state_change_handler.cpp new file mode 100644 index 000000000..7470fb225 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.cpp @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/glue/time/pm_state_change_handler.h" + +namespace Service::Glue::Time { + +PmStateChangeHandler::PmStateChangeHandler(AlarmWorker& alarm_worker) + : m_alarm_worker{alarm_worker} { + // TODO Initialize IPmModule, dependent on Rtc and Fs +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/pm_state_change_handler.h b/src/core/hle/service/glue/time/pm_state_change_handler.h new file mode 100644 index 000000000..27d9f7872 --- /dev/null +++ b/src/core/hle/service/glue/time/pm_state_change_handler.h @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace Service::Glue::Time { +class AlarmWorker; + +class PmStateChangeHandler { +public: + explicit PmStateChangeHandler(AlarmWorker& alarm_worker); + + AlarmWorker& m_alarm_worker; + s32 m_priority{}; +}; +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp new file mode 100644 index 000000000..5ebaa33e0 --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.cpp @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "common/settings.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/service/glue/time/standard_steady_clock_resource.h" +#include "core/hle/service/psc/time/errors.h" + +namespace Service::Glue::Time { +namespace { +[[maybe_unused]] constexpr u32 Max77620PmicSession = 0x3A000001; +[[maybe_unused]] constexpr u32 Max77620RtcSession = 0x3B000001; + +Result GetTimeInSeconds(Core::System& system, s64& out_time_s) { + out_time_s = std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + + if (Settings::values.custom_rtc_enabled) { + out_time_s += Settings::values.custom_rtc_offset.GetValue(); + } + R_SUCCEED(); +} +} // namespace + +StandardSteadyClockResource::StandardSteadyClockResource(Core::System& system) : m_system{system} {} + +void StandardSteadyClockResource::Initialize(Common::UUID* out_source_id, + Common::UUID* external_source_id) { + constexpr size_t NUM_TRIES{20}; + + size_t i{0}; + Result res{ResultSuccess}; + for (; i < NUM_TRIES; i++) { + res = SetCurrentTime(); + if (res == ResultSuccess) { + break; + } + Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(1)) + .count()); + } + + if (i < NUM_TRIES) { + m_set_time_result = ResultSuccess; + if (*external_source_id != Service::PSC::Time::ClockSourceId{}) { + m_clock_source_id = *external_source_id; + } else { + m_clock_source_id = Common::UUID::MakeRandom(); + } + } else { + m_set_time_result = res; + auto ticks{m_system.CoreTiming().GetClockTicks()}; + m_time = -Service::PSC::Time::ConvertToTimeSpan(ticks).count(); + m_clock_source_id = Common::UUID::MakeRandom(); + } + + if (out_source_id) { + *out_source_id = m_clock_source_id; + } +} + +bool StandardSteadyClockResource::GetResetDetected() { + // TODO: + // call Rtc::GetRtcResetDetected(Max77620RtcSession) + // if detected: + // SetSys::SetExternalSteadyClockSourceId(invalid_id) + // Rtc::ClearRtcResetDetected(Max77620RtcSession) + // set m_rtc_reset to result + // Instead, only set reset to true if we're booting for the first time. + m_rtc_reset = false; + return m_rtc_reset; +} + +Result StandardSteadyClockResource::SetCurrentTime() { + auto start_tick{m_system.CoreTiming().GetClockTicks()}; + + s64 rtc_time_s{}; + // TODO R_TRY(Rtc::GetTimeInSeconds(rtc_time_s, Max77620RtcSession)) + R_TRY(GetTimeInSeconds(m_system, rtc_time_s)); + + auto end_tick{m_system.CoreTiming().GetClockTicks()}; + auto diff{Service::PSC::Time::ConvertToTimeSpan(end_tick - start_tick)}; + // Why is this here? + R_UNLESS(diff < std::chrono::milliseconds(101), Service::PSC::Time::ResultRtcTimeout); + + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + s64 boot_time{rtc_time_s * one_second_ns - + Service::PSC::Time::ConvertToTimeSpan(end_tick).count()}; + + std::scoped_lock l{m_mutex}; + m_time = boot_time; + R_SUCCEED(); +} + +Result StandardSteadyClockResource::GetRtcTimeInSeconds(s64& out_time) { + // TODO + // R_TRY(Rtc::GetTimeInSeconds(time_s, Max77620RtcSession) + R_RETURN(GetTimeInSeconds(m_system, out_time)); +} + +void StandardSteadyClockResource::UpdateTime() { + constexpr size_t NUM_TRIES{3}; + + size_t i{0}; + Result res{ResultSuccess}; + for (; i < NUM_TRIES; i++) { + res = SetCurrentTime(); + if (res == ResultSuccess) { + break; + } + Kernel::Svc::SleepThread(m_system, std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::milliseconds(1)) + .count()); + } +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/standard_steady_clock_resource.h b/src/core/hle/service/glue/time/standard_steady_clock_resource.h new file mode 100644 index 000000000..978d6b63b --- /dev/null +++ b/src/core/hle/service/glue/time/standard_steady_clock_resource.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Service::Glue::Time { +class StandardSteadyClockResource { +public: + StandardSteadyClockResource(Core::System& system); + + void Initialize(Common::UUID* out_source_id, Common::UUID* external_source_id); + + s64 GetTime() const { + return m_time; + } + + bool GetResetDetected(); + Result SetCurrentTime(); + Result GetRtcTimeInSeconds(s64& out_time); + void UpdateTime(); + +private: + Core::System& m_system; + + std::mutex m_mutex; + Service::PSC::Time::ClockSourceId m_clock_source_id{}; + s64 m_time{}; + Result m_set_time_result; + bool m_rtc_reset; +}; +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp new file mode 100644 index 000000000..63b7d91da --- /dev/null +++ b/src/core/hle/service/glue/time/static.cpp @@ -0,0 +1,448 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "core/core.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/service/glue/time/file_timestamp_worker.h" +#include "core/hle/service/glue/time/static.h" +#include "core/hle/service/psc/time/errors.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/psc/time/static.h" +#include "core/hle/service/psc/time/steady_clock.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/psc/time/time_zone_service.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Glue::Time { +namespace { +template <typename T> +T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, + const char* category, const char* name) { + std::vector<u8> interval_buf; + auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); + ASSERT(res == ResultSuccess); + + T v{}; + std::memcpy(&v, interval_buf.data(), sizeof(T)); + return v; +} +} // namespace + +StaticService::StaticService(Core::System& system_, + Service::PSC::Time::StaticServiceSetupInfo setup_info, + std::shared_ptr<TimeManager> time, const char* name) + : ServiceFramework{system_, name}, m_system{system_}, m_time_m{time->m_time_m}, + m_setup_info{setup_info}, m_time_sm{time->m_time_sm}, + m_file_timestamp_worker{time->m_file_timestamp_worker}, m_standard_steady_clock_resource{ + time->m_steady_clock_resource} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, + {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, + {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, + {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, + {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, + {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, + {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, + {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, + {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, + {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, + {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, + {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, + {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, + {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, + {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, + {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, + {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, + {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, + {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, + }; + // clang-format on + + RegisterHandlers(functions); + + m_set_sys = + m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); + + if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock && + !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location && + !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { + m_time_m->GetStaticServiceAsAdmin(m_wrapped_service); + } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && + !m_setup_info.can_write_network_clock && + !m_setup_info.can_write_timezone_device_location && + !m_setup_info.can_write_steady_clock && + !m_setup_info.can_write_uninitialized_clock) { + m_time_m->GetStaticServiceAsUser(m_wrapped_service); + } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && + !m_setup_info.can_write_network_clock && + !m_setup_info.can_write_timezone_device_location && + m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { + m_time_m->GetStaticServiceAsRepair(m_wrapped_service); + } else { + UNREACHABLE(); + } + + auto res = m_wrapped_service->GetTimeZoneService(m_time_zone); + ASSERT(res == ResultSuccess); +} + +void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<Service::PSC::Time::SystemClock> service{}; + auto res = GetStandardUserSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<Service::PSC::Time::SystemClock> service{}; + auto res = GetStandardNetworkSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<Service::PSC::Time::SteadyClock> service{}; + auto res = GetStandardSteadyClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(service)); +} + +void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<TimeZoneService> service{}; + auto res = GetTimeZoneService(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(service)); +} + +void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<Service::PSC::Time::SystemClock> service{}; + auto res = GetStandardLocalSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<Service::PSC::Time::SystemClock> service{}; + auto res = GetEphemeralNetworkSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KSharedMemory* shared_memory{}; + auto res = GetSharedMemoryNativeHandle(&shared_memory); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(shared_memory); +} + +void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto offset_ns{rp.Pop<s64>()}; + + auto res = SetStandardSteadyClockInternalOffset(offset_ns); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s64 rtc_value{}; + auto res = GetStandardSteadyClockRtcValue(rtc_value); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(rtc_value); +} + +void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + bool is_enabled{}; + auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push<bool>(is_enabled); +} + +void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto automatic_correction{rp.Pop<bool>()}; + + auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s32 initial_year{}; + auto res = GetStandardUserSystemClockInitialYear(initial_year); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(initial_year); +} + +void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + bool is_sufficient{}; + auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push<bool>(is_sufficient); +} + +void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, + 2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); +} + +void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; + + s64 time{}; + auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push<s64>(time); +} + +void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto type{rp.PopEnum<Service::PSC::Time::TimeType>()}; + + Service::PSC::Time::ClockSnapshot snapshot{}; + auto res = GetClockSnapshot(snapshot, type); + + ctx.WriteBuffer(snapshot); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()}; + [[maybe_unused]] auto alignment{rp.Pop<u32>()}; + auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; + auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; + + Service::PSC::Time::ClockSnapshot snapshot{}; + auto res = + GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type); + + ctx.WriteBuffer(snapshot); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::ClockSnapshot a{}; + Service::PSC::Time::ClockSnapshot b{}; + + auto a_buffer{ctx.ReadBuffer(0)}; + auto b_buffer{ctx.ReadBuffer(1)}; + + std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); + std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); + + s64 difference{}; + auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(difference); +} + +void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::ClockSnapshot a{}; + Service::PSC::Time::ClockSnapshot b{}; + + auto a_buffer{ctx.ReadBuffer(0)}; + auto b_buffer{ctx.ReadBuffer(1)}; + + std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); + std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot)); + + s64 time{}; + auto res = CalculateSpanBetween(time, a, b); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(time); +} + +// =============================== Implementations =========================== + +Result StaticService::GetStandardUserSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { + R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service)); +} + +Result StaticService::GetStandardNetworkSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { + R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service)); +} + +Result StaticService::GetStandardSteadyClock( + std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) { + R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service)); +} + +Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { + out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker, + m_setup_info.can_write_timezone_device_location, + m_time_zone); + R_SUCCEED(); +} + +Result StaticService::GetStandardLocalSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { + R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service)); +} + +Result StaticService::GetEphemeralNetworkSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) { + R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service)); +} + +Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { + R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory)); +} + +Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { + R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied); + + R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset( + offset_ns / + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count())); +} + +Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) { + R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value)); +} + +Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( + bool& out_automatic_correction) { + R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( + out_automatic_correction)); +} + +Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( + bool automatic_correction) { + R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled( + automatic_correction)); +} + +Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) { + out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year"); + R_SUCCEED(); +} + +Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { + R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); +} + +Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point) { + R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + out_time_point)); +} + +Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( + s64& out_time, Service::PSC::Time::SystemClockContext& context) { + R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); +} + +Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, + Service::PSC::Time::TimeType type) { + R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); +} + +Result StaticService::GetClockSnapshotFromSystemClockContext( + Service::PSC::Time::ClockSnapshot& out_snapshot, + Service::PSC::Time::SystemClockContext& user_context, + Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) { + R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context, + network_context, type)); +} + +Result StaticService::CalculateStandardUserSystemClockDifferenceByUser( + s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) { + R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); +} + +Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, + Service::PSC::Time::ClockSnapshot& b) { + R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/static.h b/src/core/hle/service/glue/time/static.h new file mode 100644 index 000000000..75fe4e2cd --- /dev/null +++ b/src/core/hle/service/glue/time/static.h @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/service/glue/time/manager.h" +#include "core/hle/service/glue/time/time_zone.h" +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Service::Set { +class ISystemSettingsServer; +} + +namespace Service::PSC::Time { +class StaticService; +class SystemClock; +class SteadyClock; +class TimeZoneService; +class ServiceManager; +} // namespace Service::PSC::Time + +namespace Service::Glue::Time { +class FileTimestampWorker; +class StandardSteadyClockResource; + +class StaticService final : public ServiceFramework<StaticService> { +public: + explicit StaticService(Core::System& system, + Service::PSC::Time::StaticServiceSetupInfo setup_info, + std::shared_ptr<TimeManager> time, const char* name); + + ~StaticService() override = default; + + Result GetStandardUserSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); + Result GetStandardNetworkSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); + Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service); + Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); + Result GetStandardLocalSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); + Result GetEphemeralNetworkSystemClock( + std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); + Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); + Result SetStandardSteadyClockInternalOffset(s64 offset); + Result GetStandardSteadyClockRtcValue(s64& out_rtc_value); + Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction); + Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); + Result GetStandardUserSystemClockInitialYear(s32& out_year); + Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); + Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point); + Result CalculateMonotonicSystemClockBaseTimePoint( + s64& out_time, Service::PSC::Time::SystemClockContext& context); + Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, + Service::PSC::Time::TimeType type); + Result GetClockSnapshotFromSystemClockContext( + Service::PSC::Time::ClockSnapshot& out_snapshot, + Service::PSC::Time::SystemClockContext& user_context, + Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type); + Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, + Service::PSC::Time::ClockSnapshot& a, + Service::PSC::Time::ClockSnapshot& b); + Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, + Service::PSC::Time::ClockSnapshot& b); + +private: + Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot, + Service::PSC::Time::SystemClockContext& user_context, + Service::PSC::Time::SystemClockContext& network_context, + Service::PSC::Time::TimeType type); + + void Handle_GetStandardUserSystemClock(HLERequestContext& ctx); + void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx); + void Handle_GetStandardSteadyClock(HLERequestContext& ctx); + void Handle_GetTimeZoneService(HLERequestContext& ctx); + void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx); + void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx); + void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx); + void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx); + void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx); + void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx); + void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); + void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); + void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); + void Handle_GetClockSnapshot(HLERequestContext& ctx); + void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); + void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); + void Handle_CalculateSpanBetween(HLERequestContext& ctx); + + Core::System& m_system; + + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; + std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; + std::shared_ptr<Service::PSC::Time::StaticService> m_wrapped_service; + + Service::PSC::Time::StaticServiceSetupInfo m_setup_info; + std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; + std::shared_ptr<Service::PSC::Time::TimeZoneService> m_time_zone; + FileTimestampWorker& m_file_timestamp_worker; + StandardSteadyClockResource& m_standard_steady_clock_resource; +}; +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp new file mode 100644 index 000000000..503c327dd --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.cpp @@ -0,0 +1,377 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "core/core.h" +#include "core/hle/kernel/svc.h" +#include "core/hle/service/glue/time/file_timestamp_worker.h" +#include "core/hle/service/glue/time/time_zone.h" +#include "core/hle/service/glue/time/time_zone_binary.h" +#include "core/hle/service/psc/time/time_zone_service.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Glue::Time { +namespace { +static std::mutex g_list_mutex; +static Common::IntrusiveListBaseTraits<Service::PSC::Time::OperationEvent>::ListType g_list_nodes{}; +} // namespace + +TimeZoneService::TimeZoneService( + Core::System& system_, FileTimestampWorker& file_timestamp_worker, + bool can_write_timezone_device_location, + std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service) + : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, + m_can_write_timezone_device_location{can_write_timezone_device_location}, + m_file_timestamp_worker{file_timestamp_worker}, + m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, + {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, + {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, + {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, + {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, + {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, + {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, + {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, + {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, + {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, + {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, + {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, + {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, + {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, + }; + // clang-format on + RegisterHandlers(functions); + + g_list_nodes.clear(); + m_set_sys = + m_system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys", true); +} + +TimeZoneService::~TimeZoneService() = default; + +void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::LocationName name{}; + auto res = GetDeviceLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::LocationName>(name); +} + +void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; + + auto res = SetDeviceLocation(name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + u32 count{}; + auto res = GetTotalLocationNameCount(count); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto index{rp.Pop<u32>()}; + + auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)}; + + std::vector<Service::PSC::Time::LocationName> names{}; + u32 count{}; + auto res = LoadLocationNameList(count, names, max_names, index); + + ctx.WriteBuffer(names); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; + + Tz::Rule rule{}; + auto res = LoadTimeZoneRule(rule, name); + + ctx.WriteBuffer(rule); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::RuleVersion rule_version{}; + auto res = GetTimeZoneRuleVersion(rule_version); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version); +} + +void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Service::PSC::Time::LocationName name{}; + Service::PSC::Time::SteadyClockTimePoint time_point{}; + auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name); + + IPC::ResponseBuilder rb{ctx, + 2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) + + (sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::LocationName>(name); + rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); +} + +void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + auto res = SetDeviceLocationNameWithTimeZoneRule(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Service::PSC::Time::ResultNotImplemented); +} + +void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetDeviceLocationNameOperationEventReadableHandle(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event->GetReadableEvent()); +} + +void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + auto rule_buffer{ctx.ReadBuffer()}; + Tz::Rule rule{}; + std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule)); + + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo additional_info{}; + auto res = ToCalendarTime(calendar_time, additional_info, time, rule); + + IPC::ResponseBuilder rb{ctx, + 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + + (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); + rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); +} + +void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + LOG_DEBUG(Service_Time, "called. time={}", time); + + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo additional_info{}; + auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time); + + IPC::ResponseBuilder rb{ctx, + 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) + + (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time); + rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info); +} + +void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; + + LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}", + calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, + calendar.second); + + auto binary{ctx.ReadBuffer()}; + + Tz::Rule rule{}; + std::memcpy(&rule, binary.data(), sizeof(Tz::Rule)); + + u32 count{}; + std::array<s64, 2> times{}; + u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; + + auto res = ToPosixTime(count, times, times_count, calendar, rule); + + ctx.WriteBuffer(times); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()}; + + u32 count{}; + std::array<s64, 2> times{}; + u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; + + auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar); + + ctx.WriteBuffer(times); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +// =============================== Implementations =========================== + +Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) { + R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); +} + +Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) { + R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); + R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound); + + std::scoped_lock l{m_mutex}; + + std::span<const u8> binary{}; + size_t binary_size{}; + R_TRY(GetTimeZoneRule(binary, binary_size, location_name)) + + R_TRY(m_wrapped_service->SetDeviceLocationNameWithTimeZoneRule(location_name, binary)); + + m_file_timestamp_worker.SetFilesystemPosixTime(); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + Service::PSC::Time::LocationName name{}; + R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name)); + + m_set_sys->SetDeviceTimeZoneLocationName(name); + m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point); + + std::scoped_lock m{g_list_mutex}; + for (auto& operation_event : g_list_nodes) { + operation_event.m_event->Signal(); + } + R_SUCCEED(); +} + +Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { + R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); +} + +Result TimeZoneService::LoadLocationNameList( + u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names, + u32 index) { + std::scoped_lock l{m_mutex}; + R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index)); +} + +Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule, + Service::PSC::Time::LocationName& name) { + std::scoped_lock l{m_mutex}; + std::span<const u8> binary{}; + size_t binary_size{}; + R_TRY(GetTimeZoneRule(binary, binary_size, name)) + R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary)); +} + +Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) { + R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); +} + +Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point, + Service::PSC::Time::LocationName& location_name) { + R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name)); +} + +Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() { + R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); + R_RETURN(Service::PSC::Time::ResultNotImplemented); +} + +Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( + Kernel::KEvent** out_event) { + if (!operation_event_initialized) { + operation_event_initialized = false; + + m_operation_event.m_ctx.CloseEvent(m_operation_event.m_event); + m_operation_event.m_event = + m_operation_event.m_ctx.CreateEvent("Psc:TimeZoneService:OperationEvent"); + operation_event_initialized = true; + std::scoped_lock l{m_mutex}; + g_list_nodes.push_back(m_operation_event); + } + + *out_event = m_operation_event.m_event; + R_SUCCEED(); +} + +Result TimeZoneService::ToCalendarTime( + Service::PSC::Time::CalendarTime& out_calendar_time, + Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) { + R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); +} + +Result TimeZoneService::ToCalendarTimeWithMyRule( + Service::PSC::Time::CalendarTime& out_calendar_time, + Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) { + R_RETURN( + m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); +} + +Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, + u32 out_times_count, + Service::PSC::Time::CalendarTime& calendar_time, + Tz::Rule& rule) { + R_RETURN( + m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); +} + +Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, + u32 out_times_count, + Service::PSC::Time::CalendarTime& calendar_time) { + R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, + calendar_time)); +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h new file mode 100644 index 000000000..3c8ae4bf8 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone.h @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <mutex> +#include <span> +#include <vector> + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Tz { +struct Rule; +} + +namespace Service::Set { +class ISystemSettingsServer; +} + +namespace Service::PSC::Time { +class TimeZoneService; +} + +namespace Service::Glue::Time { +class FileTimestampWorker; + +class TimeZoneService final : public ServiceFramework<TimeZoneService> { +public: + explicit TimeZoneService( + Core::System& system, FileTimestampWorker& file_timestamp_worker, + bool can_write_timezone_device_location, + std::shared_ptr<Service::PSC::Time::TimeZoneService> time_zone_service); + + ~TimeZoneService() override; + + Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name); + Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name); + Result GetTotalLocationNameCount(u32& out_count); + Result LoadLocationNameList(u32& out_count, + std::vector<Service::PSC::Time::LocationName>& out_names, + size_t max_names, u32 index); + Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name); + Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version); + Result GetDeviceLocationNameAndUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point, + Service::PSC::Time::LocationName& location_name); + Result SetDeviceLocationNameWithTimeZoneRule(); + Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event); + Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time, + Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, + Tz::Rule& rule); + Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time, + Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, + s64 time); + Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule); + Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + Service::PSC::Time::CalendarTime& calendar_time); + +private: + void Handle_GetDeviceLocationName(HLERequestContext& ctx); + void Handle_SetDeviceLocationName(HLERequestContext& ctx); + void Handle_GetTotalLocationNameCount(HLERequestContext& ctx); + void Handle_LoadLocationNameList(HLERequestContext& ctx); + void Handle_LoadTimeZoneRule(HLERequestContext& ctx); + void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx); + void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx); + void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx); + void Handle_ParseTimeZoneBinary(HLERequestContext& ctx); + void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx); + void Handle_ToCalendarTime(HLERequestContext& ctx); + void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx); + void Handle_ToPosixTime(HLERequestContext& ctx); + void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx); + + Core::System& m_system; + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; + + bool m_can_write_timezone_device_location; + FileTimestampWorker& m_file_timestamp_worker; + std::shared_ptr<Service::PSC::Time::TimeZoneService> m_wrapped_service; + std::mutex m_mutex; + bool operation_event_initialized{}; + Service::PSC::Time::OperationEvent m_operation_event; +}; + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp new file mode 100644 index 000000000..d33f784c0 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.cpp @@ -0,0 +1,221 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h" +#include "core/file_sys/vfs/vfs.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/glue/time/time_zone_binary.h" + +namespace Service::Glue::Time { +namespace { +constexpr u64 TimeZoneBinaryId = 0x10000000000080E; + +static FileSys::VirtualDir g_time_zone_binary_romfs{}; +static Result g_time_zone_binary_mount_result{ResultUnknown}; +static std::vector<u8> g_time_zone_scratch_space(0x2800, 0); + +Result TimeZoneReadBinary(size_t& out_read_size, std::span<u8> out_buffer, size_t out_buffer_size, + std::string_view path) { + R_UNLESS(g_time_zone_binary_mount_result == ResultSuccess, g_time_zone_binary_mount_result); + + auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; + R_UNLESS(vfs_file, ResultUnknown); + + auto file_size{vfs_file->GetSize()}; + R_UNLESS(file_size > 0, ResultUnknown); + + R_UNLESS(file_size <= out_buffer_size, Service::PSC::Time::ResultFailed); + + out_read_size = vfs_file->Read(out_buffer.data(), file_size); + R_UNLESS(out_read_size > 0, ResultUnknown); + + R_SUCCEED(); +} +} // namespace + +void ResetTimeZoneBinary() { + g_time_zone_binary_romfs = {}; + g_time_zone_binary_mount_result = ResultUnknown; + g_time_zone_scratch_space.clear(); + g_time_zone_scratch_space.resize(0x2800, 0); +} + +Result MountTimeZoneBinary(Core::System& system) { + ResetTimeZoneBinary(); + + auto& fsc{system.GetFileSystemController()}; + std::unique_ptr<FileSys::NCA> nca{}; + + auto* bis_system = fsc.GetSystemNANDContents(); + + R_UNLESS(bis_system, ResultUnknown); + + nca = bis_system->GetEntry(TimeZoneBinaryId, FileSys::ContentRecordType::Data); + + if (nca) { + g_time_zone_binary_romfs = FileSys::ExtractRomFS(nca->GetRomFS()); + } + + if (g_time_zone_binary_romfs) { + // Validate that the romfs is readable, using invalid firmware keys can cause this to get + // set but the files to be garbage. In that case, we want to hit the next path and + // synthesise them instead. + Service::PSC::Time::LocationName name{"Etc/GMT"}; + if (!IsTimeZoneBinaryValid(name)) { + ResetTimeZoneBinary(); + } + } + + if (!g_time_zone_binary_romfs) { + g_time_zone_binary_romfs = FileSys::ExtractRomFS( + FileSys::SystemArchive::SynthesizeSystemArchive(TimeZoneBinaryId)); + } + + R_UNLESS(g_time_zone_binary_romfs, ResultUnknown); + + g_time_zone_binary_mount_result = ResultSuccess; + R_SUCCEED(); +} + +void GetTimeZoneBinaryListPath(std::string& out_path) { + if (g_time_zone_binary_mount_result != ResultSuccess) { + return; + } + // out_path = fmt::format("{}:/binaryList.txt", "TimeZoneBinary"); + out_path = "/binaryList.txt"; +} + +void GetTimeZoneBinaryVersionPath(std::string& out_path) { + if (g_time_zone_binary_mount_result != ResultSuccess) { + return; + } + // out_path = fmt::format("{}:/version.txt", "TimeZoneBinary"); + out_path = "/version.txt"; +} + +void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name) { + if (g_time_zone_binary_mount_result != ResultSuccess) { + return; + } + // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name); + out_path = fmt::format("/zoneinfo/{}", name.name.data()); +} + +bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) { + std::string path{}; + GetTimeZoneZonePath(path, name); + + auto vfs_file{g_time_zone_binary_romfs->GetFileRelative(path)}; + if (!vfs_file) { + LOG_INFO(Service_Time, "Could not find timezone file {}", path); + return false; + } + return vfs_file->GetSize() != 0; +} + +u32 GetTimeZoneCount() { + std::string path{}; + GetTimeZoneBinaryListPath(path); + + size_t bytes_read{}; + if (TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, 0x2800, path) != ResultSuccess) { + return 0; + } + if (bytes_read == 0) { + return 0; + } + + auto chars = std::span(reinterpret_cast<char*>(g_time_zone_scratch_space.data()), bytes_read); + u32 count{}; + for (auto chr : chars) { + if (chr == '\n') { + count++; + } + } + return count; +} + +Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version) { + std::string path{}; + GetTimeZoneBinaryVersionPath(path); + + auto rule_version_buffer{std::span(reinterpret_cast<u8*>(&out_rule_version), + sizeof(Service::PSC::Time::RuleVersion))}; + size_t bytes_read{}; + R_TRY(TimeZoneReadBinary(bytes_read, rule_version_buffer, rule_version_buffer.size_bytes(), + path)); + + rule_version_buffer[bytes_read] = 0; + R_SUCCEED(); +} + +Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, + Service::PSC::Time::LocationName& name) { + std::string path{}; + GetTimeZoneZonePath(path, name); + + size_t bytes_read{}; + R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, + g_time_zone_scratch_space.size(), path)); + + out_rule = std::span(g_time_zone_scratch_space.data(), bytes_read); + out_rule_size = bytes_read; + R_SUCCEED(); +} + +Result GetTimeZoneLocationList(u32& out_count, + std::vector<Service::PSC::Time::LocationName>& out_names, + size_t max_names, u32 index) { + std::string path{}; + GetTimeZoneBinaryListPath(path); + + size_t bytes_read{}; + R_TRY(TimeZoneReadBinary(bytes_read, g_time_zone_scratch_space, + g_time_zone_scratch_space.size(), path)); + + out_count = 0; + R_SUCCEED_IF(bytes_read == 0); + + Service::PSC::Time::LocationName current_name{}; + size_t current_name_len{}; + std::span<const u8> chars{g_time_zone_scratch_space}; + u32 name_count{}; + + for (auto chr : chars) { + if (chr == '\r') { + continue; + } + + if (chr == '\n') { + if (name_count >= index) { + out_names.push_back(current_name); + out_count++; + if (out_count >= max_names) { + break; + } + } + name_count++; + current_name_len = 0; + current_name = {}; + continue; + } + + if (chr == '\0') { + break; + } + + R_UNLESS(current_name_len <= current_name.name.size() - 2, + Service::PSC::Time::ResultFailed); + + current_name.name[current_name_len++] = chr; + } + + R_SUCCEED(); +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/time_zone_binary.h b/src/core/hle/service/glue/time/time_zone_binary.h new file mode 100644 index 000000000..2cad6b458 --- /dev/null +++ b/src/core/hle/service/glue/time/time_zone_binary.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <span> +#include <string> +#include <string_view> + +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Service::Glue::Time { + +void ResetTimeZoneBinary(); +Result MountTimeZoneBinary(Core::System& system); +void GetTimeZoneBinaryListPath(std::string& out_path); +void GetTimeZoneBinaryVersionPath(std::string& out_path); +void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName& name); +bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name); +u32 GetTimeZoneCount(); +Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version); +Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, + Service::PSC::Time::LocationName& name); +Result GetTimeZoneLocationList(u32& out_count, + std::vector<Service::PSC::Time::LocationName>& out_names, + size_t max_names, u32 index); + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp new file mode 100644 index 000000000..ea0e49b90 --- /dev/null +++ b/src/core/hle/service/glue/time/worker.cpp @@ -0,0 +1,338 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/service/glue/time/file_timestamp_worker.h" +#include "core/hle/service/glue/time/standard_steady_clock_resource.h" +#include "core/hle/service/glue/time/worker.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/psc/time/static.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::Glue::Time { +namespace { + +bool g_ig_report_network_clock_context_set{}; +Service::PSC::Time::SystemClockContext g_report_network_clock_context{}; +bool g_ig_report_ephemeral_clock_context_set{}; +Service::PSC::Time::SystemClockContext g_report_ephemeral_clock_context{}; + +template <typename T> +T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set_sys, + const char* category, const char* name) { + std::vector<u8> interval_buf; + auto res = set_sys->GetSettingsItemValue(interval_buf, category, name); + ASSERT(res == ResultSuccess); + + T v{}; + std::memcpy(&v, interval_buf.data(), sizeof(T)); + return v; +} + +} // namespace + +TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, + FileTimestampWorker& file_timestamp_worker) + : m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")}, + m_steady_clock_resource{steady_clock_resource}, + m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent( + "Glue:58:SteadyClockTimerEvent")}, + m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")}, + m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} { + g_ig_report_network_clock_context_set = false; + g_report_network_clock_context = {}; + g_ig_report_ephemeral_clock_context_set = false; + g_report_ephemeral_clock_context = {}; + + m_timer_steady_clock_timing_event = Core::Timing::CreateEvent( + "Time::SteadyClockEvent", + [this](s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { + m_timer_steady_clock->Signal(); + return std::nullopt; + }); + + m_timer_file_system_timing_event = Core::Timing::CreateEvent( + "Time::SteadyClockEvent", + [this](s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { + m_timer_file_system->Signal(); + return std::nullopt; + }); +} + +TimeWorker::~TimeWorker() { + m_local_clock_event->Signal(); + m_network_clock_event->Signal(); + m_ephemeral_clock_event->Signal(); + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + + m_thread.request_stop(); + m_event->Signal(); + m_thread.join(); + + m_ctx.CloseEvent(m_event); + m_system.CoreTiming().UnscheduleEvent(m_timer_steady_clock_timing_event); + m_ctx.CloseEvent(m_timer_steady_clock); + m_system.CoreTiming().UnscheduleEvent(m_timer_file_system_timing_event); + m_ctx.CloseEvent(m_timer_file_system); +} + +void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, + std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys) { + m_set_sys = std::move(set_sys); + m_time_m = + m_system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); + m_time_sm = std::move(time_sm); + + m_alarm_worker.Initialize(m_time_m); + + auto steady_clock_interval_m = GetSettingsItemValue<s32>( + m_set_sys, "time", "standard_steady_clock_rtc_update_interval_minutes"); + + auto one_minute_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::minutes(1)).count()}; + s64 steady_clock_interval_ns{steady_clock_interval_m * one_minute_ns}; + + m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), + std::chrono::nanoseconds(steady_clock_interval_ns), + m_timer_steady_clock_timing_event); + + auto fs_notify_time_s = + GetSettingsItemValue<s32>(m_set_sys, "time", "notify_time_to_fs_interval_seconds"); + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + s64 fs_notify_time_ns{fs_notify_time_s * one_second_ns}; + + m_system.CoreTiming().ScheduleLoopingEvent(std::chrono::nanoseconds(0), + std::chrono::nanoseconds(fs_notify_time_ns), + m_timer_file_system_timing_event); + + auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock); + ASSERT(res == ResultSuccess); + res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event); + ASSERT(res == ResultSuccess); + + res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock); + ASSERT(res == ResultSuccess); + res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event); + ASSERT(res == ResultSuccess); + + res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock); + ASSERT(res == ResultSuccess); + res = + m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event); + ASSERT(res == ResultSuccess); + + res = m_time_m->GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( + &m_standard_user_auto_correct_clock_event); + ASSERT(res == ResultSuccess); +} + +void TimeWorker::StartThread() { + m_thread = std::jthread(std::bind_front(&TimeWorker::ThreadFunc, this)); +} + +void TimeWorker::ThreadFunc(std::stop_token stop_token) { + Common::SetCurrentThreadName("TimeWorker"); + Common::SetCurrentThreadPriority(Common::ThreadPriority::Low); + + enum class EventType { + Exit = 0, + IpmModuleService_GetEvent = 1, + PowerStateChange = 2, + SignalAlarms = 3, + UpdateLocalSystemClock = 4, + UpdateNetworkSystemClock = 5, + UpdateEphemeralSystemClock = 6, + UpdateSteadyClock = 7, + UpdateFileTimestamp = 8, + AutoCorrect = 9, + Max = 10, + }; + + s32 num_objs{}; + std::array<Kernel::KSynchronizationObject*, static_cast<u32>(EventType::Max)> wait_objs{}; + std::array<EventType, static_cast<u32>(EventType::Max)> wait_indices{}; + + const auto AddWaiter{ + [&](Kernel::KSynchronizationObject* synchronization_object, EventType type) { + // Open a new reference to the object. + synchronization_object->Open(); + + // Insert into the list. + wait_indices[num_objs] = type; + wait_objs[num_objs++] = synchronization_object; + }}; + + while (!stop_token.stop_requested()) { + SCOPE_EXIT({ + for (s32 i = 0; i < num_objs; i++) { + wait_objs[i]->Close(); + } + }); + + num_objs = {}; + wait_objs = {}; + if (m_pm_state_change_handler.m_priority != 0) { + AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); + // TODO + // AddWaiter(gIPmModuleService::GetEvent(), 1); + AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); + } else { + AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); + // TODO + // AddWaiter(gIPmModuleService::GetEvent(), 1); + AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); + AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); + AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock); + AddWaiter(&m_network_clock_event->GetReadableEvent(), + EventType::UpdateNetworkSystemClock); + AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(), + EventType::UpdateEphemeralSystemClock); + AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); + AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); + AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(), + EventType::AutoCorrect); + } + + s32 out_index{-1}; + Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), + num_objs, -1); + ASSERT(out_index >= 0 && out_index < num_objs); + + if (stop_token.stop_requested()) { + return; + } + + switch (wait_indices[out_index]) { + case EventType::Exit: + return; + + case EventType::IpmModuleService_GetEvent: + // TODO + // IPmModuleService::GetEvent() + // clear the event + // Handle power state change event + break; + + case EventType::PowerStateChange: + m_alarm_worker.GetEvent().Clear(); + if (m_pm_state_change_handler.m_priority <= 1) { + m_alarm_worker.OnPowerStateChanged(); + } + break; + + case EventType::SignalAlarms: + m_alarm_worker.GetTimerEvent().Clear(); + m_time_m->CheckAndSignalAlarms(); + break; + + case EventType::UpdateLocalSystemClock: { + m_local_clock_event->Clear(); + + Service::PSC::Time::SystemClockContext context{}; + auto res = m_local_clock->GetSystemClockContext(context); + ASSERT(res == ResultSuccess); + + m_set_sys->SetUserSystemClockContext(context); + + m_file_timestamp_worker.SetFilesystemPosixTime(); + } break; + + case EventType::UpdateNetworkSystemClock: { + m_network_clock_event->Clear(); + Service::PSC::Time::SystemClockContext context{}; + auto res = m_network_clock->GetSystemClockContext(context); + ASSERT(res == ResultSuccess); + m_set_sys->SetNetworkSystemClockContext(context); + + s64 time{}; + if (m_network_clock->GetCurrentTime(time) != ResultSuccess) { + break; + } + + [[maybe_unused]] auto offset_before{ + g_ig_report_network_clock_context_set ? g_report_network_clock_context.offset : 0}; + // TODO system report "standard_netclock_operation" + // "clock_time" = time + // "context_offset_before" = offset_before + // "context_offset_after" = context.offset + g_report_network_clock_context = context; + if (!g_ig_report_network_clock_context_set) { + g_ig_report_network_clock_context_set = true; + } + + m_file_timestamp_worker.SetFilesystemPosixTime(); + } break; + + case EventType::UpdateEphemeralSystemClock: { + m_ephemeral_clock_event->Clear(); + + Service::PSC::Time::SystemClockContext context{}; + auto res = m_ephemeral_clock->GetSystemClockContext(context); + if (res != ResultSuccess) { + break; + } + + s64 time{}; + res = m_ephemeral_clock->GetCurrentTime(time); + if (res != ResultSuccess) { + break; + } + + [[maybe_unused]] auto offset_before{g_ig_report_ephemeral_clock_context_set + ? g_report_ephemeral_clock_context.offset + : 0}; + // TODO system report "ephemeral_netclock_operation" + // "clock_time" = time + // "context_offset_before" = offset_before + // "context_offset_after" = context.offset + g_report_ephemeral_clock_context = context; + if (!g_ig_report_ephemeral_clock_context_set) { + g_ig_report_ephemeral_clock_context_set = true; + } + } break; + + case EventType::UpdateSteadyClock: + m_timer_steady_clock->Clear(); + + m_steady_clock_resource.UpdateTime(); + m_time_m->SetStandardSteadyClockBaseTime(m_steady_clock_resource.GetTime()); + break; + + case EventType::UpdateFileTimestamp: + m_timer_file_system->Clear(); + + m_file_timestamp_worker.SetFilesystemPosixTime(); + break; + + case EventType::AutoCorrect: { + m_standard_user_auto_correct_clock_event->Clear(); + + bool automatic_correction{}; + auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( + automatic_correction); + ASSERT(res == ResultSuccess); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + ASSERT(res == ResultSuccess); + + m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); + m_set_sys->SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + } break; + + default: + UNREACHABLE(); + break; + } + } +} + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/glue/time/worker.h b/src/core/hle/service/glue/time/worker.h new file mode 100644 index 000000000..adbbe6b6d --- /dev/null +++ b/src/core/hle/service/glue/time/worker.h @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/glue/time/alarm_worker.h" +#include "core/hle/service/glue/time/pm_state_change_handler.h" +#include "core/hle/service/kernel_helpers.h" + +namespace Service::Set { +class ISystemSettingsServer; +} + +namespace Service::PSC::Time { +class StaticService; +class SystemClock; +} // namespace Service::PSC::Time + +namespace Service::Glue::Time { +class FileTimestampWorker; +class StandardSteadyClockResource; + +class TimeWorker { +public: + explicit TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, + FileTimestampWorker& file_timestamp_worker); + ~TimeWorker(); + + void Initialize(std::shared_ptr<Service::PSC::Time::StaticService> time_sm, + std::shared_ptr<Service::Set::ISystemSettingsServer> set_sys); + + void StartThread(); + +private: + void ThreadFunc(std::stop_token stop_token); + + Core::System& m_system; + KernelHelpers::ServiceContext m_ctx; + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; + + std::jthread m_thread; + Kernel::KEvent* m_event{}; + std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; + std::shared_ptr<Service::PSC::Time::StaticService> m_time_sm; + std::shared_ptr<Service::PSC::Time::SystemClock> m_network_clock; + std::shared_ptr<Service::PSC::Time::SystemClock> m_local_clock; + std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock; + StandardSteadyClockResource& m_steady_clock_resource; + FileTimestampWorker& m_file_timestamp_worker; + Kernel::KEvent* m_local_clock_event{}; + Kernel::KEvent* m_network_clock_event{}; + Kernel::KEvent* m_ephemeral_clock_event{}; + Kernel::KEvent* m_standard_user_auto_correct_clock_event{}; + Kernel::KEvent* m_timer_steady_clock{}; + std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event; + Kernel::KEvent* m_timer_file_system{}; + std::shared_ptr<Core::Timing::EventType> m_timer_file_system_timing_event; + AlarmWorker m_alarm_worker; + PmStateChangeHandler m_pm_state_change_handler; +}; + +} // namespace Service::Glue::Time diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp deleted file mode 100644 index b4ff663c2..000000000 --- a/src/core/hle/service/hid/controllers/applet_resource.cpp +++ /dev/null @@ -1,329 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/core.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/errors.h" - -namespace Service::HID { - -AppletResource::AppletResource(Core::System& system_) : system{system_} {} - -AppletResource::~AppletResource() = default; - -Result AppletResource::CreateAppletResource(u64 aruid) { - const u64 index = GetIndexFromAruid(aruid); - - if (index >= AruidIndexMax) { - return ResultAruidNotRegistered; - } - - if (data[index].flag.is_assigned) { - return ResultAruidAlreadyRegistered; - } - - auto& shared_memory = shared_memory_holder[index]; - if (!shared_memory.IsMapped()) { - const Result result = shared_memory.Initialize(system); - if (result.IsError()) { - return result; - } - if (shared_memory.GetAddress() == nullptr) { - shared_memory.Finalize(); - return ResultSharedMemoryNotInitialized; - } - } - - auto* shared_memory_format = shared_memory.GetAddress(); - if (shared_memory_format != nullptr) { - shared_memory_format->Initialize(); - } - - data[index].shared_memory_format = shared_memory_format; - data[index].flag.is_assigned.Assign(true); - // TODO: InitializeSixAxisControllerConfig(false); - active_aruid = aruid; - return ResultSuccess; -} - -Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) { - const u64 index = GetIndexFromAruid(aruid); - - if (index < AruidIndexMax) { - return ResultAruidAlreadyRegistered; - } - - std::size_t data_index = AruidIndexMax; - for (std::size_t i = 0; i < AruidIndexMax; i++) { - if (!data[i].flag.is_initialized) { - data_index = i; - break; - } - } - - if (data_index == AruidIndexMax) { - return ResultAruidNoAvailableEntries; - } - - AruidData& aruid_data = data[data_index]; - - aruid_data.aruid = aruid; - aruid_data.flag.is_initialized.Assign(true); - if (enable_input) { - aruid_data.flag.enable_pad_input.Assign(true); - aruid_data.flag.enable_six_axis_sensor.Assign(true); - aruid_data.flag.bit_18.Assign(true); - aruid_data.flag.enable_touchscreen.Assign(true); - } - - data_index = AruidIndexMax; - for (std::size_t i = 0; i < AruidIndexMax; i++) { - if (registration_list.flag[i] == RegistrationStatus::Initialized) { - if (registration_list.aruid[i] != aruid) { - continue; - } - data_index = i; - break; - } - if (registration_list.flag[i] == RegistrationStatus::None) { - data_index = i; - break; - } - } - - if (data_index == AruidIndexMax) { - return ResultSuccess; - } - - registration_list.flag[data_index] = RegistrationStatus::Initialized; - registration_list.aruid[data_index] = aruid; - - return ResultSuccess; -} - -void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { - u64 index = GetIndexFromAruid(aruid); - - if (index < AruidIndexMax) { - if (data[index].flag.is_assigned) { - data[index].shared_memory_format = nullptr; - data[index].flag.is_assigned.Assign(false); - } - } - - index = GetIndexFromAruid(aruid); - if (index < AruidIndexMax) { - DestroySevenSixAxisTransferMemory(); - data[index].flag.raw = 0; - data[index].aruid = 0; - - index = GetIndexFromAruid(aruid); - if (index < AruidIndexMax) { - registration_list.flag[index] = RegistrationStatus::PendingDelete; - } - } -} - -void AppletResource::FreeAppletResourceId(u64 aruid) { - u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - auto& aruid_data = data[index]; - if (aruid_data.flag.is_assigned) { - aruid_data.shared_memory_format = nullptr; - aruid_data.flag.is_assigned.Assign(false); - } -} - -u64 AppletResource::GetActiveAruid() { - return active_aruid; -} - -Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { - u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return ResultAruidNotRegistered; - } - - *out_handle = shared_memory_holder[index].GetHandle(); - return ResultSuccess; -} - -Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, - u64 aruid) { - u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return ResultAruidNotRegistered; - } - - *out_shared_memory_format = data[index].shared_memory_format; - return ResultSuccess; -} - -AruidData* AppletResource::GetAruidData(u64 aruid) { - const u64 aruid_index = GetIndexFromAruid(aruid); - if (aruid_index == AruidIndexMax) { - return nullptr; - } - return &data[aruid_index]; -} - -AruidData* AppletResource::GetAruidDataByIndex(std::size_t aruid_index) { - return &data[aruid_index]; -} - -bool AppletResource::IsVibrationAruidActive(u64 aruid) const { - return aruid == 0 || aruid == active_vibration_aruid; -} - -u64 AppletResource::GetIndexFromAruid(u64 aruid) { - for (std::size_t i = 0; i < AruidIndexMax; i++) { - if (registration_list.flag[i] == RegistrationStatus::Initialized && - registration_list.aruid[i] == aruid) { - return i; - } - } - return AruidIndexMax; -} - -Result AppletResource::DestroySevenSixAxisTransferMemory() { - // TODO - return ResultSuccess; -} - -void AppletResource::EnableInput(u64 aruid, bool is_enabled) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.enable_pad_input.Assign(is_enabled); - data[index].flag.enable_touchscreen.Assign(is_enabled); -} - -void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.enable_six_axis_sensor.Assign(is_enabled); -} - -void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.enable_pad_input.Assign(is_enabled); -} - -void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.enable_touchscreen.Assign(is_enabled); -} - -void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.is_palma_connectable.Assign(is_connectable); -} - -void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) { - const u64 index = GetIndexFromAruid(aruid); - if (index >= AruidIndexMax) { - return; - } - - data[index].flag.enable_palma_boost_mode.Assign(is_enabled); -} - -Result AppletResource::RegisterCoreAppletResource() { - if (ref_counter == std::numeric_limits<s32>::max() - 1) { - return ResultAppletResourceOverflow; - } - if (ref_counter == 0) { - const u64 index = GetIndexFromAruid(0); - if (index < AruidIndexMax) { - return ResultAruidAlreadyRegistered; - } - - std::size_t data_index = AruidIndexMax; - for (std::size_t i = 0; i < AruidIndexMax; i++) { - if (!data[i].flag.is_initialized) { - data_index = i; - break; - } - } - - if (data_index == AruidIndexMax) { - return ResultAruidNoAvailableEntries; - } - - AruidData& aruid_data = data[data_index]; - - aruid_data.aruid = 0; - aruid_data.flag.is_initialized.Assign(true); - aruid_data.flag.enable_pad_input.Assign(true); - aruid_data.flag.enable_six_axis_sensor.Assign(true); - aruid_data.flag.bit_18.Assign(true); - aruid_data.flag.enable_touchscreen.Assign(true); - - data_index = AruidIndexMax; - for (std::size_t i = 0; i < AruidIndexMax; i++) { - if (registration_list.flag[i] == RegistrationStatus::Initialized) { - if (registration_list.aruid[i] != 0) { - continue; - } - data_index = i; - break; - } - if (registration_list.flag[i] == RegistrationStatus::None) { - data_index = i; - break; - } - } - - Result result = ResultSuccess; - - if (data_index == AruidIndexMax) { - result = CreateAppletResource(0); - } else { - registration_list.flag[data_index] = RegistrationStatus::Initialized; - registration_list.aruid[data_index] = 0; - } - - if (result.IsError()) { - UnregisterAppletResourceUserId(0); - return result; - } - } - ref_counter++; - return ResultSuccess; -} - -Result AppletResource::UnregisterCoreAppletResource() { - if (ref_counter == 0) { - return ResultAppletResourceNotInitialized; - } - - if (--ref_counter == 0) { - UnregisterAppletResourceUserId(0); - } - - return ResultSuccess; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h deleted file mode 100644 index 52cc4cf42..000000000 --- a/src/core/hle/service/hid/controllers/applet_resource.h +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <array> -#include <mutex> - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hle/result.h" -#include "core/hle/service/hid/controllers/shared_memory_holder.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KSharedMemory; -} - -namespace Service::HID { -struct SharedMemoryFormat; -class AppletResource; -class NPadResource; - -static constexpr std::size_t AruidIndexMax = 0x20; - -enum class RegistrationStatus : u32 { - None, - Initialized, - PendingDelete, -}; - -struct DataStatusFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> is_initialized; - BitField<1, 1, u32> is_assigned; - BitField<16, 1, u32> enable_pad_input; - BitField<17, 1, u32> enable_six_axis_sensor; - BitField<18, 1, u32> bit_18; - BitField<19, 1, u32> is_palma_connectable; - BitField<20, 1, u32> enable_palma_boost_mode; - BitField<21, 1, u32> enable_touchscreen; - }; -}; - -struct AruidRegisterList { - std::array<RegistrationStatus, AruidIndexMax> flag{}; - std::array<u64, AruidIndexMax> aruid{}; -}; -static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); - -struct AruidData { - DataStatusFlag flag{}; - u64 aruid{}; - SharedMemoryFormat* shared_memory_format{nullptr}; -}; - -struct HandheldConfig { - bool is_handheld_hid_enabled; - bool is_force_handheld; - bool is_joycon_rail_enabled; - bool is_force_handheld_style_vibration; -}; -static_assert(sizeof(HandheldConfig) == 0x4, "HandheldConfig is an invalid size"); - -struct AppletResourceHolder { - std::shared_ptr<AppletResource> applet_resource{nullptr}; - std::recursive_mutex* shared_mutex{nullptr}; - NPadResource* shared_npad_resource{nullptr}; - std::shared_ptr<HandheldConfig> handheld_config{nullptr}; - long* handle_1; -}; - -class AppletResource { -public: - explicit AppletResource(Core::System& system_); - ~AppletResource(); - - Result CreateAppletResource(u64 aruid); - - Result RegisterAppletResourceUserId(u64 aruid, bool enable_input); - void UnregisterAppletResourceUserId(u64 aruid); - - void FreeAppletResourceId(u64 aruid); - - u64 GetActiveAruid(); - Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); - Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); - AruidData* GetAruidData(u64 aruid); - AruidData* GetAruidDataByIndex(std::size_t aruid_index); - - bool IsVibrationAruidActive(u64 aruid) const; - - u64 GetIndexFromAruid(u64 aruid); - - Result DestroySevenSixAxisTransferMemory(); - - void EnableInput(u64 aruid, bool is_enabled); - void EnableSixAxisSensor(u64 aruid, bool is_enabled); - void EnablePadInput(u64 aruid, bool is_enabled); - void EnableTouchScreen(u64 aruid, bool is_enabled); - void SetIsPalmaConnectable(u64 aruid, bool is_connectable); - void EnablePalmaBoostMode(u64 aruid, bool is_enabled); - - Result RegisterCoreAppletResource(); - Result UnregisterCoreAppletResource(); - -private: - u64 active_aruid{}; - AruidRegisterList registration_list{}; - std::array<AruidData, AruidIndexMax> data{}; - std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; - s32 ref_counter{}; - u64 active_vibration_aruid; - - Core::System& system; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/capture_button.cpp b/src/core/hle/service/hid/controllers/capture_button.cpp deleted file mode 100644 index 8b486fcb5..000000000 --- a/src/core/hle/service/hid/controllers/capture_button.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/capture_button.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -CaptureButton::CaptureButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} - -CaptureButton::~CaptureButton() = default; - -void CaptureButton::OnInit() {} - -void CaptureButton::OnRelease() {} - -void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!smart_update) { - return; - } - - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - auto& header = data->shared_memory_format->capture_button.header; - header.timestamp = core_timing.GetGlobalTimeNs().count(); - header.total_entry_count = 17; - header.entry_count = 0; - header.last_entry_index = 0; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/capture_button.h b/src/core/hle/service/hid/controllers/capture_button.h deleted file mode 100644 index dcc4715c5..000000000 --- a/src/core/hle/service/hid/controllers/capture_button.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -class CaptureButton final : public ControllerBase { -public: - explicit CaptureButton(Core::HID::HIDCore& hid_core_); - ~CaptureButton() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - bool smart_update{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp deleted file mode 100644 index 8eba2c292..000000000 --- a/src/core/hle/service/hid/controllers/console_six_axis.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/console_six_axis.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - console = hid_core.GetEmulatedConsole(); -} - -ConsoleSixAxis::~ConsoleSixAxis() = default; - -void ConsoleSixAxis::OnInit() {} - -void ConsoleSixAxis::OnRelease() {} - -void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - ConsoleSixAxisSensorSharedMemoryFormat& shared_memory = data->shared_memory_format->console; - - if (!IsControllerActivated()) { - return; - } - - const auto motion_status = console->GetMotion(); - - shared_memory.sampling_number++; - shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - shared_memory.verticalization_error = motion_status.verticalization_error; - shared_memory.gyro_bias = motion_status.gyro_bias; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h deleted file mode 100644 index e3351f83c..000000000 --- a/src/core/hle/service/hid/controllers/console_six_axis.h +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID - -namespace Service::HID { -class ConsoleSixAxis final : public ControllerBase { -public: - explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_); - ~ConsoleSixAxis() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - Core::HID::EmulatedConsole* console = nullptr; -}; -} // 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 deleted file mode 100644 index 2083ccfad..000000000 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} -ControllerBase::~ControllerBase() = default; - -Result ControllerBase::Activate() { - if (is_activated) { - return ResultSuccess; - } - is_activated = true; - OnInit(); - return ResultSuccess; -} - -Result ControllerBase::Activate(u64 aruid) { - return Activate(); -} - -void ControllerBase::DeactivateController() { - if (is_activated) { - OnRelease(); - } - is_activated = false; -} - -bool ControllerBase::IsControllerActivated() const { - return is_activated; -} - -void ControllerBase::SetAppletResource(std::shared_ptr<AppletResource> resource) { - applet_resource = resource; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h deleted file mode 100644 index 759ae0053..000000000 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> - -#include "common/common_types.h" -#include "core/hle/result.h" -#include "core/hle/service/hid/controllers/applet_resource.h" - -namespace Core::Timing { -class CoreTiming; -} - -namespace Core::HID { -class HIDCore; -} // namespace Core::HID - -namespace Service::HID { -class ControllerBase { -public: - explicit ControllerBase(Core::HID::HIDCore& hid_core_); - virtual ~ControllerBase(); - - // Called when the controller is initialized - virtual void OnInit() = 0; - - // When the controller is released - virtual void OnRelease() = 0; - - // When the controller is requesting an update for the shared memory - virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0; - - // When the controller is requesting a motion update for the shared memory - virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {} - - Result Activate(); - Result Activate(u64 aruid); - - void DeactivateController(); - - bool IsControllerActivated() const; - - void SetAppletResource(std::shared_ptr<AppletResource> resource); - -protected: - bool is_activated{false}; - std::shared_ptr<AppletResource> applet_resource{nullptr}; - - Core::HID::HIDCore& hid_core; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_mouse.cpp b/src/core/hle/service/hid/controllers/debug_mouse.cpp deleted file mode 100644 index f2f1a27f8..000000000 --- a/src/core/hle/service/hid/controllers/debug_mouse.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/frontend/emu_window.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/debug_mouse.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -DebugMouse::DebugMouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - emulated_devices = hid_core.GetEmulatedDevices(); -} - -DebugMouse::~DebugMouse() = default; - -void DebugMouse::OnInit() {} -void DebugMouse::OnRelease() {} - -void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_mouse; - - if (!IsControllerActivated()) { - shared_memory.mouse_lifo.buffer_count = 0; - shared_memory.mouse_lifo.buffer_tail = 0; - return; - } - - next_state = {}; - - const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; - - if (Settings::values.mouse_enabled) { - const auto& mouse_button_state = emulated_devices->GetMouseButtons(); - const auto& mouse_position_state = emulated_devices->GetMousePosition(); - const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); - next_state.attribute.is_connected.Assign(1); - next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); - next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); - next_state.delta_x = next_state.x - last_entry.x; - next_state.delta_y = next_state.y - last_entry.y; - next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; - next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; - - last_mouse_wheel_state = mouse_wheel_state; - next_state.button = mouse_button_state; - } - - shared_memory.mouse_lifo.WriteNextEntry(next_state); -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_mouse.h b/src/core/hle/service/hid/controllers/debug_mouse.h deleted file mode 100644 index ec939fa9f..000000000 --- a/src/core/hle/service/hid/controllers/debug_mouse.h +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Core::HID { -class EmulatedDevices; -struct MouseState; -struct AnalogStickState; -} // namespace Core::HID - -namespace Service::HID { -class DebugMouse final : public ControllerBase { -public: - explicit DebugMouse(Core::HID::HIDCore& hid_core_); - ~DebugMouse() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - Core::HID::MouseState next_state{}; - Core::HID::AnalogStickState last_mouse_wheel_state{}; - Core::HID::EmulatedDevices* emulated_devices = nullptr; -}; -} // 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 deleted file mode 100644 index 1811cf620..000000000 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/debug_pad.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -DebugPad::DebugPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); -} - -DebugPad::~DebugPad() = default; - -void DebugPad::OnInit() {} - -void DebugPad::OnRelease() {} - -void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - DebugPadSharedMemoryFormat& shared_memory = data->shared_memory_format->debug_pad; - - if (!IsControllerActivated()) { - shared_memory.debug_pad_lifo.buffer_count = 0; - shared_memory.debug_pad_lifo.buffer_tail = 0; - return; - } - - const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; - - if (Settings::values.debug_pad_enabled) { - next_state.attribute.connected.Assign(1); - - const auto& button_state = controller->GetDebugPadButtons(); - const auto& stick_state = controller->GetSticks(); - - next_state.pad_state = button_state; - next_state.l_stick = stick_state.left; - next_state.r_stick = stick_state.right; - } - - shared_memory.debug_pad_lifo.WriteNextEntry(next_state); -} - -} // 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 deleted file mode 100644 index dd00b2402..000000000 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/types/debug_pad_types.h" - -namespace Core::HID { -class HIDCore; -} - -namespace Core::Timing { -class CoreTiming; -} - -namespace Service::HID { -class DebugPad final : public ControllerBase { -public: - explicit DebugPad(Core::HID::HIDCore& hid_core_); - ~DebugPad() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - DebugPadState next_state{}; - Core::HID::EmulatedController* controller = nullptr; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/digitizer.cpp b/src/core/hle/service/hid/controllers/digitizer.cpp deleted file mode 100644 index c01580fd6..000000000 --- a/src/core/hle/service/hid/controllers/digitizer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/digitizer.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -Digitizer::Digitizer(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} - -Digitizer::~Digitizer() = default; - -void Digitizer::OnInit() {} - -void Digitizer::OnRelease() {} - -void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!smart_update) { - return; - } - - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - auto& header = data->shared_memory_format->digitizer.header; - header.timestamp = core_timing.GetGlobalTimeNs().count(); - header.total_entry_count = 17; - header.entry_count = 0; - header.last_entry_index = 0; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/digitizer.h b/src/core/hle/service/hid/controllers/digitizer.h deleted file mode 100644 index d81f814c3..000000000 --- a/src/core/hle/service/hid/controllers/digitizer.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -class Digitizer final : public ControllerBase { -public: - explicit Digitizer(Core::HID::HIDCore& hid_core_); - ~Digitizer() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - bool smart_update{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp deleted file mode 100644 index 6e686fe65..000000000 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ /dev/null @@ -1,364 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/math_util.h" -#include "common/settings.h" -#include "core/frontend/emu_window.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/gesture.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { -// HW is around 700, value is set to 400 to make it easier to trigger with mouse -constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s -constexpr f32 angle_threshold = 0.015f; // Threshold in radians -constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels -constexpr f32 press_delay = 0.5f; // Time in seconds -constexpr f32 double_tap_delay = 0.35f; // Time in seconds - -constexpr f32 Square(s32 num) { - return static_cast<f32>(num * num); -} - -Gesture::Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { - console = hid_core.GetEmulatedConsole(); -} -Gesture::~Gesture() = default; - -void Gesture::OnInit() { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - shared_memory = &data->shared_memory_format->gesture; - shared_memory->gesture_lifo.buffer_count = 0; - shared_memory->gesture_lifo.buffer_tail = 0; - force_update = true; -} - -void Gesture::OnRelease() {} - -void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - shared_memory = &data->shared_memory_format->gesture; - - if (!IsControllerActivated()) { - shared_memory->gesture_lifo.buffer_count = 0; - shared_memory->gesture_lifo.buffer_tail = 0; - return; - } - - ReadTouchInput(); - - GestureProperties gesture = GetGestureProperties(); - f32 time_difference = - static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / - (1000 * 1000 * 1000); - - // Only update if necessary - if (!ShouldUpdateGesture(gesture, time_difference)) { - return; - } - - last_update_timestamp = shared_memory->gesture_lifo.timestamp; - UpdateGestureSharedMemory(gesture, time_difference); -} - -void Gesture::ReadTouchInput() { - if (!Settings::values.touchscreen.enabled) { - fingers = {}; - return; - } - - const auto touch_status = console->GetTouch(); - for (std::size_t id = 0; id < fingers.size(); ++id) { - fingers[id] = touch_status[id]; - } -} - -bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); - if (force_update) { - force_update = false; - return true; - } - - // Update if coordinates change - for (size_t id = 0; id < MAX_POINTS; id++) { - if (gesture.points[id] != last_gesture.points[id]) { - return true; - } - } - - // Update on press and hold event after 0.5 seconds - if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && - time_difference > press_delay) { - return enable_press_and_tap; - } - - return false; -} - -void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) { - GestureType type = GestureType::Idle; - GestureAttribute attributes{}; - - const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; - - // Reset next state to default - next_state.sampling_number = last_entry.sampling_number + 1; - next_state.delta = {}; - next_state.vel_x = 0; - next_state.vel_y = 0; - next_state.direction = GestureDirection::None; - next_state.rotation_angle = 0; - next_state.scale = 0; - - if (gesture.active_points > 0) { - if (last_gesture.active_points == 0) { - NewGesture(gesture, type, attributes); - } else { - UpdateExistingGesture(gesture, type, time_difference); - } - } else { - EndGesture(gesture, last_gesture, type, attributes, time_difference); - } - - // Apply attributes - next_state.detection_count = gesture.detection_count; - next_state.type = type; - next_state.attributes = attributes; - next_state.pos = gesture.mid_point; - next_state.point_count = static_cast<s32>(gesture.active_points); - next_state.points = gesture.points; - last_gesture = gesture; - - shared_memory->gesture_lifo.WriteNextEntry(next_state); -} - -void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, - GestureAttribute& attributes) { - const auto& last_entry = GetLastGestureEntry(); - - gesture.detection_count++; - type = GestureType::Touch; - - // New touch after cancel is not considered new - if (last_entry.type != GestureType::Cancel) { - attributes.is_new_touch.Assign(1); - enable_press_and_tap = true; - } -} - -void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, - f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); - - // Promote to pan type if touch moved - for (size_t id = 0; id < MAX_POINTS; id++) { - if (gesture.points[id] != last_gesture.points[id]) { - type = GestureType::Pan; - break; - } - } - - // Number of fingers changed cancel the last event and clear data - if (gesture.active_points != last_gesture.active_points) { - type = GestureType::Cancel; - enable_press_and_tap = false; - gesture.active_points = 0; - gesture.mid_point = {}; - gesture.points.fill({}); - return; - } - - // Calculate extra parameters of panning - if (type == GestureType::Pan) { - UpdatePanEvent(gesture, last_gesture, type, time_difference); - return; - } - - // Promote to press type - if (last_entry.type == GestureType::Touch) { - type = GestureType::Press; - } -} - -void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); - - if (last_gesture_props.active_points != 0) { - switch (last_entry.type) { - case GestureType::Touch: - if (enable_press_and_tap) { - SetTapEvent(gesture, last_gesture_props, type, attributes); - return; - } - type = GestureType::Cancel; - force_update = true; - break; - case GestureType::Press: - case GestureType::Tap: - case GestureType::Swipe: - case GestureType::Pinch: - case GestureType::Rotate: - type = GestureType::Complete; - force_update = true; - break; - case GestureType::Pan: - EndPanEvent(gesture, last_gesture_props, type, time_difference); - break; - default: - break; - } - return; - } - if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { - gesture.detection_count++; - } -} - -void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes) { - type = GestureType::Tap; - gesture = last_gesture_props; - force_update = true; - f32 tap_time_difference = - static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); - last_tap_timestamp = last_update_timestamp; - if (tap_time_difference < double_tap_delay) { - attributes.is_double_tap.Assign(1); - } -} - -void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); - - next_state.delta = gesture.mid_point - last_entry.pos; - next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; - next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; - last_pan_time_difference = time_difference; - - // Promote to pinch type - if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > - pinch_threshold) { - type = GestureType::Pinch; - next_state.scale = gesture.average_distance / last_gesture_props.average_distance; - } - - const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / - (1 + (gesture.angle * last_gesture_props.angle))); - // Promote to rotate type - if (std::abs(angle_between_two_lines) > angle_threshold) { - type = GestureType::Rotate; - next_state.scale = 0; - next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; - } -} - -void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); - next_state.vel_x = - static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); - next_state.vel_y = - static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); - const f32 curr_vel = - std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); - - // Set swipe event with parameters - if (curr_vel > swipe_threshold) { - SetSwipeEvent(gesture, last_gesture_props, type); - return; - } - - // End panning without swipe - type = GestureType::Complete; - next_state.vel_x = 0; - next_state.vel_y = 0; - force_update = true; -} - -void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type) { - const auto& last_entry = GetLastGestureEntry(); - - type = GestureType::Swipe; - gesture = last_gesture_props; - force_update = true; - next_state.delta = last_entry.delta; - - if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { - if (next_state.delta.x > 0) { - next_state.direction = GestureDirection::Right; - return; - } - next_state.direction = GestureDirection::Left; - return; - } - if (next_state.delta.y > 0) { - next_state.direction = GestureDirection::Down; - return; - } - next_state.direction = GestureDirection::Up; -} - -const GestureState& Gesture::GetLastGestureEntry() const { - return shared_memory->gesture_lifo.ReadCurrentEntry().state; -} - -GestureProperties Gesture::GetGestureProperties() { - GestureProperties gesture; - std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; - const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), - [](const auto& finger) { return finger.pressed; }); - gesture.active_points = - static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); - - for (size_t id = 0; id < gesture.active_points; ++id) { - const auto& [active_x, active_y] = active_fingers[id].position; - gesture.points[id] = { - .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), - .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), - }; - - // Hack: There is no touch in docked but games still allow it - if (Settings::IsDockedMode()) { - gesture.points[id] = { - .x = static_cast<s32>(active_x * Layout::ScreenDocked::Width), - .y = static_cast<s32>(active_y * Layout::ScreenDocked::Height), - }; - } - - gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); - gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); - } - - for (size_t id = 0; id < gesture.active_points; ++id) { - const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + - Square(gesture.mid_point.y - gesture.points[id].y)); - gesture.average_distance += distance / static_cast<f32>(gesture.active_points); - } - - gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), - static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); - - gesture.detection_count = last_gesture.detection_count; - - return gesture; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h deleted file mode 100644 index 78da1552a..000000000 --- a/src/core/hle/service/hid/controllers/gesture.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> - -#include "common/common_types.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/types/touch_types.h" - -namespace Core::HID { -class EmulatedConsole; -} - -namespace Service::HID { -struct GestureSharedMemoryFormat; - -class Gesture final : public ControllerBase { -public: - explicit Gesture(Core::HID::HIDCore& hid_core_); - ~Gesture() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - // Reads input from all available input engines - void ReadTouchInput(); - - // Returns true if gesture state needs to be updated - bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); - - // Updates the shared memory to the next state - void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference); - - // Initializes new gesture - void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); - - // Updates existing gesture state - void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); - - // Terminates exiting gesture - void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes, f32 time_difference); - - // Set current event to a tap event - void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes); - - // Calculates and set the extra parameters related to a pan event - void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference); - - // Terminates the pan event - void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference); - - // Set current event to a swipe event - void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type); - - // Retrieves the last gesture entry, as indicated by shared memory indices. - [[nodiscard]] const GestureState& GetLastGestureEntry() const; - - // Returns the average distance, angle and middle point of the active fingers - GestureProperties GetGestureProperties(); - - GestureState next_state{}; - GestureSharedMemoryFormat* shared_memory; - Core::HID::EmulatedConsole* console = nullptr; - - std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; - GestureProperties last_gesture{}; - s64 last_update_timestamp{}; - s64 last_tap_timestamp{}; - f32 last_pan_time_difference{}; - bool force_update{false}; - bool enable_press_and_tap{false}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/home_button.cpp b/src/core/hle/service/hid/controllers/home_button.cpp deleted file mode 100644 index 71dd9bc08..000000000 --- a/src/core/hle/service/hid/controllers/home_button.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/home_button.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -HomeButton::HomeButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} - -HomeButton::~HomeButton() = default; - -void HomeButton::OnInit() {} - -void HomeButton::OnRelease() {} - -void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!smart_update) { - return; - } - - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - auto& header = data->shared_memory_format->home_button.header; - header.timestamp = core_timing.GetGlobalTimeNs().count(); - header.total_entry_count = 17; - header.entry_count = 0; - header.last_entry_index = 0; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/home_button.h b/src/core/hle/service/hid/controllers/home_button.h deleted file mode 100644 index e91c2aa5d..000000000 --- a/src/core/hle/service/hid/controllers/home_button.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -class HomeButton final : public ControllerBase { -public: - explicit HomeButton(Core::HID::HIDCore& hid_core_); - ~HomeButton() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - bool smart_update{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp deleted file mode 100644 index c72b3e5ce..000000000 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/keyboard.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -Keyboard::Keyboard(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - emulated_devices = hid_core.GetEmulatedDevices(); -} - -Keyboard::~Keyboard() = default; - -void Keyboard::OnInit() {} - -void Keyboard::OnRelease() {} - -void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - KeyboardSharedMemoryFormat& shared_memory = data->shared_memory_format->keyboard; - - if (!IsControllerActivated()) { - shared_memory.keyboard_lifo.buffer_count = 0; - shared_memory.keyboard_lifo.buffer_tail = 0; - return; - } - - const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; - - if (Settings::values.keyboard_enabled) { - const auto& keyboard_state = emulated_devices->GetKeyboard(); - const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier(); - - next_state.key = keyboard_state; - next_state.modifier = keyboard_modifier_state; - next_state.attribute.is_connected.Assign(1); - } - - shared_memory.keyboard_lifo.WriteNextEntry(next_state); -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h deleted file mode 100644 index e8ca326c6..000000000 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/types/keyboard_types.h" - -namespace Service::HID { -class Keyboard final : public ControllerBase { -public: - explicit Keyboard(Core::HID::HIDCore& hid_core_); - ~Keyboard() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - KeyboardState next_state{}; - Core::HID::EmulatedDevices* emulated_devices = nullptr; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp deleted file mode 100644 index 58deafbc5..000000000 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/frontend/emu_window.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/mouse.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -Mouse::Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - emulated_devices = hid_core.GetEmulatedDevices(); -} - -Mouse::~Mouse() = default; - -void Mouse::OnInit() {} -void Mouse::OnRelease() {} - -void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - MouseSharedMemoryFormat& shared_memory = data->shared_memory_format->mouse; - - if (!IsControllerActivated()) { - shared_memory.mouse_lifo.buffer_count = 0; - shared_memory.mouse_lifo.buffer_tail = 0; - return; - } - - next_state = {}; - - const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; - - if (Settings::values.mouse_enabled) { - const auto& mouse_button_state = emulated_devices->GetMouseButtons(); - const auto& mouse_position_state = emulated_devices->GetMousePosition(); - const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); - next_state.attribute.is_connected.Assign(1); - next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width); - next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height); - next_state.delta_x = next_state.x - last_entry.x; - next_state.delta_y = next_state.y - last_entry.y; - next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; - next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; - - last_mouse_wheel_state = mouse_wheel_state; - next_state.button = mouse_button_state; - } - - shared_memory.mouse_lifo.WriteNextEntry(next_state); -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h deleted file mode 100644 index cefad956c..000000000 --- a/src/core/hle/service/hid/controllers/mouse.h +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Core::HID { -class EmulatedDevices; -struct MouseState; -struct AnalogStickState; -} // namespace Core::HID - -namespace Service::HID { -class Mouse final : public ControllerBase { -public: - explicit Mouse(Core::HID::HIDCore& hid_core_); - ~Mouse() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - Core::HID::MouseState next_state{}; - Core::HID::AnalogStickState last_mouse_wheel_state{}; - Core::HID::EmulatedDevices* emulated_devices = nullptr; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp deleted file mode 100644 index c7aa606bc..000000000 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ /dev/null @@ -1,1346 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include <array> -#include <chrono> -#include <cstring> - -#include "common/assert.h" -#include "common/bit_field.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/errors.h" -#include "core/hle/service/hid/hid_util.h" -#include "core/hle/service/kernel_helpers.h" - -namespace Service::HID { -constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ - Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, - Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, - Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, - Core::HID::NpadIdType::Handheld, -}; - -NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) - : ControllerBase{hid_core_}, service_context{service_context_} { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.device = hid_core.GetEmulatedControllerByIndex(i); - controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = - Core::HID::DEFAULT_VIBRATION_VALUE; - controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = - Core::HID::DEFAULT_VIBRATION_VALUE; - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this, - i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, - .is_npad_service = true, - }; - controller.callback_key = controller.device->SetCallback(engine_callback); - } -} - -NPad::~NPad() { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.device->DeleteCallback(controller.callback_key); - } - OnRelease(); -} - -void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) { - if (type == Core::HID::ControllerTriggerType::All) { - ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); - ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); - return; - } - if (controller_idx >= controller_data.size()) { - return; - } - - auto& controller = controller_data[controller_idx]; - const auto is_connected = controller.device->IsConnected(); - const auto npad_type = controller.device->GetNpadStyleIndex(); - const auto npad_id = controller.device->GetNpadIdType(); - switch (type) { - case Core::HID::ControllerTriggerType::Connected: - case Core::HID::ControllerTriggerType::Disconnected: - if (is_connected == controller.is_connected) { - return; - } - UpdateControllerAt(npad_type, npad_id, is_connected); - break; - case Core::HID::ControllerTriggerType::Battery: { - if (!controller.device->IsConnected()) { - return; - } - auto* shared_memory = controller.shared_memory; - const auto& battery_level = controller.device->GetBattery(); - shared_memory->battery_level_dual = battery_level.dual.battery_level; - shared_memory->battery_level_left = battery_level.left.battery_level; - shared_memory->battery_level_right = battery_level.right.battery_level; - break; - } - default: - break; - } -} - -void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { - auto& controller = GetControllerFromNpadIdType(npad_id); - if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { - return; - } - LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); - const auto controller_type = controller.device->GetNpadStyleIndex(); - const auto& body_colors = controller.device->GetColors(); - const auto& battery_level = controller.device->GetBattery(); - auto* shared_memory = controller.shared_memory; - if (controller_type == Core::HID::NpadStyleIndex::None) { - controller.styleset_changed_event->Signal(); - return; - } - - // Reset memory values - shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; - shared_memory->device_type.raw = 0; - shared_memory->system_properties.raw = 0; - shared_memory->joycon_color.attribute = ColorAttribute::NoController; - shared_memory->joycon_color.attribute = ColorAttribute::NoController; - shared_memory->fullkey_color = {}; - shared_memory->joycon_color.left = {}; - shared_memory->joycon_color.right = {}; - shared_memory->battery_level_dual = {}; - shared_memory->battery_level_left = {}; - shared_memory->battery_level_right = {}; - - switch (controller_type) { - case Core::HID::NpadStyleIndex::None: - ASSERT(false); - break; - case Core::HID::NpadStyleIndex::ProController: - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->fullkey_color.fullkey = body_colors.fullkey; - shared_memory->battery_level_dual = battery_level.dual.battery_level; - shared_memory->style_tag.fullkey.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - shared_memory->system_properties.is_vertical.Assign(1); - shared_memory->system_properties.use_plus.Assign(1); - shared_memory->system_properties.use_minus.Assign(1); - shared_memory->system_properties.is_charging_joy_dual.Assign( - battery_level.dual.is_charging); - shared_memory->applet_footer_type = AppletFooterUiType::SwitchProController; - shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); - break; - case Core::HID::NpadStyleIndex::Handheld: - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->joycon_color.attribute = ColorAttribute::Ok; - shared_memory->fullkey_color.fullkey = body_colors.fullkey; - shared_memory->joycon_color.left = body_colors.left; - shared_memory->joycon_color.right = body_colors.right; - shared_memory->style_tag.handheld.Assign(1); - shared_memory->device_type.handheld_left.Assign(1); - shared_memory->device_type.handheld_right.Assign(1); - shared_memory->system_properties.is_vertical.Assign(1); - shared_memory->system_properties.use_plus.Assign(1); - shared_memory->system_properties.use_minus.Assign(1); - shared_memory->system_properties.use_directional_buttons.Assign(1); - shared_memory->system_properties.is_charging_joy_dual.Assign( - battery_level.left.is_charging); - shared_memory->system_properties.is_charging_joy_left.Assign( - battery_level.left.is_charging); - shared_memory->system_properties.is_charging_joy_right.Assign( - battery_level.right.is_charging); - shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory->applet_footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; - shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->joycon_color.attribute = ColorAttribute::Ok; - shared_memory->style_tag.joycon_dual.Assign(1); - if (controller.is_dual_left_connected) { - shared_memory->joycon_color.left = body_colors.left; - shared_memory->battery_level_left = battery_level.left.battery_level; - shared_memory->device_type.joycon_left.Assign(1); - shared_memory->system_properties.use_minus.Assign(1); - shared_memory->system_properties.is_charging_joy_left.Assign( - battery_level.left.is_charging); - shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); - } - if (controller.is_dual_right_connected) { - shared_memory->joycon_color.right = body_colors.right; - shared_memory->battery_level_right = battery_level.right.battery_level; - shared_memory->device_type.joycon_right.Assign(1); - shared_memory->system_properties.use_plus.Assign(1); - shared_memory->system_properties.is_charging_joy_right.Assign( - battery_level.right.is_charging); - shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); - } - shared_memory->system_properties.use_directional_buttons.Assign(1); - shared_memory->system_properties.is_vertical.Assign(1); - shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; - - if (controller.is_dual_left_connected && controller.is_dual_right_connected) { - shared_memory->applet_footer_type = AppletFooterUiType::JoyDual; - shared_memory->fullkey_color.fullkey = body_colors.left; - shared_memory->battery_level_dual = battery_level.left.battery_level; - shared_memory->system_properties.is_charging_joy_dual.Assign( - battery_level.left.is_charging); - } else if (controller.is_dual_left_connected) { - shared_memory->applet_footer_type = AppletFooterUiType::JoyDualLeftOnly; - shared_memory->fullkey_color.fullkey = body_colors.left; - shared_memory->battery_level_dual = battery_level.left.battery_level; - shared_memory->system_properties.is_charging_joy_dual.Assign( - battery_level.left.is_charging); - } else { - shared_memory->applet_footer_type = AppletFooterUiType::JoyDualRightOnly; - shared_memory->fullkey_color.fullkey = body_colors.right; - shared_memory->battery_level_dual = battery_level.right.battery_level; - shared_memory->system_properties.is_charging_joy_dual.Assign( - battery_level.right.is_charging); - } - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->fullkey_color.fullkey = body_colors.left; - shared_memory->joycon_color.attribute = ColorAttribute::Ok; - shared_memory->joycon_color.left = body_colors.left; - shared_memory->battery_level_dual = battery_level.left.battery_level; - shared_memory->style_tag.joycon_left.Assign(1); - shared_memory->device_type.joycon_left.Assign(1); - shared_memory->system_properties.is_horizontal.Assign(1); - shared_memory->system_properties.use_minus.Assign(1); - shared_memory->system_properties.is_charging_joy_left.Assign( - battery_level.left.is_charging); - shared_memory->applet_footer_type = AppletFooterUiType::JoyLeftHorizontal; - shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->fullkey_color.fullkey = body_colors.right; - shared_memory->joycon_color.attribute = ColorAttribute::Ok; - shared_memory->joycon_color.right = body_colors.right; - shared_memory->battery_level_right = battery_level.right.battery_level; - shared_memory->style_tag.joycon_right.Assign(1); - shared_memory->device_type.joycon_right.Assign(1); - shared_memory->system_properties.is_horizontal.Assign(1); - shared_memory->system_properties.use_plus.Assign(1); - shared_memory->system_properties.is_charging_joy_right.Assign( - battery_level.right.is_charging); - shared_memory->applet_footer_type = AppletFooterUiType::JoyRightHorizontal; - shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); - break; - case Core::HID::NpadStyleIndex::GameCube: - shared_memory->style_tag.gamecube.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - shared_memory->system_properties.is_vertical.Assign(1); - shared_memory->system_properties.use_plus.Assign(1); - break; - case Core::HID::NpadStyleIndex::Pokeball: - shared_memory->style_tag.palma.Assign(1); - shared_memory->device_type.palma.Assign(1); - shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); - break; - case Core::HID::NpadStyleIndex::NES: - shared_memory->style_tag.lark.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - break; - case Core::HID::NpadStyleIndex::SNES: - shared_memory->style_tag.lucia.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - shared_memory->applet_footer_type = AppletFooterUiType::Lucia; - break; - case Core::HID::NpadStyleIndex::N64: - shared_memory->style_tag.lagoon.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - shared_memory->applet_footer_type = AppletFooterUiType::Lagon; - break; - case Core::HID::NpadStyleIndex::SegaGenesis: - shared_memory->style_tag.lager.Assign(1); - shared_memory->device_type.fullkey.Assign(1); - break; - default: - break; - } - - controller.is_connected = true; - controller.device->Connect(); - controller.device->SetLedPattern(); - if (controller_type == Core::HID::NpadStyleIndex::JoyconDual) { - if (controller.is_dual_left_connected) { - controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::LeftIndex, - Common::Input::PollingMode::Active); - } - if (controller.is_dual_right_connected) { - controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::Active); - } - } else { - controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices, - Common::Input::PollingMode::Active); - } - - SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(controller.shared_memory); - hid_core.SetLastActiveController(npad_id); -} - -void NPad::OnInit() { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - if (!IsControllerActivated()) { - return; - } - - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state; - controller.styleset_changed_event = - service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); - } - - supported_npad_id_types.resize(npad_id_list.size()); - std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), - npad_id_list.size() * sizeof(Core::HID::NpadIdType)); - - // Prefill controller buffers - for (auto& controller : controller_data) { - auto* npad = controller.shared_memory; - npad->fullkey_color = { - .attribute = ColorAttribute::NoController, - .fullkey = {}, - }; - npad->joycon_color = { - .attribute = ColorAttribute::NoController, - .left = {}, - .right = {}, - }; - // HW seems to initialize the first 19 entries - for (std::size_t i = 0; i < 19; ++i) { - WriteEmptyEntry(npad); - } - } -} - -void NPad::WriteEmptyEntry(NpadInternalState* npad) { - NPadGenericState dummy_pad_state{}; - NpadGcTriggerState dummy_gc_state{}; - dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1; - npad->fullkey_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1; - npad->handheld_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; - npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1; - npad->joy_left_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1; - npad->joy_right_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1; - npad->palma_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1; - npad->system_ext_lifo.WriteNextEntry(dummy_pad_state); - dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; - npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); -} - -void NPad::OnRelease() { - is_controller_initialized = false; - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - if (controller.styleset_changed_event) { - service_context.CloseEvent(controller.styleset_changed_event); - } - for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { - VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); - } - } -} - -void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { - std::scoped_lock lock{mutex}; - auto& controller = GetControllerFromNpadIdType(npad_id); - const auto controller_type = controller.device->GetNpadStyleIndex(); - - if (!controller.device->IsConnected() && controller.is_connected) { - DisconnectNpad(npad_id); - return; - } - if (!controller.device->IsConnected()) { - return; - } - if (controller.device->IsConnected() && !controller.is_connected) { - InitNewlyAddedController(npad_id); - } - - // This function is unique to yuzu for the turbo buttons and motion to work properly - controller.device->StatusUpdate(); - - auto& pad_entry = controller.npad_pad_state; - auto& trigger_entry = controller.npad_trigger_state; - const auto button_state = controller.device->GetNpadButtons(); - const auto stick_state = controller.device->GetSticks(); - - using btn = Core::HID::NpadButton; - pad_entry.npad_buttons.raw = btn::None; - if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { - constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | - btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | - btn::StickRRight | btn::StickRDown; - pad_entry.npad_buttons.raw = button_state.raw & right_button_mask; - pad_entry.r_stick = stick_state.right; - } - - if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { - constexpr btn left_button_mask = - btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL | - btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown; - pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask; - pad_entry.l_stick = stick_state.left; - } - - if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft || - controller_type == Core::HID::NpadStyleIndex::JoyconDual) { - pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl); - pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr); - } - - if (controller_type == Core::HID::NpadStyleIndex::JoyconRight || - controller_type == Core::HID::NpadStyleIndex::JoyconDual) { - pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); - pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); - } - - if (controller_type == Core::HID::NpadStyleIndex::GameCube) { - const auto& trigger_state = controller.device->GetTriggers(); - trigger_entry.l_analog = trigger_state.left; - trigger_entry.r_analog = trigger_state.right; - pad_entry.npad_buttons.zl.Assign(false); - pad_entry.npad_buttons.zr.Assign(button_state.r); - pad_entry.npad_buttons.l.Assign(button_state.zl); - pad_entry.npad_buttons.r.Assign(button_state.zr); - } - - if (pad_entry.npad_buttons.raw != Core::HID::NpadButton::None) { - hid_core.SetLastActiveController(npad_id); - } -} - -void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - if (!IsControllerActivated()) { - return; - } - - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.shared_memory = &data->shared_memory_format->npad.npad_entry[i].internal_state; - auto* npad = controller.shared_memory; - - const auto& controller_type = controller.device->GetNpadStyleIndex(); - - if (controller_type == Core::HID::NpadStyleIndex::None || - !controller.device->IsConnected()) { - continue; - } - - RequestPadStateUpdate(controller.device->GetNpadIdType()); - auto& pad_state = controller.npad_pad_state; - auto& libnx_state = controller.npad_libnx_state; - auto& trigger_state = controller.npad_trigger_state; - - // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate - // any controllers. - libnx_state.connection_status.raw = 0; - libnx_state.connection_status.is_connected.Assign(1); - switch (controller_type) { - case Core::HID::NpadStyleIndex::None: - ASSERT(false); - break; - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::NES: - case Core::HID::NpadStyleIndex::SNES: - case Core::HID::NpadStyleIndex::N64: - case Core::HID::NpadStyleIndex::SegaGenesis: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); - - libnx_state.connection_status.is_wired.Assign(1); - pad_state.sampling_number = - npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->fullkey_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::Handheld: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); - pad_state.connection_status.is_left_wired.Assign(1); - pad_state.connection_status.is_right_wired.Assign(1); - - libnx_state.connection_status.is_wired.Assign(1); - libnx_state.connection_status.is_left_connected.Assign(1); - libnx_state.connection_status.is_right_connected.Assign(1); - libnx_state.connection_status.is_left_wired.Assign(1); - libnx_state.connection_status.is_right_wired.Assign(1); - pad_state.sampling_number = - npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->handheld_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - if (controller.is_dual_left_connected) { - pad_state.connection_status.is_left_connected.Assign(1); - libnx_state.connection_status.is_left_connected.Assign(1); - } - if (controller.is_dual_right_connected) { - pad_state.connection_status.is_right_connected.Assign(1); - libnx_state.connection_status.is_right_connected.Assign(1); - } - - pad_state.sampling_number = - npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->joy_dual_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - - libnx_state.connection_status.is_left_connected.Assign(1); - pad_state.sampling_number = - npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->joy_left_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); - - libnx_state.connection_status.is_right_connected.Assign(1); - pad_state.sampling_number = - npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->joy_right_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::GameCube: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); - - libnx_state.connection_status.is_wired.Assign(1); - pad_state.sampling_number = - npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - trigger_state.sampling_number = - npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->fullkey_lifo.WriteNextEntry(pad_state); - npad->gc_trigger_lifo.WriteNextEntry(trigger_state); - break; - case Core::HID::NpadStyleIndex::Pokeball: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.sampling_number = - npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad->palma_lifo.WriteNextEntry(pad_state); - break; - default: - break; - } - - libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; - libnx_state.l_stick = pad_state.l_stick; - libnx_state.r_stick = pad_state.r_stick; - npad->system_ext_lifo.WriteNextEntry(pad_state); - - press_state |= static_cast<u64>(pad_state.npad_buttons.raw); - } -} - -void NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { - hid_core.SetSupportedStyleTag(style_set); - - if (is_controller_initialized) { - return; - } - - // Once SetSupportedStyleSet is called controllers are fully initialized - is_controller_initialized = true; -} - -Core::HID::NpadStyleTag NPad::GetSupportedStyleSet() const { - if (!is_controller_initialized) { - return {Core::HID::NpadStyleSet::None}; - } - return hid_core.GetSupportedStyleTag(); -} - -Result NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { - constexpr std::size_t max_number_npad_ids = 0xa; - const auto length = data.size(); - ASSERT(length > 0 && (length % sizeof(u32)) == 0); - const std::size_t elements = length / sizeof(u32); - - if (elements > max_number_npad_ids) { - return InvalidArraySize; - } - - supported_npad_id_types.clear(); - supported_npad_id_types.resize(elements); - std::memcpy(supported_npad_id_types.data(), data.data(), length); - return ResultSuccess; -} - -void NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { - const auto copy_amount = supported_npad_id_types.size() * sizeof(u32); - ASSERT(max_length <= copy_amount); - std::memcpy(data, supported_npad_id_types.data(), copy_amount); -} - -std::size_t NPad::GetSupportedNpadIdTypesSize() const { - return supported_npad_id_types.size(); -} - -void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { - if (joy_hold_type != NpadJoyHoldType::Horizontal && - joy_hold_type != NpadJoyHoldType::Vertical) { - LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}", - joy_hold_type); - return; - } - hold_type = joy_hold_type; -} - -NpadJoyHoldType NPad::GetHoldType() const { - return hold_type; -} - -void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { - if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { - ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); - return; - } - - handheld_activation_mode = activation_mode; -} - -NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { - return handheld_activation_mode; -} - -void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { - communication_mode = communication_mode_; -} - -NpadCommunicationMode NPad::GetNpadCommunicationMode() const { - return communication_mode; -} - -bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, - NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return false; - } - - auto& controller = GetControllerFromNpadIdType(npad_id); - if (controller.shared_memory->assignment_mode != assignment_mode) { - controller.shared_memory->assignment_mode = assignment_mode; - } - - if (!controller.device->IsConnected()) { - return false; - } - - if (assignment_mode == NpadJoyAssignmentMode::Dual) { - if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft) { - DisconnectNpad(npad_id); - controller.is_dual_left_connected = true; - controller.is_dual_right_connected = false; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); - return false; - } - if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) { - DisconnectNpad(npad_id); - controller.is_dual_left_connected = false; - controller.is_dual_right_connected = true; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true); - return false; - } - return false; - } - - // This is for NpadJoyAssignmentMode::Single - - // Only JoyconDual get affected by this function - if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) { - return false; - } - - if (controller.is_dual_left_connected && !controller.is_dual_right_connected) { - DisconnectNpad(npad_id); - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); - return false; - } - if (!controller.is_dual_left_connected && controller.is_dual_right_connected) { - DisconnectNpad(npad_id); - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); - return false; - } - - // We have two controllers connected to the same npad_id we need to split them - new_npad_id = hid_core.GetFirstDisconnectedNpadId(); - auto& controller_2 = GetControllerFromNpadIdType(new_npad_id); - DisconnectNpad(npad_id); - if (npad_device_type == NpadJoyDeviceType::Left) { - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true); - controller_2.is_dual_left_connected = false; - controller_2.is_dual_right_connected = true; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); - } else { - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true); - controller_2.is_dual_left_connected = true; - controller_2.is_dual_right_connected = false; - UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true); - } - return true; -} - -bool NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, - const Core::HID::VibrationValue& vibration_value) { - auto& controller = GetControllerFromNpadIdType(npad_id); - if (!controller.device->IsConnected()) { - return false; - } - - if (!controller.device->IsVibrationEnabled(device_index)) { - if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || - controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { - // Send an empty vibration to stop any vibrations. - Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; - controller.device->SetVibration(device_index, vibration); - // Then reset the vibration value to its default value. - controller.vibration[device_index].latest_vibration_value = - Core::HID::DEFAULT_VIBRATION_VALUE; - } - - return false; - } - - if (!Settings::values.enable_accurate_vibrations.GetValue()) { - using std::chrono::duration_cast; - using std::chrono::milliseconds; - using std::chrono::steady_clock; - - const auto now = steady_clock::now(); - - // Filter out non-zero vibrations that are within 15ms of each other. - if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && - duration_cast<milliseconds>( - now - controller.vibration[device_index].last_vibration_timepoint) < - milliseconds(15)) { - return false; - } - - controller.vibration[device_index].last_vibration_timepoint = now; - } - - Core::HID::VibrationValue vibration{ - vibration_value.low_amplitude, vibration_value.low_frequency, - vibration_value.high_amplitude, vibration_value.high_frequency}; - return controller.device->SetVibration(device_index, vibration); -} - -void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, - const Core::HID::VibrationValue& vibration_value) { - if (IsVibrationHandleValid(vibration_device_handle).IsError()) { - return; - } - - if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { - return; - } - - auto& controller = GetControllerFromHandle(vibration_device_handle); - const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); - - if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { - return; - } - - if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { - ASSERT_MSG(false, "DeviceIndex should never be None!"); - return; - } - - // Some games try to send mismatched parameters in the device handle, block these. - if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || - vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || - (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && - (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || - vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) { - return; - } - - // Filter out vibrations with equivalent values to reduce unnecessary state changes. - if (vibration_value.low_amplitude == - controller.vibration[device_index].latest_vibration_value.low_amplitude && - vibration_value.high_amplitude == - controller.vibration[device_index].latest_vibration_value.high_amplitude) { - return; - } - - if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, - vibration_value)) { - controller.vibration[device_index].latest_vibration_value = vibration_value; - } -} - -void NPad::VibrateControllers( - std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, - std::span<const Core::HID::VibrationValue> vibration_values) { - if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { - return; - } - - ASSERT_OR_EXECUTE_MSG( - vibration_device_handles.size() == vibration_values.size(), { return; }, - "The amount of device handles does not match with the amount of vibration values," - "this is undefined behavior!"); - - for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { - VibrateController(vibration_device_handles[i], vibration_values[i]); - } -} - -Core::HID::VibrationValue NPad::GetLastVibration( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (IsVibrationHandleValid(vibration_device_handle).IsError()) { - return {}; - } - - const auto& controller = GetControllerFromHandle(vibration_device_handle); - const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); - return controller.vibration[device_index].latest_vibration_value; -} - -void NPad::InitializeVibrationDevice( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) { - if (IsVibrationHandleValid(vibration_device_handle).IsError()) { - return; - } - - const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); - const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); - InitializeVibrationDeviceAtIndex(npad_index, device_index); -} - -void NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, - std::size_t device_index) { - auto& controller = GetControllerFromNpadIdType(npad_id); - if (!Settings::values.vibration_enabled.GetValue()) { - controller.vibration[device_index].device_mounted = false; - return; - } - - controller.vibration[device_index].device_mounted = - controller.device->IsVibrationEnabled(device_index); -} - -void NPad::SetPermitVibrationSession(bool permit_vibration_session) { - permit_vibration_session_enabled = permit_vibration_session; -} - -bool NPad::IsVibrationDeviceMounted( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (IsVibrationHandleValid(vibration_device_handle).IsError()) { - return false; - } - - const auto& controller = GetControllerFromHandle(vibration_device_handle); - const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); - return controller.vibration[device_index].device_mounted; -} - -Kernel::KReadableEvent& NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - // Fallback to player 1 - const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); - return controller.styleset_changed_event->GetReadableEvent(); - } - - const auto& controller = GetControllerFromNpadIdType(npad_id); - return controller.styleset_changed_event->GetReadableEvent(); -} - -void NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { - const auto& controller = GetControllerFromNpadIdType(npad_id); - controller.styleset_changed_event->Signal(); -} - -void NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id) { - UpdateControllerAt(controller, npad_id, true); -} - -void NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, Core::HID::NpadIdType npad_id, - bool connected) { - auto& controller = GetControllerFromNpadIdType(npad_id); - if (!connected) { - DisconnectNpad(npad_id); - return; - } - - controller.device->SetNpadStyleIndex(type); - InitNewlyAddedController(npad_id); -} - -Result NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return InvalidNpadId; - } - - LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); - auto& controller = GetControllerFromNpadIdType(npad_id); - for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { - // Send an empty vibration to stop any vibrations. - VibrateControllerAtIndex(npad_id, device_idx, {}); - controller.vibration[device_idx].device_mounted = false; - } - - auto* shared_memory = controller.shared_memory; - // Don't reset shared_memory->assignment_mode this value is persistent - shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out - shared_memory->device_type.raw = 0; - shared_memory->system_properties.raw = 0; - shared_memory->button_properties.raw = 0; - shared_memory->sixaxis_fullkey_properties.raw = 0; - shared_memory->sixaxis_handheld_properties.raw = 0; - shared_memory->sixaxis_dual_left_properties.raw = 0; - shared_memory->sixaxis_dual_right_properties.raw = 0; - shared_memory->sixaxis_left_properties.raw = 0; - shared_memory->sixaxis_right_properties.raw = 0; - shared_memory->battery_level_dual = Core::HID::NpadBatteryLevel::Empty; - shared_memory->battery_level_left = Core::HID::NpadBatteryLevel::Empty; - shared_memory->battery_level_right = Core::HID::NpadBatteryLevel::Empty; - shared_memory->fullkey_color = { - .attribute = ColorAttribute::NoController, - .fullkey = {}, - }; - shared_memory->joycon_color = { - .attribute = ColorAttribute::NoController, - .left = {}, - .right = {}, - }; - shared_memory->applet_footer_type = AppletFooterUiType::None; - - controller.is_dual_left_connected = true; - controller.is_dual_right_connected = true; - controller.is_connected = false; - controller.device->Disconnect(); - SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(shared_memory); - return ResultSuccess; -} - -Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); - is_firmware_available = sixaxis_properties.is_firmware_update_available != 0; - return ResultSuccess; -} - -Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis_properties = GetSixaxisProperties(sixaxis_handle); - sixaxis_properties.is_newly_assigned.Assign(0); - - return ResultSuccess; -} - -Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2) { - if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, - npad_id_2); - return InvalidNpadId; - } - auto& controller_1 = GetControllerFromNpadIdType(npad_id_1); - auto& controller_2 = GetControllerFromNpadIdType(npad_id_2); - auto controller_style_1 = controller_1.device->GetNpadStyleIndex(); - auto controller_style_2 = controller_2.device->GetNpadStyleIndex(); - - // Simplify this code by converting dualjoycon with only a side connected to single joycons - if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) { - if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) { - controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft; - } - if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) { - controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight; - } - } - if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) { - if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) { - controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft; - } - if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) { - controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight; - } - } - - // Invalid merge errors - if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual || - controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) { - return NpadIsDualJoycon; - } - if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft && - controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) { - return NpadIsSameType; - } - if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight && - controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) { - return NpadIsSameType; - } - - // These exceptions are handled as if they where dual joycon - if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft && - controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) { - return NpadIsDualJoycon; - } - if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft && - controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) { - return NpadIsDualJoycon; - } - - // Disconnect the joycons and connect them as dual joycon at the first index. - DisconnectNpad(npad_id_1); - DisconnectNpad(npad_id_2); - controller_1.is_dual_left_connected = true; - controller_1.is_dual_right_connected = true; - AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); - return ResultSuccess; -} - -void NPad::StartLRAssignmentMode() { - // Nothing internally is used for lr assignment mode. Since we have the ability to set the - // controller types from boot, it doesn't really matter about showing a selection screen - is_in_lr_assignment_mode = true; -} - -void NPad::StopLRAssignmentMode() { - is_in_lr_assignment_mode = false; -} - -Result NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2) { - if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, - npad_id_2); - return InvalidNpadId; - } - if (npad_id_1 == Core::HID::NpadIdType::Handheld || - npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || - npad_id_2 == Core::HID::NpadIdType::Other) { - return ResultSuccess; - } - const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; - const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; - const auto type_index_1 = controller_1->GetNpadStyleIndex(); - const auto type_index_2 = controller_2->GetNpadStyleIndex(); - const auto is_connected_1 = controller_1->IsConnected(); - const auto is_connected_2 = controller_2->IsConnected(); - - if (!IsControllerSupported(type_index_1) && is_connected_1) { - return NpadNotConnected; - } - if (!IsControllerSupported(type_index_2) && is_connected_2) { - return NpadNotConnected; - } - - UpdateControllerAt(type_index_2, npad_id_1, is_connected_2); - UpdateControllerAt(type_index_1, npad_id_2, is_connected_1); - - return ResultSuccess; -} - -Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return InvalidNpadId; - } - const auto& controller = GetControllerFromNpadIdType(npad_id).device; - pattern = controller->GetLedPattern(); - return ResultSuccess; -} - -Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, - bool& is_valid) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return InvalidNpadId; - } - const auto& controller = GetControllerFromNpadIdType(npad_id); - is_valid = controller.unintended_home_button_input_protection; - return ResultSuccess; -} - -Result NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, - Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return InvalidNpadId; - } - auto& controller = GetControllerFromNpadIdType(npad_id); - controller.unintended_home_button_input_protection = is_protection_enabled; - return ResultSuccess; -} - -void NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { - analog_stick_use_center_clamp = use_center_clamp; -} - -void NPad::ClearAllConnectedControllers() { - for (auto& controller : controller_data) { - if (controller.device->IsConnected() && - controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { - controller.device->Disconnect(); - controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); - } - } -} - -void NPad::DisconnectAllConnectedControllers() { - for (auto& controller : controller_data) { - controller.device->Disconnect(); - } -} - -void NPad::ConnectAllDisconnectedControllers() { - for (auto& controller : controller_data) { - if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && - !controller.device->IsConnected()) { - controller.device->Connect(); - } - } -} - -void NPad::ClearAllControllers() { - for (auto& controller : controller_data) { - controller.device->Disconnect(); - controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); - } -} - -Core::HID::NpadButton NPad::GetAndResetPressState() { - return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); -} - -void NPad::ApplyNpadSystemCommonPolicy() { - Core::HID::NpadStyleTag styletag{}; - styletag.fullkey.Assign(1); - styletag.handheld.Assign(1); - styletag.joycon_dual.Assign(1); - styletag.system_ext.Assign(1); - styletag.system.Assign(1); - SetSupportedStyleSet(styletag); - - SetNpadHandheldActivationMode(NpadHandheldActivationMode::Dual); - - supported_npad_id_types.clear(); - supported_npad_id_types.resize(10); - supported_npad_id_types[0] = Core::HID::NpadIdType::Player1; - supported_npad_id_types[1] = Core::HID::NpadIdType::Player2; - supported_npad_id_types[2] = Core::HID::NpadIdType::Player3; - supported_npad_id_types[3] = Core::HID::NpadIdType::Player4; - supported_npad_id_types[4] = Core::HID::NpadIdType::Player5; - supported_npad_id_types[5] = Core::HID::NpadIdType::Player6; - supported_npad_id_types[6] = Core::HID::NpadIdType::Player7; - supported_npad_id_types[7] = Core::HID::NpadIdType::Player8; - supported_npad_id_types[8] = Core::HID::NpadIdType::Other; - supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; -} - -bool NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { - if (controller == Core::HID::NpadStyleIndex::Handheld) { - const bool support_handheld = - std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), - Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); - // Handheld is not even a supported type, lets stop here - if (!support_handheld) { - return false; - } - // Handheld shouldn't be supported in docked mode - if (Settings::IsDockedMode()) { - return false; - } - - return true; - } - - if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), - [](Core::HID::NpadIdType npad_id) { - return npad_id <= Core::HID::NpadIdType::Player8; - })) { - Core::HID::NpadStyleTag style = GetSupportedStyleSet(); - switch (controller) { - case Core::HID::NpadStyleIndex::ProController: - return style.fullkey.As<bool>(); - case Core::HID::NpadStyleIndex::JoyconDual: - return style.joycon_dual.As<bool>(); - case Core::HID::NpadStyleIndex::JoyconLeft: - return style.joycon_left.As<bool>(); - case Core::HID::NpadStyleIndex::JoyconRight: - return style.joycon_right.As<bool>(); - case Core::HID::NpadStyleIndex::GameCube: - return style.gamecube.As<bool>(); - case Core::HID::NpadStyleIndex::Pokeball: - return style.palma.As<bool>(); - case Core::HID::NpadStyleIndex::NES: - return style.lark.As<bool>(); - case Core::HID::NpadStyleIndex::SNES: - return style.lucia.As<bool>(); - case Core::HID::NpadStyleIndex::N64: - return style.lagoon.As<bool>(); - case Core::HID::NpadStyleIndex::SegaGenesis: - return style.lager.As<bool>(); - default: - return false; - } - } - - return false; -} - -NPad::NpadControllerData& NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -const NPad::NpadControllerData& NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) const { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -NPad::NpadControllerData& NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -const NPad::NpadControllerData& NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - -const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType( - Core::HID::NpadIdType npad_id) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - -Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) { - auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.shared_memory->sixaxis_fullkey_properties; - case Core::HID::NpadStyleIndex::Handheld: - return controller.shared_memory->sixaxis_handheld_properties; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.shared_memory->sixaxis_dual_left_properties; - } - return controller.shared_memory->sixaxis_dual_right_properties; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.shared_memory->sixaxis_left_properties; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.shared_memory->sixaxis_right_properties; - default: - return controller.shared_memory->sixaxis_fullkey_properties; - } -} - -const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { - const auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.shared_memory->sixaxis_fullkey_properties; - case Core::HID::NpadStyleIndex::Handheld: - return controller.shared_memory->sixaxis_handheld_properties; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.shared_memory->sixaxis_dual_left_properties; - } - return controller.shared_memory->sixaxis_dual_right_properties; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.shared_memory->sixaxis_left_properties; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.shared_memory->sixaxis_right_properties; - default: - return controller.shared_memory->sixaxis_fullkey_properties; - } -} - -AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { - const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; - - return { - .ui_variant = 0, - .footer = shared_memory->applet_footer_type, - }; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h deleted file mode 100644 index 80cfcb2bb..000000000 --- a/src/core/hle/service/hid/controllers/npad.h +++ /dev/null @@ -1,197 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <atomic> -#include <mutex> -#include <span> - -#include "common/common_types.h" -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/types/npad_types.h" - -namespace Core::HID { -class EmulatedController; -enum class ControllerTriggerType; -} // namespace Core::HID - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::KernelHelpers { -class ServiceContext; -} // namespace Service::KernelHelpers - -union Result; - -namespace Service::HID { -class AppletResource; -struct NpadInternalState; -struct NpadSixAxisSensorLifo; -struct NpadSharedMemoryFormat; - -class NPad final : public ControllerBase { -public: - explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); - ~NPad() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - - void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); - Core::HID::NpadStyleTag GetSupportedStyleSet() const; - - Result SetSupportedNpadIdTypes(std::span<const u8> data); - void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); - std::size_t GetSupportedNpadIdTypesSize() const; - - void SetHoldType(NpadJoyHoldType joy_hold_type); - NpadJoyHoldType GetHoldType() const; - - void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); - NpadHandheldActivationMode GetNpadHandheldActivationMode() const; - - void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); - NpadCommunicationMode GetNpadCommunicationMode() const; - - bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, - NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); - - bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, - const Core::HID::VibrationValue& vibration_value); - - void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, - const Core::HID::VibrationValue& vibration_value); - - void VibrateControllers( - std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, - std::span<const Core::HID::VibrationValue> vibration_values); - - Core::HID::VibrationValue GetLastVibration( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - - void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); - - void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); - - void SetPermitVibrationSession(bool permit_vibration_session); - - bool IsVibrationDeviceMounted( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; - - Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); - void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; - - // Adds a new controller at an index. - void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); - // Adds a new controller at an index with connection status. - void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, - bool connected); - - Result DisconnectNpad(Core::HID::NpadIdType npad_id); - - Result IsFirmwareUpdateAvailableForSixAxisSensor( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const; - Result ResetIsSixAxisSensorDeviceNewlyAssigned( - const Core::HID::SixAxisSensorHandle& sixaxis_handle); - - Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; - Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, - bool& is_enabled) const; - Result SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, - Core::HID::NpadIdType npad_id); - void SetAnalogStickUseCenterClamp(bool use_center_clamp); - void ClearAllConnectedControllers(); - void DisconnectAllConnectedControllers(); - void ConnectAllDisconnectedControllers(); - void ClearAllControllers(); - - Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2); - void StartLRAssignmentMode(); - void StopLRAssignmentMode(); - Result SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); - - // Logical OR for all buttons presses on all controllers - // Specifically for cheat engine and other features. - Core::HID::NpadButton GetAndResetPressState(); - - void ApplyNpadSystemCommonPolicy(); - - AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); - -private: - struct VibrationData { - bool device_mounted{}; - Core::HID::VibrationValue latest_vibration_value{}; - std::chrono::steady_clock::time_point last_vibration_timepoint{}; - }; - - struct NpadControllerData { - Kernel::KEvent* styleset_changed_event{}; - NpadInternalState* shared_memory = nullptr; - Core::HID::EmulatedController* device = nullptr; - - std::array<VibrationData, 2> vibration{}; - bool unintended_home_button_input_protection{}; - bool is_connected{}; - - // Dual joycons can have only one side connected - bool is_dual_left_connected{true}; - bool is_dual_right_connected{true}; - - // Current pad state - NPadGenericState npad_pad_state{}; - NPadGenericState npad_libnx_state{}; - NpadGcTriggerState npad_trigger_state{}; - int callback_key{}; - }; - - void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); - void InitNewlyAddedController(Core::HID::NpadIdType npad_id); - bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; - void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); - void WriteEmptyEntry(NpadInternalState* npad); - - NpadControllerData& GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) const; - NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const; - NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); - const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; - - Core::HID::SixAxisSensorProperties& GetSixaxisProperties( - const Core::HID::SixAxisSensorHandle& device_handle); - const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( - const Core::HID::SixAxisSensorHandle& device_handle) const; - - std::atomic<u64> press_state{}; - - std::array<NpadControllerData, NpadCount> controller_data{}; - KernelHelpers::ServiceContext& service_context; - std::mutex mutex; - std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; - NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; - NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; - NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; - bool permit_vibration_session_enabled{false}; - bool analog_stick_use_center_clamp{false}; - bool is_in_lr_assignment_mode{false}; - bool is_controller_initialized{false}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp deleted file mode 100644 index aa0454b5e..000000000 --- a/src/core/hle/service/hid/controllers/palma.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/hid/controllers/palma.h" -#include "core/hle/service/kernel_helpers.h" - -namespace Service::HID { - -Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) - : ControllerBase{hid_core_}, service_context{service_context_} { - controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); - operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); -} - -Palma::~Palma() { - service_context.CloseEvent(operation_complete_event); -}; - -void Palma::OnInit() {} - -void Palma::OnRelease() {} - -void Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!IsControllerActivated()) { - return; - } -} - -Result Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, - PalmaConnectionHandle& handle) { - active_handle.npad_id = npad_id; - handle = active_handle; - return ResultSuccess; -} - -Result Palma::InitializePalma(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - Activate(); - return ResultSuccess; -} - -Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent( - const PalmaConnectionHandle& handle) const { - if (handle.npad_id != active_handle.npad_id) { - LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id); - } - return operation_complete_event->GetReadableEvent(); -} - -Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle, - PalmaOperationType& operation_type, - PalmaOperationData& data) const { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation_type = operation.operation; - data = operation.data; - return ResultSuccess; -} - -Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::PlayActivity; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - fr_mode = fr_mode_; - return ResultSuccess; -} - -Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::ReadStep; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - return ResultSuccess; -} - -Result Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - return ResultSuccess; -} - -void Palma::ReadPalmaApplicationSection() {} - -void Palma::WritePalmaApplicationSection() {} - -Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::ReadUniqueCode; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::SetUniqueCodeInvalid; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -void Palma::WritePalmaActivityEntry() {} - -Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::WriteRgbLedPatternEntry; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, - Common::ProcessAddress t_mem, u64 size) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::WriteWaveEntry; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle, - s32 database_id_version_) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - database_id_version = database_id_version_; - operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion; - operation.result = PalmaResultSuccess; - operation.data[0] = {}; - operation_complete_event->Signal(); - return ResultSuccess; -} - -Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion; - operation.result = PalmaResultSuccess; - operation.data = {}; - operation.data[0] = static_cast<u8>(database_id_version); - operation_complete_event->Signal(); - return ResultSuccess; -} - -void Palma::SuspendPalmaFeature() {} - -Result Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - return operation.result; -} -void Palma::ReadPalmaPlayLog() {} - -void Palma::ResetPalmaPlayLog() {} - -void Palma::SetIsPalmaAllConnectable(bool is_all_connectable) { - // If true controllers are able to be paired - is_connectable = is_all_connectable; -} - -void Palma::SetIsPalmaPairedConnectable() {} - -Result Palma::PairPalma(const PalmaConnectionHandle& handle) { - if (handle.npad_id != active_handle.npad_id) { - return InvalidPalmaHandle; - } - // TODO: Do something - return ResultSuccess; -} - -void Palma::SetPalmaBoostMode(bool boost_mode) {} - -void Palma::CancelWritePalmaWaveEntry() {} - -void Palma::EnablePalmaBoostMode() {} - -void Palma::GetPalmaBluetoothAddress() {} - -void Palma::SetDisallowedPalmaConnection() {} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h deleted file mode 100644 index 73884230d..000000000 --- a/src/core/hle/service/hid/controllers/palma.h +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include "common/common_funcs.h" -#include "common/typed_address.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/errors.h" - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::KernelHelpers { -class ServiceContext; -} - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::HID { -class Palma final : public ControllerBase { -public: - using PalmaOperationData = std::array<u8, 0x140>; - - // This is nn::hid::PalmaOperationType - enum class PalmaOperationType { - PlayActivity, - SetFrModeType, - ReadStep, - EnableStep, - ResetStep, - ReadApplicationSection, - WriteApplicationSection, - ReadUniqueCode, - SetUniqueCodeInvalid, - WriteActivityEntry, - WriteRgbLedPatternEntry, - WriteWaveEntry, - ReadDataBaseIdentificationVersion, - WriteDataBaseIdentificationVersion, - SuspendFeature, - ReadPlayLog, - ResetPlayLog, - }; - - // This is nn::hid::PalmaWaveSet - enum class PalmaWaveSet : u64 { - Small, - Medium, - Large, - }; - - // This is nn::hid::PalmaFrModeType - enum class PalmaFrModeType : u64 { - Off, - B01, - B02, - B03, - Downloaded, - }; - - // This is nn::hid::PalmaFeature - enum class PalmaFeature : u64 { - FrMode, - RumbleFeedback, - Step, - MuteSwitch, - }; - - // This is nn::hid::PalmaOperationInfo - struct PalmaOperationInfo { - PalmaOperationType operation{}; - Result result{PalmaResultSuccess}; - PalmaOperationData data{}; - }; - static_assert(sizeof(PalmaOperationInfo) == 0x148, "PalmaOperationInfo is an invalid size"); - - // This is nn::hid::PalmaActivityEntry - struct PalmaActivityEntry { - u32 rgb_led_pattern_index; - INSERT_PADDING_BYTES(2); - PalmaWaveSet wave_set; - u32 wave_index; - INSERT_PADDING_BYTES(12); - }; - static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size"); - - struct PalmaConnectionHandle { - Core::HID::NpadIdType npad_id; - INSERT_PADDING_BYTES(4); // Unknown - }; - static_assert(sizeof(PalmaConnectionHandle) == 0x8, - "PalmaConnectionHandle has incorrect size."); - - explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); - ~Palma() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - - Result GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, PalmaConnectionHandle& handle); - Result InitializePalma(const PalmaConnectionHandle& handle); - Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent( - const PalmaConnectionHandle& handle) const; - Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle, - PalmaOperationType& operation_type, - PalmaOperationData& data) const; - Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity); - Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_); - Result ReadPalmaStep(const PalmaConnectionHandle& handle); - Result EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled); - Result ResetPalmaStep(const PalmaConnectionHandle& handle); - Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle); - Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle); - Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown); - Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, - Common::ProcessAddress t_mem, u64 size); - Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle, - s32 database_id_version_); - Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle); - Result GetPalmaOperationResult(const PalmaConnectionHandle& handle) const; - void SetIsPalmaAllConnectable(bool is_all_connectable); - Result PairPalma(const PalmaConnectionHandle& handle); - void SetPalmaBoostMode(bool boost_mode); - -private: - void ReadPalmaApplicationSection(); - void WritePalmaApplicationSection(); - void WritePalmaActivityEntry(); - void SuspendPalmaFeature(); - void ReadPalmaPlayLog(); - void ResetPalmaPlayLog(); - void SetIsPalmaPairedConnectable(); - void CancelWritePalmaWaveEntry(); - void EnablePalmaBoostMode(); - void GetPalmaBluetoothAddress(); - void SetDisallowedPalmaConnection(); - - bool is_connectable{}; - s32 database_id_version{}; - PalmaOperationInfo operation{}; - PalmaFrModeType fr_mode{}; - PalmaConnectionHandle active_handle{}; - - Core::HID::EmulatedController* controller; - - Kernel::KEvent* operation_complete_event; - KernelHelpers::ServiceContext& service_context; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/seven_six_axis.cpp b/src/core/hle/service/hid/controllers/seven_six_axis.cpp deleted file mode 100644 index 495568484..000000000 --- a/src/core/hle/service/hid/controllers/seven_six_axis.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include <cstring> -#include "common/common_types.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/frontend/emu_window.h" -#include "core/hid/emulated_console.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/seven_six_axis.h" -#include "core/memory.h" - -namespace Service::HID { -SevenSixAxis::SevenSixAxis(Core::System& system_) - : ControllerBase{system_.HIDCore()}, system{system_} { - console = hid_core.GetEmulatedConsole(); -} - -SevenSixAxis::~SevenSixAxis() = default; - -void SevenSixAxis::OnInit() {} -void SevenSixAxis::OnRelease() {} - -void SevenSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!IsControllerActivated() || transfer_memory == 0) { - seven_sixaxis_lifo.buffer_count = 0; - seven_sixaxis_lifo.buffer_tail = 0; - return; - } - - const auto& last_entry = seven_sixaxis_lifo.ReadCurrentEntry().state; - next_seven_sixaxis_state.sampling_number = last_entry.sampling_number + 1; - - const auto motion_status = console->GetMotion(); - last_global_timestamp = core_timing.GetGlobalTimeNs().count(); - - // This value increments every time the switch goes to sleep - next_seven_sixaxis_state.unknown = 1; - next_seven_sixaxis_state.timestamp = last_global_timestamp - last_saved_timestamp; - next_seven_sixaxis_state.accel = motion_status.accel; - next_seven_sixaxis_state.gyro = motion_status.gyro; - next_seven_sixaxis_state.quaternion = { - { - motion_status.quaternion.xyz.y, - motion_status.quaternion.xyz.x, - -motion_status.quaternion.w, - }, - -motion_status.quaternion.xyz.z, - }; - - seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); - system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo, - sizeof(seven_sixaxis_lifo)); -} - -void SevenSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { - transfer_memory = t_mem; -} - -void SevenSixAxis::ResetTimestamp() { - last_saved_timestamp = last_global_timestamp; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/seven_six_axis.h b/src/core/hle/service/hid/controllers/seven_six_axis.h deleted file mode 100644 index 40e3f5d12..000000000 --- a/src/core/hle/service/hid/controllers/seven_six_axis.h +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "common/quaternion.h" -#include "common/typed_address.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core { -class System; -} // namespace Core - -namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID - -namespace Service::HID { -class SevenSixAxis final : public ControllerBase { -public: - explicit SevenSixAxis(Core::System& system_); - ~SevenSixAxis() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - - // Called on InitializeSevenSixAxisSensor - void SetTransferMemoryAddress(Common::ProcessAddress t_mem); - - // Called on ResetSevenSixAxisSensorTimestamp - void ResetTimestamp(); - -private: - struct SevenSixAxisState { - INSERT_PADDING_WORDS(2); // unused - u64 timestamp{}; - u64 sampling_number{}; - u64 unknown{}; - Common::Vec3f accel{}; - Common::Vec3f gyro{}; - Common::Quaternion<f32> quaternion{}; - }; - static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); - - Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; - static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); - - u64 last_saved_timestamp{}; - u64 last_global_timestamp{}; - - SevenSixAxisState next_seven_sixaxis_state{}; - Common::ProcessAddress transfer_memory{}; - Core::HID::EmulatedConsole* console = nullptr; - - Core::System& system; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp deleted file mode 100644 index 0bc5169c6..000000000 --- a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/core.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/shared_memory_holder.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/errors.h" - -namespace Service::HID { -SharedMemoryHolder::SharedMemoryHolder() {} - -SharedMemoryHolder::~SharedMemoryHolder() { - Finalize(); -} - -Result SharedMemoryHolder::Initialize(Core::System& system) { - shared_memory = Kernel::KSharedMemory::Create(system.Kernel()); - const Result result = shared_memory->Initialize( - system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None, - Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat)); - if (result.IsError()) { - return result; - } - Kernel::KSharedMemory::Register(system.Kernel(), shared_memory); - - is_created = true; - is_mapped = true; - address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer())); - return ResultSuccess; -} - -void SharedMemoryHolder::Finalize() { - if (address != nullptr) { - shared_memory->Close(); - } - is_created = false; - is_mapped = false; - address = nullptr; -} - -bool SharedMemoryHolder::IsMapped() { - return is_mapped; -} - -SharedMemoryFormat* SharedMemoryHolder::GetAddress() { - return address; -} - -Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() { - return shared_memory; -} -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.h b/src/core/hle/service/hid/controllers/shared_memory_holder.h deleted file mode 100644 index 943407c00..000000000 --- a/src/core/hle/service/hid/controllers/shared_memory_holder.h +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KSharedMemory; -} - -namespace Service::HID { -struct SharedMemoryFormat; - -// This is nn::hid::detail::SharedMemoryHolder -class SharedMemoryHolder { -public: - SharedMemoryHolder(); - ~SharedMemoryHolder(); - - Result Initialize(Core::System& system); - void Finalize(); - - bool IsMapped(); - SharedMemoryFormat* GetAddress(); - Kernel::KSharedMemory* GetHandle(); - -private: - bool is_owner{}; - bool is_created{}; - bool is_mapped{}; - INSERT_PADDING_BYTES(0x5); - Kernel::KSharedMemory* shared_memory; - INSERT_PADDING_BYTES(0x38); - SharedMemoryFormat* address = nullptr; -}; -// Correct size is 0x50 bytes -static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size"); - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp deleted file mode 100644 index a5a67dea6..000000000 --- a/src/core/hle/service/hid/controllers/six_axis.cpp +++ /dev/null @@ -1,420 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "common/common_types.h" -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/controllers/six_axis.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/errors.h" -#include "core/hle/service/hid/hid_util.h" - -namespace Service::HID { - -SixAxis::SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_) - : ControllerBase{hid_core_}, npad{npad_} { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.device = hid_core.GetEmulatedControllerByIndex(i); - } -} - -SixAxis::~SixAxis() = default; - -void SixAxis::OnInit() {} -void SixAxis::OnRelease() {} - -void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - if (!IsControllerActivated()) { - return; - } - - for (std::size_t i = 0; i < controller_data.size(); ++i) { - NpadSharedMemoryEntry& shared_memory = data->shared_memory_format->npad.npad_entry[i]; - auto& controller = controller_data[i]; - const auto& controller_type = controller.device->GetNpadStyleIndex(); - - if (controller_type == Core::HID::NpadStyleIndex::None || - !controller.device->IsConnected()) { - continue; - } - - const auto& motion_state = controller.device->GetMotions(); - auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; - auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; - auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; - auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; - auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; - auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; - - auto& sixaxis_fullkey_lifo = shared_memory.internal_state.sixaxis_fullkey_lifo; - auto& sixaxis_handheld_lifo = shared_memory.internal_state.sixaxis_handheld_lifo; - auto& sixaxis_dual_left_lifo = shared_memory.internal_state.sixaxis_dual_left_lifo; - auto& sixaxis_dual_right_lifo = shared_memory.internal_state.sixaxis_dual_right_lifo; - auto& sixaxis_left_lifo = shared_memory.internal_state.sixaxis_left_lifo; - auto& sixaxis_right_lifo = shared_memory.internal_state.sixaxis_right_lifo; - - // Clear previous state - sixaxis_fullkey_state = {}; - sixaxis_handheld_state = {}; - sixaxis_dual_left_state = {}; - sixaxis_dual_right_state = {}; - sixaxis_left_lifo_state = {}; - sixaxis_right_lifo_state = {}; - - if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { - controller.sixaxis_at_rest = true; - for (std::size_t e = 0; e < motion_state.size(); ++e) { - controller.sixaxis_at_rest = - controller.sixaxis_at_rest && motion_state[e].is_at_rest; - } - } - - const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state, - const Core::HID::ControllerMotion& hid_state) { - using namespace std::literals::chrono_literals; - static constexpr Core::HID::SixAxisSensorState default_motion_state = { - .delta_time = std::chrono::nanoseconds(5ms).count(), - .accel = {0, 0, -1.0f}, - .orientation = - { - Common::Vec3f{1.0f, 0, 0}, - Common::Vec3f{0, 1.0f, 0}, - Common::Vec3f{0, 0, 1.0f}, - }, - .attribute = {1}, - }; - if (!controller.sixaxis_sensor_enabled) { - state = default_motion_state; - return; - } - if (!Settings::values.motion_enabled.GetValue()) { - state = default_motion_state; - return; - } - state.attribute.is_connected.Assign(1); - state.delta_time = std::chrono::nanoseconds(5ms).count(); - state.accel = hid_state.accel; - state.gyro = hid_state.gyro; - state.rotation = hid_state.rotation; - state.orientation = hid_state.orientation; - }; - - switch (controller_type) { - case Core::HID::NpadStyleIndex::None: - ASSERT(false); - break; - case Core::HID::NpadStyleIndex::ProController: - set_motion_state(sixaxis_fullkey_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::Handheld: - set_motion_state(sixaxis_handheld_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - set_motion_state(sixaxis_dual_left_state, motion_state[0]); - set_motion_state(sixaxis_dual_right_state, motion_state[1]); - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - set_motion_state(sixaxis_left_lifo_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - set_motion_state(sixaxis_right_lifo_state, motion_state[1]); - break; - case Core::HID::NpadStyleIndex::Pokeball: - using namespace std::literals::chrono_literals; - set_motion_state(sixaxis_fullkey_state, motion_state[0]); - sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count(); - break; - default: - break; - } - - sixaxis_fullkey_state.sampling_number = - sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_handheld_state.sampling_number = - sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_left_state.sampling_number = - sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_right_state.sampling_number = - sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_left_lifo_state.sampling_number = - sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_right_lifo_state.sampling_number = - sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; - - if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { - // This buffer only is updated on handheld on HW - sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state); - } else { - // Handheld doesn't update this buffer on HW - sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state); - } - - sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state); - sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state); - sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state); - sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state); - } -} - -Result SixAxis::SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode drift_mode) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - auto& controller = GetControllerFromHandle(sixaxis_handle); - sixaxis.gyroscope_zero_drift_mode = drift_mode; - controller.device->SetGyroscopeZeroDriftMode(drift_mode); - - return ResultSuccess; -} - -Result SixAxis::GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode& drift_mode) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - drift_mode = sixaxis.gyroscope_zero_drift_mode; - - return ResultSuccess; -} - -Result SixAxis::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_at_rest) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& controller = GetControllerFromHandle(sixaxis_handle); - is_at_rest = controller.sixaxis_at_rest; - return ResultSuccess; -} - -Result SixAxis::LoadSixAxisSensorCalibrationParameter( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorCalibrationParameter& calibration) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - // TODO: Request this data to the controller. On error return 0xd8ca - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - calibration = sixaxis.calibration; - return ResultSuccess; -} - -Result SixAxis::GetSixAxisSensorIcInformation( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorIcInformation& ic_information) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - // TODO: Request this data to the controller. On error return 0xd8ca - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - ic_information = sixaxis.ic_information; - return ResultSuccess; -} - -Result SixAxis::EnableSixAxisSensorUnalteredPassthrough( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.unaltered_passtrough = is_enabled; - return ResultSuccess; -} - -Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - is_enabled = sixaxis.unaltered_passtrough; - return ResultSuccess; -} - -Result SixAxis::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool sixaxis_status) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.sixaxis_sensor_enabled = sixaxis_status; - return ResultSuccess; -} - -Result SixAxis::IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_fusion_enabled) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - is_fusion_enabled = sixaxis.is_fusion_enabled; - - return ResultSuccess; -} -Result SixAxis::SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool is_fusion_enabled) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.is_fusion_enabled = is_fusion_enabled; - - return ResultSuccess; -} - -Result SixAxis::SetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto param1 = sixaxis_fusion_parameters.parameter1; - if (param1 < 0.0f || param1 > 1.0f) { - return InvalidSixAxisFusionRange; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.fusion = sixaxis_fusion_parameters; - - return ResultSuccess; -} - -Result SixAxis::GetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters& parameters) const { - const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - parameters = sixaxis.fusion; - - return ResultSuccess; -} - -SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) { - auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.sixaxis_fullkey; - case Core::HID::NpadStyleIndex::Handheld: - return controller.sixaxis_handheld; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.sixaxis_dual_left; - } - return controller.sixaxis_dual_right; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.sixaxis_left; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.sixaxis_right; - default: - return controller.sixaxis_unknown; - } -} - -const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { - const auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.sixaxis_fullkey; - case Core::HID::NpadStyleIndex::Handheld: - return controller.sixaxis_handheld; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.sixaxis_dual_left; - } - return controller.sixaxis_dual_right; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.sixaxis_left; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.sixaxis_right; - default: - return controller.sixaxis_unknown; - } -} - -SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -const SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const { - const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - -const SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType( - Core::HID::NpadIdType npad_id) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/six_axis.h b/src/core/hle/service/hid/controllers/six_axis.h deleted file mode 100644 index 4c4f5dc7b..000000000 --- a/src/core/hle/service/hid/controllers/six_axis.h +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::HID { -class NPad; - -class SixAxis final : public ControllerBase { -public: - explicit SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_); - ~SixAxis() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - - Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode drift_mode); - Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode& drift_mode) const; - Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_at_rest) const; - Result EnableSixAxisSensorUnalteredPassthrough( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled); - Result IsSixAxisSensorUnalteredPassthroughEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const; - Result LoadSixAxisSensorCalibrationParameter( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorCalibrationParameter& calibration) const; - Result GetSixAxisSensorIcInformation( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorIcInformation& ic_information) const; - Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool sixaxis_status); - Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_fusion_enabled) const; - Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool is_fusion_enabled); - Result SetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); - Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters& parameters) const; - -private: - static constexpr std::size_t NPAD_COUNT = 10; - - struct SixaxisParameters { - bool is_fusion_enabled{true}; - bool unaltered_passtrough{false}; - Core::HID::SixAxisSensorFusionParameters fusion{}; - Core::HID::SixAxisSensorCalibrationParameter calibration{}; - Core::HID::SixAxisSensorIcInformation ic_information{}; - Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{ - Core::HID::GyroscopeZeroDriftMode::Standard}; - }; - - struct NpadControllerData { - Core::HID::EmulatedController* device = nullptr; - - // Motion parameters - bool sixaxis_at_rest{true}; - bool sixaxis_sensor_enabled{true}; - SixaxisParameters sixaxis_fullkey{}; - SixaxisParameters sixaxis_handheld{}; - SixaxisParameters sixaxis_dual_left{}; - SixaxisParameters sixaxis_dual_right{}; - SixaxisParameters sixaxis_left{}; - SixaxisParameters sixaxis_right{}; - SixaxisParameters sixaxis_unknown{}; - - // Current pad state - Core::HID::SixAxisSensorState sixaxis_fullkey_state{}; - Core::HID::SixAxisSensorState sixaxis_handheld_state{}; - Core::HID::SixAxisSensorState sixaxis_dual_left_state{}; - Core::HID::SixAxisSensorState sixaxis_dual_right_state{}; - Core::HID::SixAxisSensorState sixaxis_left_lifo_state{}; - Core::HID::SixAxisSensorState sixaxis_right_lifo_state{}; - int callback_key{}; - }; - - SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle); - const SixaxisParameters& GetSixaxisState( - const Core::HID::SixAxisSensorHandle& device_handle) const; - - NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const; - NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); - const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; - - std::shared_ptr<NPad> npad; - std::array<NpadControllerData, NPAD_COUNT> controller_data{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/sleep_button.cpp b/src/core/hle/service/hid/controllers/sleep_button.cpp deleted file mode 100644 index 978dc4c1f..000000000 --- a/src/core/hle/service/hid/controllers/sleep_button.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/sleep_button.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -SleepButton::SleepButton(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} - -SleepButton::~SleepButton() = default; - -void SleepButton::OnInit() {} - -void SleepButton::OnRelease() {} - -void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!smart_update) { - return; - } - - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - auto& header = data->shared_memory_format->capture_button.header; - header.timestamp = core_timing.GetGlobalTimeNs().count(); - header.total_entry_count = 17; - header.entry_count = 0; - header.last_entry_index = 0; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/sleep_button.h b/src/core/hle/service/hid/controllers/sleep_button.h deleted file mode 100644 index 59964bf63..000000000 --- a/src/core/hle/service/hid/controllers/sleep_button.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -class SleepButton final : public ControllerBase { -public: - explicit SleepButton(Core::HID::HIDCore& hid_core_); - ~SleepButton() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - bool smart_update{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp deleted file mode 100644 index 291dc707e..000000000 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include "common/common_types.h" -#include "common/settings.h" -#include "core/core_timing.h" -#include "core/frontend/emu_window.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" - -namespace Service::HID { - -TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_) - : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width), - touchscreen_height(Layout::ScreenUndocked::Height) { - console = hid_core.GetEmulatedConsole(); -} - -TouchScreen::~TouchScreen() = default; - -void TouchScreen::OnInit() {} - -void TouchScreen::OnRelease() {} - -void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - TouchScreenSharedMemoryFormat& shared_memory = data->shared_memory_format->touch_screen; - shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); - - if (!IsControllerActivated()) { - shared_memory.touch_screen_lifo.buffer_count = 0; - shared_memory.touch_screen_lifo.buffer_tail = 0; - return; - } - - const auto touch_status = console->GetTouch(); - for (std::size_t id = 0; id < MAX_FINGERS; id++) { - const auto& current_touch = touch_status[id]; - auto& finger = fingers[id]; - finger.id = current_touch.id; - - if (finger.attribute.start_touch) { - finger.attribute.raw = 0; - continue; - } - - if (finger.attribute.end_touch) { - finger.attribute.raw = 0; - finger.pressed = false; - continue; - } - - if (!finger.pressed && current_touch.pressed) { - // Ignore all touch fingers if disabled - if (!Settings::values.touchscreen.enabled) { - continue; - } - - finger.attribute.start_touch.Assign(1); - finger.pressed = true; - finger.position = current_touch.position; - continue; - } - - if (finger.pressed && !current_touch.pressed) { - finger.attribute.raw = 0; - finger.attribute.end_touch.Assign(1); - continue; - } - - // Only update position if touch is not on a special frame - finger.position = current_touch.position; - } - - std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers; - const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), - [](const auto& finger) { return finger.pressed; }); - const auto active_fingers_count = - static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); - - const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count()); - const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state; - - next_state.sampling_number = last_entry.sampling_number + 1; - next_state.entry_count = static_cast<s32>(active_fingers_count); - - for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - auto& touch_entry = next_state.states[id]; - if (id < active_fingers_count) { - const auto& [active_x, active_y] = active_fingers[id].position; - touch_entry.position = { - .x = static_cast<u16>(active_x * static_cast<float>(touchscreen_width)), - .y = static_cast<u16>(active_y * static_cast<float>(touchscreen_height)), - }; - touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; - touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; - touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; - touch_entry.delta_time = timestamp - active_fingers[id].last_touch; - fingers[active_fingers[id].id].last_touch = timestamp; - touch_entry.finger = active_fingers[id].id; - touch_entry.attribute.raw = active_fingers[id].attribute.raw; - } else { - // Clear touch entry - touch_entry.attribute.raw = 0; - touch_entry.position = {}; - touch_entry.diameter_x = 0; - touch_entry.diameter_y = 0; - touch_entry.rotation_angle = 0; - touch_entry.delta_time = 0; - touch_entry.finger = 0; - } - } - - shared_memory.touch_screen_lifo.WriteNextEntry(next_state); -} - -void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) { - touchscreen_width = width; - touchscreen_height = height; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h deleted file mode 100644 index 945d359be..000000000 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> - -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/types/touch_types.h" - -namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID - -namespace Service::HID { -struct TouchScreenSharedMemoryFormat; - -class TouchScreen final : public ControllerBase { -public: - explicit TouchScreen(Core::HID::HIDCore& hid_core_); - ~TouchScreen() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - - void SetTouchscreenDimensions(u32 width, u32 height); - -private: - TouchScreenState next_state{}; - Core::HID::EmulatedConsole* console = nullptr; - - std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; - u32 touchscreen_width; - u32 touchscreen_height; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/debug_pad_types.h b/src/core/hle/service/hid/controllers/types/debug_pad_types.h deleted file mode 100644 index a96171b62..000000000 --- a/src/core/hle/service/hid/controllers/types/debug_pad_types.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hid/hid_types.h" - -namespace Service::HID { - -// This is nn::hid::DebugPadAttribute -struct DebugPadAttribute { - union { - u32 raw{}; - BitField<0, 1, u32> connected; - }; -}; -static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); - -// This is nn::hid::DebugPadState -struct DebugPadState { - s64 sampling_number{}; - DebugPadAttribute attribute{}; - Core::HID::DebugPadButton pad_state{}; - Core::HID::AnalogStickState r_stick{}; - Core::HID::AnalogStickState l_stick{}; -}; -static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/gesture_types.h b/src/core/hle/service/hid/controllers/types/gesture_types.h deleted file mode 100644 index b4f034cd3..000000000 --- a/src/core/hle/service/hid/controllers/types/gesture_types.h +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <array> -#include "common/bit_field.h" -#include "common/common_types.h" -#include "common/point.h" - -namespace Service::HID { -static constexpr size_t MAX_FINGERS = 16; -static constexpr size_t MAX_POINTS = 4; - -// This is nn::hid::GestureType -enum class GestureType : u32 { - Idle, // Nothing touching the screen - Complete, // Set at the end of a touch event - Cancel, // Set when the number of fingers change - Touch, // A finger just touched the screen - Press, // Set if last type is touch and the finger hasn't moved - Tap, // Fast press then release - Pan, // All points moving together across the screen - Swipe, // Fast press movement and release of a single point - Pinch, // All points moving away/closer to the midpoint - Rotate, // All points rotating from the midpoint -}; - -// This is nn::hid::GestureDirection -enum class GestureDirection : u32 { - None, - Left, - Up, - Right, - Down, -}; - -// This is nn::hid::GestureAttribute -struct GestureAttribute { - union { - u32 raw{}; - - BitField<4, 1, u32> is_new_touch; - BitField<8, 1, u32> is_double_tap; - }; -}; -static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); - -// This is nn::hid::GestureState -struct GestureState { - s64 sampling_number{}; - s64 detection_count{}; - GestureType type{GestureType::Idle}; - GestureDirection direction{GestureDirection::None}; - Common::Point<s32> pos{}; - Common::Point<s32> delta{}; - f32 vel_x{}; - f32 vel_y{}; - GestureAttribute attributes{}; - f32 scale{}; - f32 rotation_angle{}; - s32 point_count{}; - std::array<Common::Point<s32>, 4> points{}; -}; -static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); - -struct GestureProperties { - std::array<Common::Point<s32>, MAX_POINTS> points{}; - std::size_t active_points{}; - Common::Point<s32> mid_point{}; - s64 detection_count{}; - u64 delta_time{}; - f32 average_distance{}; - f32 angle{}; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/keyboard_types.h b/src/core/hle/service/hid/controllers/types/keyboard_types.h deleted file mode 100644 index f44a536b9..000000000 --- a/src/core/hle/service/hid/controllers/types/keyboard_types.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hid/hid_types.h" - -namespace Service::HID { - -// This is nn::hid::detail::KeyboardState -struct KeyboardState { - s64 sampling_number{}; - Core::HID::KeyboardModifier modifier{}; - Core::HID::KeyboardAttribute attribute{}; - Core::HID::KeyboardKey key{}; -}; -static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/mouse_types.h b/src/core/hle/service/hid/controllers/types/mouse_types.h deleted file mode 100644 index 8bd6e167c..000000000 --- a/src/core/hle/service/hid/controllers/types/mouse_types.h +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" - -namespace Service::HID {} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h deleted file mode 100644 index a5ce2562b..000000000 --- a/src/core/hle/service/hid/controllers/types/npad_types.h +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hid/hid_types.h" - -namespace Service::HID { -static constexpr std::size_t NpadCount = 10; - -// This is nn::hid::NpadJoyHoldType -enum class NpadJoyHoldType : u64 { - Vertical = 0, - Horizontal = 1, -}; - -// This is nn::hid::NpadJoyAssignmentMode -enum class NpadJoyAssignmentMode : u32 { - Dual = 0, - Single = 1, -}; - -// This is nn::hid::NpadJoyDeviceType -enum class NpadJoyDeviceType : s64 { - Left = 0, - Right = 1, -}; - -// This is nn::hid::NpadHandheldActivationMode -enum class NpadHandheldActivationMode : u64 { - Dual = 0, - Single = 1, - None = 2, - MaxActivationMode = 3, -}; - -// This is nn::hid::system::AppletFooterUiAttributesSet -struct AppletFooterUiAttributes { - INSERT_PADDING_BYTES(0x4); -}; - -// This is nn::hid::system::AppletFooterUiType -enum class AppletFooterUiType : u8 { - None = 0, - HandheldNone = 1, - HandheldJoyConLeftOnly = 2, - HandheldJoyConRightOnly = 3, - HandheldJoyConLeftJoyConRight = 4, - JoyDual = 5, - JoyDualLeftOnly = 6, - JoyDualRightOnly = 7, - JoyLeftHorizontal = 8, - JoyLeftVertical = 9, - JoyRightHorizontal = 10, - JoyRightVertical = 11, - SwitchProController = 12, - CompatibleProController = 13, - CompatibleJoyCon = 14, - LarkHvc1 = 15, - LarkHvc2 = 16, - LarkNesLeft = 17, - LarkNesRight = 18, - Lucia = 19, - Verification = 20, - Lagon = 21, -}; - -using AppletFooterUiVariant = u8; - -// This is "nn::hid::system::AppletDetailedUiType". -struct AppletDetailedUiType { - AppletFooterUiVariant ui_variant; - INSERT_PADDING_BYTES(0x2); - AppletFooterUiType footer; -}; -static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size"); -// This is nn::hid::NpadCommunicationMode -enum class NpadCommunicationMode : u64 { - Mode_5ms = 0, - Mode_10ms = 1, - Mode_15ms = 2, - Default = 3, -}; - -enum class NpadRevision : u32 { - Revision0 = 0, - Revision1 = 1, - Revision2 = 2, - Revision3 = 3, -}; - -// This is nn::hid::detail::ColorAttribute -enum class ColorAttribute : u32 { - Ok = 0, - ReadError = 1, - NoController = 2, -}; -static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); - -// This is nn::hid::detail::NpadFullKeyColorState -struct NpadFullKeyColorState { - ColorAttribute attribute{ColorAttribute::NoController}; - Core::HID::NpadControllerColor fullkey{}; -}; -static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); - -// This is nn::hid::detail::NpadJoyColorState -struct NpadJoyColorState { - ColorAttribute attribute{ColorAttribute::NoController}; - Core::HID::NpadControllerColor left{}; - Core::HID::NpadControllerColor right{}; -}; -static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); - -// This is nn::hid::NpadAttribute -struct NpadAttribute { - union { - u32 raw{}; - BitField<0, 1, u32> is_connected; - BitField<1, 1, u32> is_wired; - BitField<2, 1, u32> is_left_connected; - BitField<3, 1, u32> is_left_wired; - BitField<4, 1, u32> is_right_connected; - BitField<5, 1, u32> is_right_wired; - }; -}; -static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); - -// This is nn::hid::NpadFullKeyState -// This is nn::hid::NpadHandheldState -// This is nn::hid::NpadJoyDualState -// This is nn::hid::NpadJoyLeftState -// This is nn::hid::NpadJoyRightState -// This is nn::hid::NpadPalmaState -// This is nn::hid::NpadSystemExtState -struct NPadGenericState { - s64_le sampling_number{}; - Core::HID::NpadButtonState npad_buttons{}; - Core::HID::AnalogStickState l_stick{}; - Core::HID::AnalogStickState r_stick{}; - NpadAttribute connection_status{}; - INSERT_PADDING_BYTES(4); // Reserved -}; -static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); - -// This is nn::hid::server::NpadGcTriggerState -struct NpadGcTriggerState { - s64 sampling_number{}; - s32 l_analog{}; - s32 r_analog{}; -}; -static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); - -// This is nn::hid::NpadSystemProperties -struct NPadSystemProperties { - union { - s64 raw{}; - BitField<0, 1, s64> is_charging_joy_dual; - BitField<1, 1, s64> is_charging_joy_left; - BitField<2, 1, s64> is_charging_joy_right; - BitField<3, 1, s64> is_powered_joy_dual; - BitField<4, 1, s64> is_powered_joy_left; - BitField<5, 1, s64> is_powered_joy_right; - BitField<9, 1, s64> is_system_unsupported_button; - BitField<10, 1, s64> is_system_ext_unsupported_button; - BitField<11, 1, s64> is_vertical; - BitField<12, 1, s64> is_horizontal; - BitField<13, 1, s64> use_plus; - BitField<14, 1, s64> use_minus; - BitField<15, 1, s64> use_directional_buttons; - }; -}; -static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); - -// This is nn::hid::NpadSystemButtonProperties -struct NpadSystemButtonProperties { - union { - s32 raw{}; - BitField<0, 1, s32> is_home_button_protection_enabled; - }; -}; -static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); - -// This is nn::hid::system::DeviceType -struct DeviceType { - union { - u32 raw{}; - BitField<0, 1, s32> fullkey; - BitField<1, 1, s32> debug_pad; - BitField<2, 1, s32> handheld_left; - BitField<3, 1, s32> handheld_right; - BitField<4, 1, s32> joycon_left; - BitField<5, 1, s32> joycon_right; - BitField<6, 1, s32> palma; - BitField<7, 1, s32> lark_hvc_left; - BitField<8, 1, s32> lark_hvc_right; - BitField<9, 1, s32> lark_nes_left; - BitField<10, 1, s32> lark_nes_right; - BitField<11, 1, s32> handheld_lark_hvc_left; - BitField<12, 1, s32> handheld_lark_hvc_right; - BitField<13, 1, s32> handheld_lark_nes_left; - BitField<14, 1, s32> handheld_lark_nes_right; - BitField<15, 1, s32> lucia; - BitField<16, 1, s32> lagon; - BitField<17, 1, s32> lager; - BitField<31, 1, s32> system; - }; -}; - -// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl -struct NfcXcdDeviceHandleStateImpl { - u64 handle{}; - bool is_available{}; - bool is_activated{}; - INSERT_PADDING_BYTES(0x6); // Reserved - u64 sampling_number{}; -}; -static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, - "NfcXcdDeviceHandleStateImpl is an invalid size"); - -// This is nn::hid::NpadLarkType -enum class NpadLarkType : u32 { - Invalid, - H1, - H2, - NL, - NR, -}; - -// This is nn::hid::NpadLuciaType -enum class NpadLuciaType : u32 { - Invalid, - J, - E, - U, -}; - -// This is nn::hid::NpadLagonType -enum class NpadLagonType : u32 { - Invalid, -}; - -// This is nn::hid::NpadLagerType -enum class NpadLagerType : u32 { - Invalid, - J, - E, - U, -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/shared_memory_format.h b/src/core/hle/service/hid/controllers/types/shared_memory_format.h deleted file mode 100644 index 2986c113e..000000000 --- a/src/core/hle/service/hid/controllers/types/shared_memory_format.h +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/vector_math.h" -#include "core/hid/hid_types.h" -#include "core/hle/service/hid//controllers/types/debug_pad_types.h" -#include "core/hle/service/hid//controllers/types/keyboard_types.h" -#include "core/hle/service/hid//controllers/types/mouse_types.h" -#include "core/hle/service/hid//controllers/types/npad_types.h" -#include "core/hle/service/hid//controllers/types/touch_types.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Service::HID { -static const std::size_t HidEntryCount = 17; - -struct CommonHeader { - s64 timestamp{}; - s64 total_entry_count{}; - s64 last_entry_index{}; - s64 entry_count{}; -}; -static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - -// This is nn::hid::detail::DebugPadSharedMemoryFormat -struct DebugPadSharedMemoryFormat { - // This is nn::hid::detail::DebugPadLifo - Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{}; - static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x4E); -}; -static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400, - "DebugPadSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::TouchScreenSharedMemoryFormat -struct TouchScreenSharedMemoryFormat { - // This is nn::hid::detail::TouchScreenLifo - Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{}; - static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); - INSERT_PADDING_WORDS(0xF2); -}; -static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000, - "TouchScreenSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::MouseSharedMemoryFormat -struct MouseSharedMemoryFormat { - // This is nn::hid::detail::MouseLifo - Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{}; - static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x2C); -}; -static_assert(sizeof(MouseSharedMemoryFormat) == 0x400, - "MouseSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::KeyboardSharedMemoryFormat -struct KeyboardSharedMemoryFormat { - // This is nn::hid::detail::KeyboardLifo - Lifo<KeyboardState, HidEntryCount> keyboard_lifo{}; - static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); - INSERT_PADDING_WORDS(0xA); -}; -static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400, - "KeyboardSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::DigitizerSharedMemoryFormat -struct DigitizerSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0xFE0); -}; -static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000, - "DigitizerSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::HomeButtonSharedMemoryFormat -struct HomeButtonSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0x1E0); -}; -static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200, - "HomeButtonSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::SleepButtonSharedMemoryFormat -struct SleepButtonSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0x1E0); -}; -static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200, - "SleepButtonSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::CaptureButtonSharedMemoryFormat -struct CaptureButtonSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0x1E0); -}; -static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200, - "CaptureButtonSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::InputDetectorSharedMemoryFormat -struct InputDetectorSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0x7E0); -}; -static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800, - "InputDetectorSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::UniquePadSharedMemoryFormat -struct UniquePadSharedMemoryFormat { - CommonHeader header; - INSERT_PADDING_BYTES(0x3FE0); -}; -static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000, - "UniquePadSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::NpadSixAxisSensorLifo -struct NpadSixAxisSensorLifo { - Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo; -}; - -// This is nn::hid::detail::NpadInternalState -struct NpadInternalState { - Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; - NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; - NpadFullKeyColorState fullkey_color{}; - NpadJoyColorState joycon_color{}; - Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{}; - Lifo<NPadGenericState, HidEntryCount> handheld_lifo{}; - Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{}; - Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{}; - Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{}; - Lifo<NPadGenericState, HidEntryCount> palma_lifo{}; - Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{}; - NpadSixAxisSensorLifo sixaxis_fullkey_lifo{}; - NpadSixAxisSensorLifo sixaxis_handheld_lifo{}; - NpadSixAxisSensorLifo sixaxis_dual_left_lifo{}; - NpadSixAxisSensorLifo sixaxis_dual_right_lifo{}; - NpadSixAxisSensorLifo sixaxis_left_lifo{}; - NpadSixAxisSensorLifo sixaxis_right_lifo{}; - DeviceType device_type{}; - INSERT_PADDING_BYTES(0x4); // Reserved - NPadSystemProperties system_properties{}; - NpadSystemButtonProperties button_properties{}; - Core::HID::NpadBatteryLevel battery_level_dual{}; - Core::HID::NpadBatteryLevel battery_level_left{}; - Core::HID::NpadBatteryLevel battery_level_right{}; - AppletFooterUiAttributes applet_footer_attributes{}; - AppletFooterUiType applet_footer_type{AppletFooterUiType::None}; - INSERT_PADDING_BYTES(0x5B); // Reserved - INSERT_PADDING_BYTES(0x20); // Unknown - Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{}; - NpadLarkType lark_type_l_and_main{}; - NpadLarkType lark_type_r{}; - NpadLuciaType lucia_type{}; - NpadLagerType lager_type{}; - Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties; - Core::HID::SixAxisSensorProperties sixaxis_handheld_properties; - Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties; - Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties; - Core::HID::SixAxisSensorProperties sixaxis_left_properties; - Core::HID::SixAxisSensorProperties sixaxis_right_properties; -}; -static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size"); - -// This is nn::hid::detail::NpadSharedMemoryEntry -struct NpadSharedMemoryEntry { - NpadInternalState internal_state; - INSERT_PADDING_BYTES(0xC08); -}; -static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size"); - -// This is nn::hid::detail::NpadSharedMemoryFormat -struct NpadSharedMemoryFormat { - std::array<NpadSharedMemoryEntry, NpadCount> npad_entry; -}; -static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000, - "NpadSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::GestureSharedMemoryFormat -struct GestureSharedMemoryFormat { - // This is nn::hid::detail::GestureLifo - Lifo<GestureState, HidEntryCount> gesture_lifo{}; - static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x3E); -}; -static_assert(sizeof(GestureSharedMemoryFormat) == 0x800, - "GestureSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat -struct ConsoleSixAxisSensorSharedMemoryFormat { - u64 sampling_number{}; - bool is_seven_six_axis_sensor_at_rest{}; - INSERT_PADDING_BYTES(3); // padding - f32 verticalization_error{}; - Common::Vec3f gyro_bias{}; - INSERT_PADDING_BYTES(4); // padding -}; -static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20, - "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size"); - -// This is nn::hid::detail::SharedMemoryFormat -struct SharedMemoryFormat { - void Initialize() {} - - DebugPadSharedMemoryFormat debug_pad; - TouchScreenSharedMemoryFormat touch_screen; - MouseSharedMemoryFormat mouse; - KeyboardSharedMemoryFormat keyboard; - DigitizerSharedMemoryFormat digitizer; - HomeButtonSharedMemoryFormat home_button; - SleepButtonSharedMemoryFormat sleep_button; - CaptureButtonSharedMemoryFormat capture_button; - InputDetectorSharedMemoryFormat input_detector; - UniquePadSharedMemoryFormat unique_pad; - NpadSharedMemoryFormat npad; - GestureSharedMemoryFormat gesture; - ConsoleSixAxisSensorSharedMemoryFormat console; - INSERT_PADDING_BYTES(0x19E0); - MouseSharedMemoryFormat debug_mouse; - INSERT_PADDING_BYTES(0x2000); -}; -static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00, - "sleep_button has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000, - "capture_button has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200, - "input_detector has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset"); -static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset"); -static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size"); - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/types/touch_types.h b/src/core/hle/service/hid/controllers/types/touch_types.h deleted file mode 100644 index efeaa796d..000000000 --- a/src/core/hle/service/hid/controllers/types/touch_types.h +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <array> - -#include <array> -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/point.h" -#include "core/hid/hid_types.h" - -namespace Service::HID { -static constexpr std::size_t MAX_FINGERS = 16; -static constexpr size_t MAX_POINTS = 4; - -// This is nn::hid::GestureType -enum class GestureType : u32 { - Idle, // Nothing touching the screen - Complete, // Set at the end of a touch event - Cancel, // Set when the number of fingers change - Touch, // A finger just touched the screen - Press, // Set if last type is touch and the finger hasn't moved - Tap, // Fast press then release - Pan, // All points moving together across the screen - Swipe, // Fast press movement and release of a single point - Pinch, // All points moving away/closer to the midpoint - Rotate, // All points rotating from the midpoint -}; - -// This is nn::hid::GestureDirection -enum class GestureDirection : u32 { - None, - Left, - Up, - Right, - Down, -}; - -// This is nn::hid::GestureAttribute -struct GestureAttribute { - union { - u32 raw{}; - - BitField<4, 1, u32> is_new_touch; - BitField<8, 1, u32> is_double_tap; - }; -}; -static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); - -// This is nn::hid::GestureState -struct GestureState { - s64 sampling_number{}; - s64 detection_count{}; - GestureType type{GestureType::Idle}; - GestureDirection direction{GestureDirection::None}; - Common::Point<s32> pos{}; - Common::Point<s32> delta{}; - f32 vel_x{}; - f32 vel_y{}; - GestureAttribute attributes{}; - f32 scale{}; - f32 rotation_angle{}; - s32 point_count{}; - std::array<Common::Point<s32>, 4> points{}; -}; -static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); - -struct GestureProperties { - std::array<Common::Point<s32>, MAX_POINTS> points{}; - std::size_t active_points{}; - Common::Point<s32> mid_point{}; - s64 detection_count{}; - u64 delta_time{}; - f32 average_distance{}; - f32 angle{}; -}; - -// This is nn::hid::TouchScreenState -struct TouchScreenState { - s64 sampling_number{}; - s32 entry_count{}; - INSERT_PADDING_BYTES(4); // Reserved - std::array<Core::HID::TouchState, MAX_FINGERS> states{}; -}; -static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/unique_pad.cpp b/src/core/hle/service/hid/controllers/unique_pad.cpp deleted file mode 100644 index 8230501a5..000000000 --- a/src/core/hle/service/hid/controllers/unique_pad.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core_timing.h" -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/controllers/unique_pad.h" - -namespace Service::HID { - -UniquePad::UniquePad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} - -UniquePad::~UniquePad() = default; - -void UniquePad::OnInit() {} - -void UniquePad::OnRelease() {} - -void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!smart_update) { - return; - } - - const u64 aruid = applet_resource->GetActiveAruid(); - auto* data = applet_resource->GetAruidData(aruid); - - if (data == nullptr) { - return; - } - - auto& header = data->shared_memory_format->capture_button.header; - header.timestamp = core_timing.GetGlobalTimeNs().count(); - header.total_entry_count = 17; - header.entry_count = 0; - header.last_entry_index = 0; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/unique_pad.h b/src/core/hle/service/hid/controllers/unique_pad.h deleted file mode 100644 index 966368264..000000000 --- a/src/core/hle/service/hid/controllers/unique_pad.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/hid/controllers/controller_base.h" - -namespace Service::HID { - -class UniquePad final : public ControllerBase { -public: - explicit UniquePad(Core::HID::HIDCore& hid_core_); - ~UniquePad() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - bool smart_update{}; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h deleted file mode 100644 index 6dc976fe1..000000000 --- a/src/core/hle/service/hid/errors.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/result.h" - -namespace Service::HID { - -constexpr Result PalmaResultSuccess{ErrorModule::HID, 0}; -constexpr Result NpadInvalidHandle{ErrorModule::HID, 100}; -constexpr Result NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; -constexpr Result VibrationInvalidStyleIndex{ErrorModule::HID, 122}; -constexpr Result VibrationInvalidNpadId{ErrorModule::HID, 123}; -constexpr Result VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; -constexpr Result InvalidSixAxisFusionRange{ErrorModule::HID, 423}; -constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601}; -constexpr Result NpadIsSameType{ErrorModule::HID, 602}; -constexpr Result InvalidNpadId{ErrorModule::HID, 709}; -constexpr Result NpadNotConnected{ErrorModule::HID, 710}; -constexpr Result InvalidArraySize{ErrorModule::HID, 715}; - -constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041}; -constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042}; -constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043}; -constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044}; -constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046}; -constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047}; - -constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; - -} // namespace Service::HID - -namespace Service::IRS { - -constexpr Result InvalidProcessorState{ErrorModule::Irsensor, 78}; -constexpr Result InvalidIrCameraHandle{ErrorModule::Irsensor, 204}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index afbcb019f..5b28be577 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -5,35 +5,35 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_debug_server.h" -#include "core/hle/service/hid/hid_firmware_settings.h" #include "core/hle/service/hid/hid_server.h" #include "core/hle/service/hid/hid_system_server.h" #include "core/hle/service/hid/hidbus.h" #include "core/hle/service/hid/irs.h" -#include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/hid/xcd.h" #include "core/hle/service/server_manager.h" +#include "hid_core/resource_manager.h" +#include "hid_core/resources/hid_firmware_settings.h" namespace Service::HID { void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); + std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); std::shared_ptr<HidFirmwareSettings> firmware_settings = - std::make_shared<HidFirmwareSettings>(); + std::make_shared<HidFirmwareSettings>(system); - // TODO: Remove this hack until this service is emulated properly. - const auto process_list = system.Kernel().GetProcessList(); - if (!process_list.empty()) { - resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); - } + // TODO: Remove this hack when am is emulated properly. + resource_manager->Initialize(); + resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), + true); + resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true); server_manager->RegisterNamedService( - "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); + "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); server_manager->RegisterNamedService( - "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); + "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); server_manager->RegisterNamedService( - "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); + "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager, firmware_settings)); server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp index 6294f3dfb..f2a767d37 100644 --- a/src/core/hle/service/hid/hid_debug_server.cpp +++ b/src/core/hle/service/hid/hid_debug_server.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "core/hle/service/hid/hid_debug_server.h" -#include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" +#include "hid_core/resource_manager.h" namespace Service::HID { diff --git a/src/core/hle/service/hid/hid_firmware_settings.cpp b/src/core/hle/service/hid/hid_firmware_settings.cpp deleted file mode 100644 index 59bd6825c..000000000 --- a/src/core/hle/service/hid/hid_firmware_settings.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/hle/service/hid/hid_firmware_settings.h" - -namespace Service::HID { - -HidFirmwareSettings::HidFirmwareSettings() { - LoadSettings(true); -} - -void HidFirmwareSettings::Reload() { - LoadSettings(true); -} - -void HidFirmwareSettings::LoadSettings(bool reload_config) { - if (is_initalized && !reload_config) { - return; - } - - // TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values - - is_debug_pad_enabled = true; - is_device_managed = true; - is_touch_i2c_managed = is_device_managed; - is_future_devices_emulated = false; - is_mcu_hardware_error_emulated = false; - is_rail_enabled = true; - is_firmware_update_failure_emulated = false; - is_firmware_update_failure = {}; - is_ble_disabled = false; - is_dscale_disabled = false; - is_handheld_forced = true; - features_per_id_disabled = {}; - is_touch_firmware_auto_update_disabled = false; - is_initalized = true; -} - -bool HidFirmwareSettings::IsDebugPadEnabled() { - LoadSettings(false); - return is_debug_pad_enabled; -} - -bool HidFirmwareSettings::IsDeviceManaged() { - LoadSettings(false); - return is_device_managed; -} - -bool HidFirmwareSettings::IsEmulateFutureDevice() { - LoadSettings(false); - return is_future_devices_emulated; -} - -bool HidFirmwareSettings::IsTouchI2cManaged() { - LoadSettings(false); - return is_touch_i2c_managed; -} - -bool HidFirmwareSettings::IsHandheldForced() { - LoadSettings(false); - return is_handheld_forced; -} - -bool HidFirmwareSettings::IsRailEnabled() { - LoadSettings(false); - return is_rail_enabled; -} - -bool HidFirmwareSettings::IsHardwareErrorEmulated() { - LoadSettings(false); - return is_mcu_hardware_error_emulated; -} - -bool HidFirmwareSettings::IsBleDisabled() { - LoadSettings(false); - return is_ble_disabled; -} - -bool HidFirmwareSettings::IsDscaleDisabled() { - LoadSettings(false); - return is_dscale_disabled; -} - -bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() { - LoadSettings(false); - return is_touch_firmware_auto_update_disabled; -} - -HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() { - LoadSettings(false); - return is_firmware_update_failure; -} - -HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() { - LoadSettings(false); - return features_per_id_disabled; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hid_firmware_settings.h b/src/core/hle/service/hid/hid_firmware_settings.h deleted file mode 100644 index 6c10c440b..000000000 --- a/src/core/hle/service/hid/hid_firmware_settings.h +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" - -namespace Service::HID { - -/// Loads firmware config from nn::settings::fwdbg -class HidFirmwareSettings { -public: - using FirmwareSetting = std::array<u8, 4>; - using FeaturesPerId = std::array<bool, 0xA8>; - - HidFirmwareSettings(); - - void Reload(); - void LoadSettings(bool reload_config); - - bool IsDebugPadEnabled(); - bool IsDeviceManaged(); - bool IsEmulateFutureDevice(); - bool IsTouchI2cManaged(); - bool IsHandheldForced(); - bool IsRailEnabled(); - bool IsHardwareErrorEmulated(); - bool IsBleDisabled(); - bool IsDscaleDisabled(); - bool IsTouchAutoUpdateDisabled(); - - FirmwareSetting GetFirmwareUpdateFailure(); - FeaturesPerId FeaturesDisabledPerId(); - -private: - bool is_initalized{}; - - // Debug settings - bool is_debug_pad_enabled{}; - bool is_device_managed{}; - bool is_touch_i2c_managed{}; - bool is_future_devices_emulated{}; - bool is_mcu_hardware_error_emulated{}; - bool is_rail_enabled{}; - bool is_firmware_update_failure_emulated{}; - bool is_ble_disabled{}; - bool is_dscale_disabled{}; - bool is_handheld_forced{}; - bool is_touch_firmware_auto_update_disabled{}; - FirmwareSetting is_firmware_update_failure{}; - FeaturesPerId features_per_id_disabled{}; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 3174672af..09c47b5e3 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -5,30 +5,33 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/settings.h" -#include "core/hid/hid_core.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/service/hid/errors.h" -#include "core/hle/service/hid/hid_firmware_settings.h" #include "core/hle/service/hid/hid_server.h" -#include "core/hle/service/hid/hid_util.h" -#include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" - -#include "core/hle/service/hid/controllers/console_six_axis.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/controllers/debug_pad.h" -#include "core/hle/service/hid/controllers/gesture.h" -#include "core/hle/service/hid/controllers/keyboard.h" -#include "core/hle/service/hid/controllers/mouse.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/controllers/palma.h" -#include "core/hle/service/hid/controllers/seven_six_axis.h" -#include "core/hle/service/hid/controllers/six_axis.h" -#include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/types/npad_types.h" +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resource_manager.h" +#include "hid_core/resources/hid_firmware_settings.h" + +#include "hid_core/resources/controller_base.h" +#include "hid_core/resources/debug_pad/debug_pad.h" +#include "hid_core/resources/keyboard/keyboard.h" +#include "hid_core/resources/mouse/mouse.h" +#include "hid_core/resources/npad/npad.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/palma/palma.h" +#include "hid_core/resources/six_axis/console_six_axis.h" +#include "hid_core/resources/six_axis/seven_six_axis.h" +#include "hid_core/resources/six_axis/six_axis.h" +#include "hid_core/resources/touch_screen/gesture.h" +#include "hid_core/resources/touch_screen/touch_screen.h" +#include "hid_core/resources/vibration/gc_vibration_device.h" +#include "hid_core/resources/vibration/n64_vibration_device.h" +#include "hid_core/resources/vibration/vibration_device.h" namespace Service::HID { @@ -39,7 +42,7 @@ public: : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) { // clang-format off static const FunctionInfo functions[] = { - {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"}, + {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, }; // clang-format on @@ -47,22 +50,49 @@ public: } private: - void InitializeVibrationDevice(HLERequestContext& ctx) { + void ActivateVibrationDevice(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; - if (resource_manager != nullptr && resource_manager->GetNpad()) { - resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); - } - LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", vibration_device_handle.npad_type, vibration_device_handle.npad_id, vibration_device_handle.device_index); + const auto result = ActivateVibrationDeviceImpl(vibration_device_handle); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } + Result ActivateVibrationDeviceImpl(const Core::HID::VibrationDeviceHandle& handle) { + std::scoped_lock lock{mutex}; + + const Result is_valid = IsVibrationHandleValid(handle); + if (is_valid.IsError()) { + return is_valid; + } + + for (std::size_t i = 0; i < list_size; i++) { + if (handle.device_index == vibration_device_list[i].device_index && + handle.npad_id == vibration_device_list[i].npad_id && + handle.npad_type == vibration_device_list[i].npad_type) { + return ResultSuccess; + } + } + if (list_size == vibration_device_list.size()) { + return ResultVibrationDeviceIndexOutOfRange; + } + const Result result = resource_manager->GetVibrationDevice(handle)->Activate(); + if (result.IsError()) { + return result; + } + vibration_device_list[list_size++] = handle; + return ResultSuccess; + } + + mutable std::mutex mutex; + std::size_t list_size{}; + std::array<Core::HID::VibrationDeviceHandle, 0x100> vibration_device_list{}; std::shared_ptr<ResourceManager> resource_manager; }; @@ -154,7 +184,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, - {212, nullptr, "SendVibrationValueInBool"}, + {212, &IHidServer::SendVibrationValueInBool, "SendVibrationValueInBool"}, {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, @@ -785,8 +815,8 @@ void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ct bool is_firmware_available{}; auto controller = GetResourceManager()->GetNpad(); - controller->IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, - is_firmware_available); + controller->IsFirmwareUpdateAvailableForSixAxisSensor( + parameters.applet_resource_user_id, parameters.sixaxis_handle, is_firmware_available); LOG_WARNING( Service_HID, @@ -924,8 +954,8 @@ void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) const auto parameters{rp.PopRaw<Parameters>()}; auto controller = GetResourceManager()->GetNpad(); - const auto result = - controller->ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); + const auto result = controller->ResetIsSixAxisSensorDeviceNewlyAssigned( + parameters.applet_resource_user_id, parameters.sixaxis_handle); LOG_WARNING( Service_HID, @@ -970,7 +1000,7 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) { void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadStyleSet supported_styleset; + Core::HID::NpadStyleSet supported_style_set; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -978,13 +1008,25 @@ void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager()->GetNpad()->SetSupportedStyleSet({parameters.supported_styleset}); + LOG_DEBUG(Service_HID, "called, supported_style_set={}, applet_resource_user_id={}", + parameters.supported_style_set, parameters.applet_resource_user_id); + + const auto npad = GetResourceManager()->GetNpad(); + const Result result = npad->SetSupportedNpadStyleSet(parameters.applet_resource_user_id, + parameters.supported_style_set); - LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", - parameters.supported_styleset, parameters.applet_resource_user_id); + if (result.IsSuccess()) { + Core::HID::NpadStyleTag style_tag{parameters.supported_style_set}; + const auto revision = npad->GetRevision(parameters.applet_resource_user_id); + + if (style_tag.palma != 0 && revision < NpadRevision::Revision3) { + // GetResourceManager()->GetPalma()->EnableBoostMode(parameters.applet_resource_user_id, + // true); + } + } IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { @@ -993,19 +1035,31 @@ void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + Core::HID::NpadStyleSet supported_style_set{}; + const auto npad = GetResourceManager()->GetNpad(); + const auto result = + npad->GetSupportedNpadStyleSet(applet_resource_user_id, supported_style_set); + IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw); + rb.Push(result); + rb.PushEnum(supported_style_set); } void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - - const auto result = GetResourceManager()->GetNpad()->SetSupportedNpadIdTypes(ctx.ReadBuffer()); + const auto buffer = ctx.ReadBuffer(); + const std::size_t elements = ctx.GetReadBufferNumElements<Core::HID::NpadIdType>(); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + std::vector<Core::HID::NpadIdType> supported_npad_list(elements); + memcpy(supported_npad_list.data(), buffer.data(), buffer.size()); + + const auto npad = GetResourceManager()->GetNpad(); + const Result result = + npad->SetSupportedNpadIdType(applet_resource_user_id, supported_npad_list); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } @@ -1018,7 +1072,7 @@ void IHidServer::ActivateNpad(HLERequestContext& ctx) { auto npad = GetResourceManager()->GetNpad(); - // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); + npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); const Result result = npad->Activate(applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -1052,13 +1106,13 @@ void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); - // Games expect this event to be signaled after calling this function - GetResourceManager()->GetNpad()->SignalStyleSetChangedEvent(parameters.npad_id); + Kernel::KReadableEvent* style_set_update_event; + const auto result = GetResourceManager()->GetNpad()->AcquireNpadStyleSetUpdateEventHandle( + parameters.applet_resource_user_id, &style_set_update_event, parameters.npad_id); IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects( - GetResourceManager()->GetNpad()->GetStyleSetChangedEvent(parameters.npad_id)); + rb.Push(result); + rb.PushCopyObjects(style_set_update_event); } void IHidServer::DisconnectNpad(HLERequestContext& ctx) { @@ -1073,7 +1127,7 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; auto controller = GetResourceManager()->GetNpad(); - controller->DisconnectNpad(parameters.npad_id); + controller->DisconnectNpad(parameters.applet_resource_user_id, parameters.npad_id); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1113,7 +1167,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { auto npad = GetResourceManager()->GetNpad(); - // TODO: npad->SetRevision(applet_resource_user_id, revision); + npad->SetRevision(parameters.applet_resource_user_id, parameters.revision); const auto result = npad->Activate(parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -1125,13 +1179,19 @@ void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { const auto applet_resource_user_id{rp.Pop<u64>()}; const auto hold_type{rp.PopEnum<NpadJoyHoldType>()}; - GetResourceManager()->GetNpad()->SetHoldType(hold_type); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", applet_resource_user_id, hold_type); + if (hold_type != NpadJoyHoldType::Horizontal && hold_type != NpadJoyHoldType::Vertical) { + // This should crash console + ASSERT_MSG(false, "Invalid npad joy hold type"); + } + + const auto npad = GetResourceManager()->GetNpad(); + const auto result = npad->SetNpadJoyHoldType(applet_resource_user_id, hold_type); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { @@ -1140,9 +1200,13 @@ void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + NpadJoyHoldType hold_type{}; + const auto npad = GetResourceManager()->GetNpad(); + const auto result = npad->GetNpadJoyHoldType(applet_resource_user_id, hold_type); + IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager()->GetNpad()->GetHoldType()); + rb.Push(result); + rb.PushEnum(hold_type); } void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { @@ -1158,8 +1222,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); - controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left, - NpadJoyAssignmentMode::Single); + controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, + NpadJoyDeviceType::Left, NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1182,8 +1246,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); - controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - NpadJoyAssignmentMode::Single); + controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, + parameters.npad_joy_device_type, NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -1206,7 +1270,8 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); - controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual); + controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, {}, + NpadJoyAssignmentMode::Dual); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); // Spams a lot when controller applet is open @@ -1222,7 +1287,8 @@ void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) { const auto applet_resource_user_id{rp.Pop<u64>()}; auto controller = GetResourceManager()->GetNpad(); - const auto result = controller->MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); + const auto result = + controller->MergeSingleJoyAsDualJoy(applet_resource_user_id, npad_id_1, npad_id_2); LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", npad_id_1, npad_id_2, applet_resource_user_id); @@ -1235,10 +1301,10 @@ void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager()->GetNpad()->StartLRAssignmentMode(); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + GetResourceManager()->GetNpad()->StartLrAssignmentMode(applet_resource_user_id); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -1247,10 +1313,10 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager()->GetNpad()->StopLRAssignmentMode(); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + GetResourceManager()->GetNpad()->StopLrAssignmentMode(applet_resource_user_id); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -1260,13 +1326,23 @@ void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { const auto applet_resource_user_id{rp.Pop<u64>()}; const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()}; - GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", applet_resource_user_id, activation_mode); + if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { + // Console should crash here + ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + return; + } + + const auto npad = GetResourceManager()->GetNpad(); + const auto result = + npad->SetNpadHandheldActivationMode(applet_resource_user_id, activation_mode); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { @@ -1275,9 +1351,14 @@ void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + NpadHandheldActivationMode activation_mode{}; + const auto npad = GetResourceManager()->GetNpad(); + const auto result = + npad->GetNpadHandheldActivationMode(applet_resource_user_id, activation_mode); + IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadHandheldActivationMode()); + rb.Push(result); + rb.PushEnum(activation_mode); } void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { @@ -1286,12 +1367,12 @@ void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - auto controller = GetResourceManager()->GetNpad(); - const auto result = controller->SwapNpadAssignment(npad_id_1, npad_id_2); - LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", npad_id_1, npad_id_2, applet_resource_user_id); + const auto npad = GetResourceManager()->GetNpad(); + const auto result = npad->SwapNpadAssignment(applet_resource_user_id, npad_id_1, npad_id_2); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } @@ -1307,13 +1388,19 @@ void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& const auto parameters{rp.PopRaw<Parameters>()}; - bool is_enabled = false; - auto controller = GetResourceManager()->GetNpad(); - const auto result = - controller->IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); + LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, + parameters.applet_resource_user_id); - LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", - parameters.npad_id, parameters.applet_resource_user_id); + if (!IsNpadIdValid(parameters.npad_id)) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultInvalidNpadId); + return; + } + + bool is_enabled{}; + const auto npad = GetResourceManager()->GetNpad(); + const auto result = npad->IsUnintendedHomeButtonInputProtectionEnabled( + is_enabled, parameters.applet_resource_user_id, parameters.npad_id); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(result); @@ -1332,14 +1419,19 @@ void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ct const auto parameters{rp.PopRaw<Parameters>()}; - auto controller = GetResourceManager()->GetNpad(); - const auto result = controller->SetUnintendedHomeButtonInputProtectionEnabled( - parameters.is_enabled, parameters.npad_id); - - LOG_DEBUG(Service_HID, - "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}", + LOG_DEBUG(Service_HID, "called, is_enabled={}, npad_id={}, applet_resource_user_id={}", parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); + if (!IsNpadIdValid(parameters.npad_id)) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultInvalidNpadId); + return; + } + + const auto npad = GetResourceManager()->GetNpad(); + const auto result = npad->EnableUnintendedHomeButtonInputProtection( + parameters.applet_resource_user_id, parameters.npad_id, parameters.is_enabled); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); } @@ -1359,8 +1451,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); const auto is_reassigned = - controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - NpadJoyAssignmentMode::Single); + controller->SetNpadMode(parameters.applet_resource_user_id, new_npad_id, parameters.npad_id, + parameters.npad_joy_device_type, NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -1375,7 +1467,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - bool analog_stick_use_center_clamp; + bool use_center_clamp; INSERT_PADDING_BYTES_NOINIT(7); u64 applet_resource_user_id; }; @@ -1383,12 +1475,11 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager()->GetNpad()->SetAnalogStickUseCenterClamp( - parameters.analog_stick_use_center_clamp); + LOG_INFO(Service_HID, "called, use_center_clamp={}, applet_resource_user_id={}", + parameters.use_center_clamp, parameters.applet_resource_user_id); - LOG_WARNING(Service_HID, - "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}", - parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id); + GetResourceManager()->GetNpad()->SetNpadAnalogStickUseCenterClamp( + parameters.applet_resource_user_id, parameters.use_center_clamp); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1406,81 +1497,39 @@ void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - LOG_WARNING(Service_HID, - "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}", - parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button); + LOG_INFO(Service_HID, "called, npad_styleset={}, applet_resource_user_id={}, button={}", + parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button); + + const auto result = GetResourceManager()->GetNpad()->SetNpadCaptureButtonAssignment( + parameters.applet_resource_user_id, parameters.npad_styleset, parameters.button); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", - applet_resource_user_id); + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + const auto result = + GetResourceManager()->GetNpad()->ClearNpadCaptureButtonAssignment(applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; - const auto controller = GetResourceManager()->GetNpad(); - - Core::HID::VibrationDeviceInfo vibration_device_info; - bool check_device_index = false; - - switch (vibration_device_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Handheld: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::JoyconRight: - vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; - check_device_index = true; - break; - case Core::HID::NpadStyleIndex::GameCube: - vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; - break; - case Core::HID::NpadStyleIndex::N64: - vibration_device_info.type = Core::HID::VibrationDeviceType::N64; - break; - default: - vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; - break; - } - - vibration_device_info.position = Core::HID::VibrationDevicePosition::None; - if (check_device_index) { - switch (vibration_device_handle.device_index) { - case Core::HID::DeviceIndex::Left: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; - break; - case Core::HID::DeviceIndex::Right: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; - break; - case Core::HID::DeviceIndex::None: - default: - ASSERT_MSG(false, "DeviceIndex should never be None!"); - break; - } - } - - LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", - vibration_device_info.type, vibration_device_info.position); - const auto result = IsVibrationHandleValid(vibration_device_handle); - if (result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } + Core::HID::VibrationDeviceInfo vibration_device_info{}; + const auto result = GetResourceManager()->GetVibrationDeviceInfo(vibration_device_info, + vibration_device_handle); IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); + rb.Push(result); rb.PushRaw(vibration_device_info); } @@ -1496,15 +1545,16 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, - parameters.vibration_value); - LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.vibration_device_handle.npad_type, parameters.vibration_device_handle.npad_id, parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); + GetResourceManager()->SendVibrationValue(parameters.applet_resource_user_id, + parameters.vibration_device_handle, + parameters.vibration_value); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -1526,10 +1576,28 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) { parameters.vibration_device_handle.npad_id, parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); + bool has_active_aruid{}; + NpadVibrationDevice* device{nullptr}; + Core::HID::VibrationValue vibration_value{}; + Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, + has_active_aruid); + + if (result.IsSuccess() && has_active_aruid) { + result = IsVibrationHandleValid(parameters.vibration_device_handle); + } + if (result.IsSuccess() && has_active_aruid) { + device = GetResourceManager()->GetNSVibrationDevice(parameters.vibration_device_handle); + } + if (device != nullptr) { + result = device->GetActualVibrationValue(vibration_value); + } + if (result.IsError()) { + vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; + } + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - rb.PushRaw( - GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle)); + rb.PushRaw(vibration_value); } void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { @@ -1544,25 +1612,27 @@ void IHidServer::PermitVibration(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto can_vibrate{rp.Pop<bool>()}; - // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value - // by converting it to a bool - Settings::values.vibration_enabled.SetValue(can_vibrate); - LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume( + can_vibrate ? 1.0f : 0.0f); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called"); - // nnSDK checks if a float is greater than zero. We return the bool we stored earlier - const auto is_enabled = Settings::values.vibration_enabled.GetValue(); + f32 master_volume{}; + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume( + master_volume); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(is_enabled); + rb.Push(result); + rb.Push(master_volume > 0.0f); } void IHidServer::SendVibrationValues(HLERequestContext& ctx) { @@ -1580,12 +1650,22 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) { auto vibration_values = std::span( reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); - GetResourceManager()->GetNpad()->VibrateControllers(vibration_device_handles, vibration_values); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + Result result = ResultSuccess; + if (handle_count != vibration_count) { + result = ResultVibrationArraySizeMismatch; + } + + for (std::size_t i = 0; i < handle_count; i++) { + if (result.IsSuccess()) { + result = GetResourceManager()->SendVibrationValue( + applet_resource_user_id, vibration_device_handles[i], vibration_values[i]); + } + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { @@ -1600,43 +1680,6 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - /** - * Note: This uses yuzu-specific behavior such that the StopHard command produces - * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below, - * in order to differentiate between Stop and StopHard commands. - * This is done to reuse the controller vibration functions made for regular controllers. - */ - const auto vibration_value = [parameters] { - switch (parameters.gc_erm_command) { - case Core::HID::VibrationGcErmCommand::Stop: - return Core::HID::VibrationValue{ - .low_amplitude = 0.0f, - .low_frequency = 160.0f, - .high_amplitude = 0.0f, - .high_frequency = 320.0f, - }; - case Core::HID::VibrationGcErmCommand::Start: - return Core::HID::VibrationValue{ - .low_amplitude = 1.0f, - .low_frequency = 160.0f, - .high_amplitude = 1.0f, - .high_frequency = 320.0f, - }; - case Core::HID::VibrationGcErmCommand::StopHard: - return Core::HID::VibrationValue{ - .low_amplitude = 0.0f, - .low_frequency = 0.0f, - .high_amplitude = 0.0f, - .high_frequency = 0.0f, - }; - default: - return Core::HID::DEFAULT_VIBRATION_VALUE; - } - }(); - - GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, - vibration_value); - LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " "gc_erm_command={}", @@ -1645,8 +1688,23 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, parameters.gc_erm_command); + bool has_active_aruid{}; + NpadGcVibrationDevice* gc_device{nullptr}; + Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, + has_active_aruid); + + if (result.IsSuccess() && has_active_aruid) { + result = IsVibrationHandleValid(parameters.vibration_device_handle); + } + if (result.IsSuccess() && has_active_aruid) { + gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle); + } + if (gc_device != nullptr) { + result = gc_device->SendVibrationGcErmCommand(parameters.gc_erm_command); + } + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { @@ -1659,33 +1717,31 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - const auto last_vibration = - GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle); - - const auto gc_erm_command = [last_vibration] { - if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { - return Core::HID::VibrationGcErmCommand::Start; - } - - /** - * Note: This uses yuzu-specific behavior such that the StopHard command produces - * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function - * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. - * This is done to reuse the controller vibration functions made for regular controllers. - */ - if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { - return Core::HID::VibrationGcErmCommand::StopHard; - } - - return Core::HID::VibrationGcErmCommand::Stop; - }(); - LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.vibration_device_handle.npad_type, parameters.vibration_device_handle.npad_id, parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); + bool has_active_aruid{}; + NpadGcVibrationDevice* gc_device{nullptr}; + Core::HID::VibrationGcErmCommand gc_erm_command{}; + Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, + has_active_aruid); + + if (result.IsSuccess() && has_active_aruid) { + result = IsVibrationHandleValid(parameters.vibration_device_handle); + } + if (result.IsSuccess() && has_active_aruid) { + gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle); + } + if (gc_device != nullptr) { + result = gc_device->GetActualVibrationGcErmCommand(gc_erm_command); + } + if (result.IsError()) { + gc_erm_command = Core::HID::VibrationGcErmCommand::Stop; + } + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); rb.PushEnum(gc_erm_command); @@ -1695,21 +1751,24 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager()->GetNpad()->SetPermitVibrationSession(true); - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession( + applet_resource_user_id); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { - GetResourceManager()->GetNpad()->SetPermitVibrationSession(false); - LOG_DEBUG(Service_HID, "called"); + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession(); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { @@ -1729,10 +1788,61 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { parameters.vibration_device_handle.npad_id, parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); + bool is_mounted{}; + NpadVibrationBase* device{nullptr}; + Result result = IsVibrationHandleValid(parameters.vibration_device_handle); + + if (result.IsSuccess()) { + device = GetResourceManager()->GetVibrationDevice(parameters.vibration_device_handle); + } + + if (device != nullptr) { + is_mounted = device->IsVibrationMounted(); + } + IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( - parameters.vibration_device_handle)); + rb.Push(result); + rb.Push(is_mounted); +} + +void IHidServer::SendVibrationValueInBool(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + Core::HID::VibrationDeviceHandle vibration_device_handle; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + bool is_vibrating; + }; + static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " + "is_vibrating={}", + parameters.vibration_device_handle.npad_type, + parameters.vibration_device_handle.npad_id, + parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, + parameters.is_vibrating); + + bool has_active_aruid{}; + NpadN64VibrationDevice* n64_device{nullptr}; + Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, + has_active_aruid); + + if (result.IsSuccess() && has_active_aruid) { + result = IsVibrationHandleValid(parameters.vibration_device_handle); + } + if (result.IsSuccess() && has_active_aruid) { + n64_device = + GetResourceManager()->GetN64VibrationDevice(parameters.vibration_device_handle); + } + if (n64_device != nullptr) { + result = n64_device->SendValueInBool(parameters.is_vibrating); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); } void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { @@ -2315,10 +2425,10 @@ void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { const auto applet_resource_user_id{rp.Pop<u64>()}; const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()}; - GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, communication_mode={}", + applet_resource_user_id, communication_mode); - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}", - applet_resource_user_id, communication_mode); + // This function has been stubbed since 2.0.0+ IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2326,12 +2436,15 @@ void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + // This function has been stubbed since 2.0.0+ IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadCommunicationMode()); + rb.PushEnum(NpadCommunicationMode::Default); } void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h index cc7c4ebdd..3a2e0a230 100644 --- a/src/core/hle/service/hid/hid_server.h +++ b/src/core/hle/service/hid/hid_server.h @@ -97,6 +97,7 @@ private: void BeginPermitVibrationSession(HLERequestContext& ctx); void EndPermitVibrationSession(HLERequestContext& ctx); void IsVibrationDeviceMounted(HLERequestContext& ctx); + void SendVibrationValueInBool(HLERequestContext& ctx); void ActivateConsoleSixAxisSensor(HLERequestContext& ctx); void StartConsoleSixAxisSensor(HLERequestContext& ctx); void StopConsoleSixAxisSensor(HLERequestContext& ctx); diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index 5cc88c4a1..d1ec42edc 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp @@ -1,21 +1,24 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/controllers/palma.h" -#include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/types/npad_types.h" -#include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid_system_server.h" -#include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/set/settings_types.h" +#include "hid_core/hid_result.h" +#include "hid_core/resource_manager.h" +#include "hid_core/resources/hid_firmware_settings.h" +#include "hid_core/resources/npad/npad.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/palma/palma.h" +#include "hid_core/resources/touch_screen/touch_screen.h" namespace Service::HID { -IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource) +IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, + std::shared_ptr<HidFirmwareSettings> settings) : ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name}, - resource_manager{resource} { + resource_manager{resource}, firmware_settings{settings} { // clang-format off static const FunctionInfo functions[] = { {31, nullptr, "SendKeyboardLockKeyEvent"}, @@ -25,7 +28,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {131, nullptr, "ActivateSleepButton"}, {141, nullptr, "AcquireCaptureButtonEventHandle"}, {151, nullptr, "ActivateCaptureButton"}, - {161, nullptr, "GetPlatformConfig"}, + {161, &IHidSystemServer::GetPlatformConfig, "GetPlatformConfig"}, {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, {211, nullptr, "GetNpadsWithNfc"}, {212, nullptr, "AcquireNfcActivateEventHandle"}, @@ -47,7 +50,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, - {313, nullptr, "GetNpadCaptureButtonAssignment"}, + {313, &IHidSystemServer::GetNpadCaptureButtonAssignment, "GetNpadCaptureButtonAssignment"}, {314, nullptr, "GetAppletFooterUiType"}, {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, @@ -55,8 +58,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {318, &IHidSystemServer::HasBattery, "HasBattery"}, {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, - {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, - {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, + {322, &IHidSystemServer::SetNpadSystemExtStateEnabled, "SetNpadSystemExtStateEnabled"}, + {323, nullptr, "GetLastActiveUniquePad"}, {324, nullptr, "GetUniquePadButtonSet"}, {325, nullptr, "GetUniquePadColor"}, {326, nullptr, "GetUniquePadAppletDetailedUiType"}, @@ -68,21 +71,21 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, - {504, nullptr, "SetAruidValidForVibration"}, + {504, &IHidSystemServer::SetAruidValidForVibration, "SetAruidValidForVibration"}, {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, - {510, nullptr, "SetVibrationMasterVolume"}, - {511, nullptr, "GetVibrationMasterVolume"}, - {512, nullptr, "BeginPermitVibrationSession"}, - {513, nullptr, "EndPermitVibrationSession"}, + {510, &IHidSystemServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"}, + {511, &IHidSystemServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"}, + {512, &IHidSystemServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, + {513, &IHidSystemServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, {514, nullptr, "Unknown514"}, {520, nullptr, "EnableHandheldHids"}, {521, nullptr, "DisableHandheldHids"}, {522, nullptr, "SetJoyConRailEnabled"}, - {523, nullptr, "IsJoyConRailEnabled"}, + {523, &IHidSystemServer::IsJoyConRailEnabled, "IsJoyConRailEnabled"}, {524, nullptr, "IsHandheldHidsEnabled"}, - {525, nullptr, "IsJoyConAttachedOnAllRail"}, + {525, &IHidSystemServer::IsJoyConAttachedOnAllRail, "IsJoyConAttachedOnAllRail"}, {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, {541, nullptr, "GetPlayReportControllerUsages"}, {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, @@ -123,7 +126,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {831, nullptr, "SetNotificationLedPatternWithTimeout"}, {832, nullptr, "PrepareHidsForNotificationWake"}, {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"}, - {851, nullptr, "EnableUsbFullKeyController"}, + {851, &IHidSystemServer::EnableUsbFullKeyController, "EnableUsbFullKeyController"}, {852, nullptr, "IsUsbConnected"}, {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"}, {900, nullptr, "ActivateInputDetector"}, @@ -132,7 +135,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {1001, nullptr, "GetFirmwareVersion"}, {1002, nullptr, "GetAvailableFirmwareVersion"}, {1003, nullptr, "IsFirmwareUpdateAvailable"}, - {1004, nullptr, "CheckFirmwareUpdateRequired"}, + {1004, &IHidSystemServer::CheckFirmwareUpdateRequired, "CheckFirmwareUpdateRequired"}, {1005, nullptr, "StartFirmwareUpdate"}, {1006, nullptr, "AbortFirmwareUpdate"}, {1007, nullptr, "GetFirmwareUpdateState"}, @@ -145,10 +148,10 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, {1100, nullptr, "GetHidbusSystemServiceObject"}, - {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, - {1130, nullptr, "InitializeUsbFirmwareUpdate"}, - {1131, nullptr, "FinalizeUsbFirmwareUpdate"}, - {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, + {1120, &IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled, "SetFirmwareHotfixUpdateSkipEnabled"}, + {1130, &IHidSystemServer::InitializeUsbFirmwareUpdate, "InitializeUsbFirmwareUpdate"}, + {1131, &IHidSystemServer::FinalizeUsbFirmwareUpdate, "FinalizeUsbFirmwareUpdate"}, + {1132, &IHidSystemServer::CheckUsbFirmwareUpdateRequired, "CheckUsbFirmwareUpdateRequired"}, {1133, nullptr, "StartUsbFirmwareUpdate"}, {1134, nullptr, "GetUsbFirmwareUpdateState"}, {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, @@ -157,7 +160,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, {1154, nullptr, "IsFirmwareAvailableForNotification"}, - {1155, nullptr, "SetForceHandheldStyleVibration"}, + {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"}, {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, {1157, nullptr, "CancelConnectionTrigger"}, {1200, nullptr, "IsButtonConfigSupported"}, @@ -197,7 +200,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {1268, nullptr, "DeleteButtonConfigStorageFull"}, {1269, nullptr, "DeleteButtonConfigStorageLeft"}, {1270, nullptr, "DeleteButtonConfigStorageRight"}, - {1271, nullptr, "IsUsingCustomButtonConfig"}, + {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"}, {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, {1274, nullptr, "SetDefaultButtonConfig"}, @@ -239,41 +242,70 @@ IHidSystemServer::~IHidSystemServer() { service_context.CloseEvent(unique_pad_connection_event); }; +void IHidSystemServer::GetPlatformConfig(HLERequestContext& ctx) { + const auto platform_config = firmware_settings->GetPlatformConfig(); + + LOG_INFO(Service_HID, "called, platform_config={}", platform_config.raw); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(platform_config); +} + void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); + GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, true); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + GetResourceManager()->GetNpad()->AssigningSingleOnSlSrPress(applet_resource_user_id, false); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running + Core::HID::NpadIdType npad_id{}; + const Result result = GetResourceManager()->GetNpad()->GetLastActiveNpad(npad_id); + + LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(system.HIDCore().GetLastActiveController()); + rb.Push(result); + rb.PushEnum(npad_id); } void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "called"); + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); + GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicyFull(applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -298,28 +330,53 @@ void IHidSystemServer::GetNpadFullKeyGripColor(HLERequestContext& ctx) { void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_INFO(Service_HID, "(STUBBED) called"); + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - Core::HID::NpadStyleSet supported_styleset = - GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; + Core::HID::NpadStyleSet supported_styleset{}; + const auto& npad = GetResourceManager()->GetNpad(); + const Result result = + npad->GetMaskedSupportedNpadStyleSet(applet_resource_user_id, supported_styleset); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); + rb.Push(result); rb.PushEnum(supported_styleset); } void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_INFO(Service_HID, "(STUBBED) called"); + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - Core::HID::NpadStyleSet supported_styleset = - GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; + const auto& npad = GetResourceManager()->GetNpad(); + const auto result = + npad->SetSupportedNpadStyleSet(applet_resource_user_id, Core::HID::NpadStyleSet::All); - IPC::ResponseBuilder rb{ctx, 3}; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidSystemServer::GetNpadCaptureButtonAssignment(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + const auto capture_button_list_size{ctx.GetWriteBufferNumElements<Core::HID::NpadButton>()}; + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + std::vector<Core::HID::NpadButton> capture_button_list(capture_button_list_size); + const auto& npad = GetResourceManager()->GetNpad(); + const u64 list_size = + npad->GetNpadCaptureButtonAssignment(capture_button_list, applet_resource_user_id); + + if (list_size != 0) { + ctx.WriteBuffer(capture_button_list); + } + + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushEnum(supported_styleset); + rb.Push(list_size); } void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { @@ -414,13 +471,25 @@ void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) { rb.Push(static_cast<u32>(unique_pads.size())); } -void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) { +void IHidSystemServer::SetNpadSystemExtStateEnabled(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_BYTES_NOINIT(7); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); - LOG_WARNING(Service_HID, "(STUBBED) called"); + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + const auto result = GetResourceManager()->GetNpad()->SetNpadSystemExtStateEnabled( + parameters.applet_resource_user_id, parameters.is_enabled); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -477,7 +546,28 @@ void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) { parameters.is_enabled, parameters.applet_resource_user_id); GetResourceManager()->EnableInput(parameters.applet_resource_user_id, parameters.is_enabled); - // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); + GetResourceManager()->GetNpad()->EnableAppletToGetInput(parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::SetAruidValidForVibration(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + GetResourceManager()->SetAruidValidForVibration(parameters.applet_resource_user_id, + parameters.is_enabled); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -519,7 +609,7 @@ void IHidSystemServer::EnableAppletToGetPadInput(HLERequestContext& ctx) { parameters.is_enabled, parameters.applet_resource_user_id); GetResourceManager()->EnablePadInput(parameters.applet_resource_user_id, parameters.is_enabled); - // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); + GetResourceManager()->GetNpad()->EnableAppletToGetInput(parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -546,6 +636,77 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void IHidSystemServer::SetVibrationMasterVolume(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto master_volume{rp.Pop<f32>()}; + + LOG_INFO(Service_HID, "called, volume={}", master_volume); + + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume( + master_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidSystemServer::GetVibrationMasterVolume(HLERequestContext& ctx) { + f32 master_volume{}; + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume( + master_volume); + + LOG_INFO(Service_HID, "called, volume={}", master_volume); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.Push(master_volume); +} + +void IHidSystemServer::BeginPermitVibrationSession(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession( + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidSystemServer::EndPermitVibrationSession(HLERequestContext& ctx) { + LOG_INFO(Service_HID, "called"); + + const auto result = + GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IHidSystemServer::IsJoyConRailEnabled(HLERequestContext& ctx) { + const bool is_attached = true; + + LOG_WARNING(Service_HID, "(STUBBED) called, is_attached={}", is_attached); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_attached); +} + +void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) { + const bool is_attached = true; + + LOG_DEBUG(Service_HID, "(STUBBED) called, is_attached={}", is_attached); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_attached); +} + void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { LOG_INFO(Service_AM, "(STUBBED) called"); @@ -589,7 +750,7 @@ void IHidSystemServer::AcquireUniquePadConnectionEventHandle(HLERequestContext& } void IHidSystemServer::GetUniquePadIds(HLERequestContext& ctx) { - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_DEBUG(Service_HID, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -614,6 +775,16 @@ void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) { rb.Push(is_enabled); } +void IHidSystemServer::EnableUsbFullKeyController(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_enabled{rp.Pop<bool>()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void IHidSystemServer::IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx) { const bool button_pressed = false; @@ -632,6 +803,41 @@ void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void IHidSystemServer::CheckFirmwareUpdateRequired(HLERequestContext& ctx) { + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx) { + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::InitializeUsbFirmwareUpdate(HLERequestContext& ctx) { + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::FinalizeUsbFirmwareUpdate(HLERequestContext& ctx) { + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx) { + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called"); @@ -656,6 +862,29 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx rb.PushRaw(touchscreen_config); } +void IHidSystemServer::SetForceHandheldStyleVibration(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto is_forced{rp.Pop<bool>()}; + + LOG_INFO(Service_HID, "called, is_forced={}", is_forced); + + GetResourceManager()->SetForceHandheldStyleVibration(is_forced); + GetResourceManager()->GetNpad()->UpdateHandheldAbstractState(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) { + const bool is_enabled = false; + + LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_enabled); +} + std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { resource_manager->Initialize(); return resource_manager; diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h index 1e623dfc2..4ab4d3931 100644 --- a/src/core/hle/service/hid/hid_system_server.h +++ b/src/core/hle/service/hid/hid_system_server.h @@ -16,13 +16,16 @@ class KEvent; namespace Service::HID { class ResourceManager; +class HidFirmwareSettings; class IHidSystemServer final : public ServiceFramework<IHidSystemServer> { public: - explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource); + explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource, + std::shared_ptr<HidFirmwareSettings> settings); ~IHidSystemServer() override; private: + void GetPlatformConfig(HLERequestContext& ctx); void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx); void EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx); void DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx); @@ -31,19 +34,27 @@ private: void GetNpadFullKeyGripColor(HLERequestContext& ctx); void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx); void SetSupportedNpadStyleSetAll(HLERequestContext& ctx); + void GetNpadCaptureButtonAssignment(HLERequestContext& ctx); void GetAppletDetailedUiType(HLERequestContext& ctx); void GetNpadInterfaceType(HLERequestContext& ctx); void GetNpadLeftRightInterfaceType(HLERequestContext& ctx); void HasBattery(HLERequestContext& ctx); void HasLeftRightBattery(HLERequestContext& ctx); void GetUniquePadsFromNpad(HLERequestContext& ctx); - void GetIrSensorState(HLERequestContext& ctx); + void SetNpadSystemExtStateEnabled(HLERequestContext& ctx); void RegisterAppletResourceUserId(HLERequestContext& ctx); void UnregisterAppletResourceUserId(HLERequestContext& ctx); void EnableAppletToGetInput(HLERequestContext& ctx); + void SetAruidValidForVibration(HLERequestContext& ctx); void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); void EnableAppletToGetPadInput(HLERequestContext& ctx); void EnableAppletToGetTouchScreen(HLERequestContext& ctx); + void SetVibrationMasterVolume(HLERequestContext& ctx); + void GetVibrationMasterVolume(HLERequestContext& ctx); + void BeginPermitVibrationSession(HLERequestContext& ctx); + void EndPermitVibrationSession(HLERequestContext& ctx); + void IsJoyConRailEnabled(HLERequestContext& ctx); + void IsJoyConAttachedOnAllRail(HLERequestContext& ctx); void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); void GetRegisteredDevices(HLERequestContext& ctx); @@ -51,10 +62,18 @@ private: void GetUniquePadIds(HLERequestContext& ctx); void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx); void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx); + void EnableUsbFullKeyController(HLERequestContext& ctx); void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx); void InitializeFirmwareUpdate(HLERequestContext& ctx); + void CheckFirmwareUpdateRequired(HLERequestContext& ctx); + void SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx); + void InitializeUsbFirmwareUpdate(HLERequestContext& ctx); + void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); + void CheckUsbFirmwareUpdateRequired(HLERequestContext& ctx); void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); + void SetForceHandheldStyleVibration(HLERequestContext& ctx); + void IsUsingCustomButtonConfig(HLERequestContext& ctx); std::shared_ptr<ResourceManager> GetResourceManager(); @@ -64,6 +83,7 @@ private: Kernel::KEvent* unique_pad_connection_event; KernelHelpers::ServiceContext service_context; std::shared_ptr<ResourceManager> resource_manager; + std::shared_ptr<HidFirmwareSettings> firmware_settings; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid_util.h b/src/core/hle/service/hid/hid_util.h deleted file mode 100644 index b87cc10e3..000000000 --- a/src/core/hle/service/hid/hid_util.h +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/errors.h" - -namespace Service::HID { - -constexpr bool IsNpadIdValid(const Core::HID::NpadIdType npad_id) { - switch (npad_id) { - case Core::HID::NpadIdType::Player1: - case Core::HID::NpadIdType::Player2: - case Core::HID::NpadIdType::Player3: - case Core::HID::NpadIdType::Player4: - case Core::HID::NpadIdType::Player5: - case Core::HID::NpadIdType::Player6: - case Core::HID::NpadIdType::Player7: - case Core::HID::NpadIdType::Player8: - case Core::HID::NpadIdType::Other: - case Core::HID::NpadIdType::Handheld: - return true; - default: - return false; - } -} - -constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& handle) { - const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id)); - const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; - - if (!npad_id) { - return InvalidNpadId; - } - if (!device_index) { - return NpadDeviceIndexOutOfRange; - } - - return ResultSuccess; -} - -constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { - switch (handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Handheld: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::JoyconRight: - case Core::HID::NpadStyleIndex::GameCube: - case Core::HID::NpadStyleIndex::N64: - case Core::HID::NpadStyleIndex::SystemExt: - case Core::HID::NpadStyleIndex::System: - // These support vibration - break; - default: - return VibrationInvalidStyleIndex; - } - - if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) { - return VibrationInvalidNpadId; - } - - if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) { - return VibrationDeviceIndexOutOfRange; - } - - return ResultSuccess; -} - -/// Converts a Core::HID::NpadIdType to an array index. -constexpr size_t NpadIdTypeToIndex(Core::HID::NpadIdType npad_id_type) { - switch (npad_id_type) { - case Core::HID::NpadIdType::Player1: - return 0; - case Core::HID::NpadIdType::Player2: - return 1; - case Core::HID::NpadIdType::Player3: - return 2; - case Core::HID::NpadIdType::Player4: - return 3; - case Core::HID::NpadIdType::Player5: - return 4; - case Core::HID::NpadIdType::Player6: - return 5; - case Core::HID::NpadIdType::Player7: - return 6; - case Core::HID::NpadIdType::Player8: - return 7; - case Core::HID::NpadIdType::Handheld: - return 8; - case Core::HID::NpadIdType::Other: - return 9; - default: - return 8; - } -} - -/// Converts an array index to a Core::HID::NpadIdType -constexpr Core::HID::NpadIdType IndexToNpadIdType(size_t index) { - switch (index) { - case 0: - return Core::HID::NpadIdType::Player1; - case 1: - return Core::HID::NpadIdType::Player2; - case 2: - return Core::HID::NpadIdType::Player3; - case 3: - return Core::HID::NpadIdType::Player4; - case 4: - return Core::HID::NpadIdType::Player5; - case 5: - return Core::HID::NpadIdType::Player6; - case 6: - return Core::HID::NpadIdType::Player7; - case 7: - return Core::HID::NpadIdType::Player8; - case 8: - return Core::HID::NpadIdType::Handheld; - case 9: - return Core::HID::NpadIdType::Other; - default: - return Core::HID::NpadIdType::Invalid; - } -} - -constexpr Core::HID::NpadStyleSet GetStylesetByIndex(std::size_t index) { - switch (index) { - case 0: - return Core::HID::NpadStyleSet::Fullkey; - case 1: - return Core::HID::NpadStyleSet::Handheld; - case 2: - return Core::HID::NpadStyleSet::JoyDual; - case 3: - return Core::HID::NpadStyleSet::JoyLeft; - case 4: - return Core::HID::NpadStyleSet::JoyRight; - case 5: - return Core::HID::NpadStyleSet::Palma; - default: - return Core::HID::NpadStyleSet::None; - } -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index ffa7e144d..c903ee8b8 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -5,18 +5,18 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/service/hid/hidbus.h" -#include "core/hle/service/hid/hidbus/ringcon.h" -#include "core/hle/service/hid/hidbus/starlink.h" -#include "core/hle/service/hid/hidbus/stubbed.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/service.h" #include "core/memory.h" +#include "hid_core/hid_types.h" +#include "hid_core/hidbus/ringcon.h" +#include "hid_core/hidbus/starlink.h" +#include "hid_core/hidbus/stubbed.h" namespace Service::HID { // (15ms, 66Hz) @@ -67,7 +67,7 @@ HidBus::~HidBus() { void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { if (is_hidbus_enabled) { for (std::size_t i = 0; i < devices.size(); ++i) { - if (!devices[i].is_device_initializated) { + if (!devices[i].is_device_initialized) { continue; } auto& device = devices[i].device; @@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { MakeDevice<RingController>(bus_handle_); - devices[device_index.value()].is_device_initializated = true; + devices[device_index.value()].is_device_initialized = true; devices[device_index.value()].device->ActivateDevice(); cur_entry.is_in_focus = true; cur_entry.is_connected = true; @@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { cur_entry.is_polling_mode = false; } else { MakeDevice<HidbusStubbed>(bus_handle_); - devices[device_index.value()].is_device_initializated = true; + devices[device_index.value()].is_device_initialized = true; cur_entry.is_in_focus = true; cur_entry.is_connected = false; cur_entry.is_connected_result = ResultSuccess; @@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) { const auto entry_index = devices[device_index.value()].handle.internal_index; auto& cur_entry = hidbus_status.entries[entry_index]; auto& device = devices[device_index.value()].device; - devices[device_index.value()].is_device_initializated = false; + devices[device_index.value()].is_device_initialized = false; device->DeactivateDevice(); cur_entry.is_in_focus = true; diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h index 85a1df133..03d9f6863 100644 --- a/src/core/hle/service/hid/hidbus.h +++ b/src/core/hle/service/hid/hidbus.h @@ -5,9 +5,9 @@ #include <functional> -#include "core/hle/service/hid/hidbus/hidbus_base.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" +#include "hid_core/hidbus/hidbus_base.h" namespace Core::Timing { struct EventType; @@ -89,7 +89,7 @@ private: static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); struct HidbusDevice { - bool is_device_initializated{}; + bool is_device_initialized{}; BusHandle handle{}; std::unique_ptr<HidbusBase> device{nullptr}; }; diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp deleted file mode 100644 index 8c44f93e8..000000000 --- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hid/hid_core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/hid/hidbus/hidbus_base.h" -#include "core/hle/service/kernel_helpers.h" - -namespace Service::HID { - -HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_) - : system(system_), service_context(service_context_) { - send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent"); -} - -HidbusBase::~HidbusBase() { - service_context.CloseEvent(send_command_async_event); -}; - -void HidbusBase::ActivateDevice() { - if (is_activated) { - return; - } - is_activated = true; - OnInit(); -} - -void HidbusBase::DeactivateDevice() { - if (is_activated) { - OnRelease(); - } - is_activated = false; -} - -bool HidbusBase::IsDeviceActivated() const { - return is_activated; -} - -void HidbusBase::Enable(bool enable) { - device_enabled = enable; -} - -bool HidbusBase::IsEnabled() const { - return device_enabled; -} - -bool HidbusBase::IsPollingMode() const { - return polling_mode_enabled; -} - -JoyPollingMode HidbusBase::GetPollingMode() const { - return polling_mode; -} - -void HidbusBase::SetPollingMode(JoyPollingMode mode) { - polling_mode = mode; - polling_mode_enabled = true; -} - -void HidbusBase::DisablePollingMode() { - polling_mode_enabled = false; -} - -void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { - transfer_memory = t_mem; -} - -Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const { - return send_command_async_event->GetReadableEvent(); -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h deleted file mode 100644 index ec41684e1..000000000 --- a/src/core/hle/service/hid/hidbus/hidbus_base.h +++ /dev/null @@ -1,183 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <span> -#include "common/typed_address.h" -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KEvent; -class KReadableEvent; -} // namespace Kernel - -namespace Service::KernelHelpers { -class ServiceContext; -} - -namespace Service::HID { - -// This is nn::hidbus::JoyPollingMode -enum class JoyPollingMode : u32 { - SixAxisSensorDisable, - SixAxisSensorEnable, - ButtonOnly, -}; - -struct DataAccessorHeader { - Result result{ResultUnknown}; - INSERT_PADDING_WORDS(0x1); - std::array<u8, 0x18> unused{}; - u64 latest_entry{}; - u64 total_entries{}; -}; -static_assert(sizeof(DataAccessorHeader) == 0x30, "DataAccessorHeader is an invalid size"); - -struct JoyDisableSixAxisPollingData { - std::array<u8, 0x26> data; - u8 out_size; - INSERT_PADDING_BYTES(0x1); - u64 sampling_number; -}; -static_assert(sizeof(JoyDisableSixAxisPollingData) == 0x30, - "JoyDisableSixAxisPollingData is an invalid size"); - -struct JoyEnableSixAxisPollingData { - std::array<u8, 0x8> data; - u8 out_size; - INSERT_PADDING_BYTES(0x7); - u64 sampling_number; -}; -static_assert(sizeof(JoyEnableSixAxisPollingData) == 0x18, - "JoyEnableSixAxisPollingData is an invalid size"); - -struct JoyButtonOnlyPollingData { - std::array<u8, 0x2c> data; - u8 out_size; - INSERT_PADDING_BYTES(0x3); - u64 sampling_number; -}; -static_assert(sizeof(JoyButtonOnlyPollingData) == 0x38, - "JoyButtonOnlyPollingData is an invalid size"); - -struct JoyDisableSixAxisPollingEntry { - u64 sampling_number; - JoyDisableSixAxisPollingData polling_data; -}; -static_assert(sizeof(JoyDisableSixAxisPollingEntry) == 0x38, - "JoyDisableSixAxisPollingEntry is an invalid size"); - -struct JoyEnableSixAxisPollingEntry { - u64 sampling_number; - JoyEnableSixAxisPollingData polling_data; -}; -static_assert(sizeof(JoyEnableSixAxisPollingEntry) == 0x20, - "JoyEnableSixAxisPollingEntry is an invalid size"); - -struct JoyButtonOnlyPollingEntry { - u64 sampling_number; - JoyButtonOnlyPollingData polling_data; -}; -static_assert(sizeof(JoyButtonOnlyPollingEntry) == 0x40, - "JoyButtonOnlyPollingEntry is an invalid size"); - -struct JoyDisableSixAxisDataAccessor { - DataAccessorHeader header{}; - std::array<JoyDisableSixAxisPollingEntry, 0xb> entries{}; -}; -static_assert(sizeof(JoyDisableSixAxisDataAccessor) == 0x298, - "JoyDisableSixAxisDataAccessor is an invalid size"); - -struct JoyEnableSixAxisDataAccessor { - DataAccessorHeader header{}; - std::array<JoyEnableSixAxisPollingEntry, 0xb> entries{}; -}; -static_assert(sizeof(JoyEnableSixAxisDataAccessor) == 0x190, - "JoyEnableSixAxisDataAccessor is an invalid size"); - -struct ButtonOnlyPollingDataAccessor { - DataAccessorHeader header; - std::array<JoyButtonOnlyPollingEntry, 0xb> entries; -}; -static_assert(sizeof(ButtonOnlyPollingDataAccessor) == 0x2F0, - "ButtonOnlyPollingDataAccessor is an invalid size"); - -class HidbusBase { -public: - explicit HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_); - virtual ~HidbusBase(); - - void ActivateDevice(); - - void DeactivateDevice(); - - bool IsDeviceActivated() const; - - // Enables/disables the device - void Enable(bool enable); - - // returns true if device is enabled - bool IsEnabled() const; - - // returns true if polling mode is enabled - bool IsPollingMode() const; - - // returns polling mode - JoyPollingMode GetPollingMode() const; - - // Sets and enables JoyPollingMode - void SetPollingMode(JoyPollingMode mode); - - // Disables JoyPollingMode - void DisablePollingMode(); - - // Called on EnableJoyPollingReceiveMode - void SetTransferMemoryAddress(Common::ProcessAddress t_mem); - - Kernel::KReadableEvent& GetSendCommandAsycEvent() const; - - virtual void OnInit() {} - - virtual void OnRelease() {} - - // Updates device transfer memory - virtual void OnUpdate() {} - - // Returns the device ID of the joycon - virtual u8 GetDeviceId() const { - return {}; - } - - // Assigns a command from data - virtual bool SetCommand(std::span<const u8> data) { - return {}; - } - - // Returns a reply from a command - virtual std::vector<u8> GetReply() const { - return {}; - } - -protected: - bool is_activated{}; - bool device_enabled{}; - bool polling_mode_enabled{}; - JoyPollingMode polling_mode = {}; - // TODO(German77): All data accessors need to be replaced with a ring lifo object - JoyDisableSixAxisDataAccessor disable_sixaxis_data{}; - JoyEnableSixAxisDataAccessor enable_sixaxis_data{}; - ButtonOnlyPollingDataAccessor button_only_data{}; - - Common::ProcessAddress transfer_memory{}; - - Core::System& system; - Kernel::KEvent* send_command_async_event; - KernelHelpers::ServiceContext& service_context; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp deleted file mode 100644 index 378108012..000000000 --- a/src/core/hle/service/hid/hidbus/ringcon.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/kernel/k_readable_event.h" -#include "core/hle/service/hid/hidbus/ringcon.h" -#include "core/memory.h" - -namespace Service::HID { - -RingController::RingController(Core::System& system_, - KernelHelpers::ServiceContext& service_context_) - : HidbusBase(system_, service_context_) { - input = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); -} - -RingController::~RingController() = default; - -void RingController::OnInit() { - input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::Ring); - return; -} - -void RingController::OnRelease() { - input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, - Common::Input::PollingMode::Active); - return; -}; - -void RingController::OnUpdate() { - if (!is_activated) { - return; - } - - if (!device_enabled) { - return; - } - - if (!polling_mode_enabled || transfer_memory == 0) { - return; - } - - // TODO: Increment multitasking counters from motion and sensor data - - switch (polling_mode) { - case JoyPollingMode::SixAxisSensorEnable: { - enable_sixaxis_data.header.total_entries = 10; - enable_sixaxis_data.header.result = ResultSuccess; - const auto& last_entry = - enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry]; - - enable_sixaxis_data.header.latest_entry = - (enable_sixaxis_data.header.latest_entry + 1) % 10; - auto& curr_entry = enable_sixaxis_data.entries[enable_sixaxis_data.header.latest_entry]; - - curr_entry.sampling_number = last_entry.sampling_number + 1; - curr_entry.polling_data.sampling_number = curr_entry.sampling_number; - - const RingConData ringcon_value = GetSensorValue(); - curr_entry.polling_data.out_size = sizeof(ringcon_value); - std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value)); - - system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data, - sizeof(enable_sixaxis_data)); - break; - } - default: - LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode); - break; - } -} - -RingController::RingConData RingController::GetSensorValue() const { - RingConData ringcon_sensor_value{ - .status = DataValid::Valid, - .data = 0, - }; - - const f32 force_value = input->GetRingSensorForce().force * range; - ringcon_sensor_value.data = static_cast<s16>(force_value) + idle_value; - - return ringcon_sensor_value; -} - -u8 RingController::GetDeviceId() const { - return device_id; -} - -std::vector<u8> RingController::GetReply() const { - const RingConCommands current_command = command; - - switch (current_command) { - case RingConCommands::GetFirmwareVersion: - return GetFirmwareVersionReply(); - case RingConCommands::ReadId: - return GetReadIdReply(); - case RingConCommands::c20105: - return GetC020105Reply(); - case RingConCommands::ReadUnkCal: - return GetReadUnkCalReply(); - case RingConCommands::ReadFactoryCal: - return GetReadFactoryCalReply(); - case RingConCommands::ReadUserCal: - return GetReadUserCalReply(); - case RingConCommands::ReadRepCount: - return GetReadRepCountReply(); - case RingConCommands::ReadTotalPushCount: - return GetReadTotalPushCountReply(); - case RingConCommands::ResetRepCount: - return GetResetRepCountReply(); - case RingConCommands::SaveCalData: - return GetSaveDataReply(); - default: - return GetErrorReply(); - } -} - -bool RingController::SetCommand(std::span<const u8> data) { - if (data.size() < 4) { - LOG_ERROR(Service_HID, "Command size not supported {}", data.size()); - command = RingConCommands::Error; - return false; - } - - std::memcpy(&command, data.data(), sizeof(RingConCommands)); - - switch (command) { - case RingConCommands::GetFirmwareVersion: - case RingConCommands::ReadId: - case RingConCommands::c20105: - case RingConCommands::ReadUnkCal: - case RingConCommands::ReadFactoryCal: - case RingConCommands::ReadUserCal: - case RingConCommands::ReadRepCount: - case RingConCommands::ReadTotalPushCount: - ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes"); - send_command_async_event->Signal(); - return true; - case RingConCommands::ResetRepCount: - ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes"); - total_rep_count = 0; - send_command_async_event->Signal(); - return true; - case RingConCommands::SaveCalData: { - ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes"); - - SaveCalData save_info{}; - std::memcpy(&save_info, data.data(), sizeof(SaveCalData)); - user_calibration = save_info.calibration; - send_command_async_event->Signal(); - return true; - } - default: - LOG_ERROR(Service_HID, "Command not implemented {}", command); - command = RingConCommands::Error; - // Signal a reply to avoid softlocking the game - send_command_async_event->Signal(); - return false; - } -} - -std::vector<u8> RingController::GetFirmwareVersionReply() const { - const FirmwareVersionReply reply{ - .status = DataValid::Valid, - .firmware = version, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadIdReply() const { - // The values are hardcoded from a real joycon - const ReadIdReply reply{ - .status = DataValid::Valid, - .id_l_x0 = 8, - .id_l_x0_2 = 41, - .id_l_x4 = 22294, - .id_h_x0 = 19777, - .id_h_x0_2 = 13621, - .id_h_x4 = 8245, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetC020105Reply() const { - const Cmd020105Reply reply{ - .status = DataValid::Valid, - .data = 1, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadUnkCalReply() const { - const ReadUnkCalReply reply{ - .status = DataValid::Valid, - .data = 0, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadFactoryCalReply() const { - const ReadFactoryCalReply reply{ - .status = DataValid::Valid, - .calibration = factory_calibration, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadUserCalReply() const { - const ReadUserCalReply reply{ - .status = DataValid::Valid, - .calibration = user_calibration, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadRepCountReply() const { - const GetThreeByteReply reply{ - .status = DataValid::Valid, - .data = {total_rep_count, 0, 0}, - .crc = GetCrcValue({total_rep_count, 0, 0, 0}), - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetReadTotalPushCountReply() const { - const GetThreeByteReply reply{ - .status = DataValid::Valid, - .data = {total_push_count, 0, 0}, - .crc = GetCrcValue({total_push_count, 0, 0, 0}), - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetResetRepCountReply() const { - return GetReadRepCountReply(); -} - -std::vector<u8> RingController::GetSaveDataReply() const { - const StatusReply reply{ - .status = DataValid::Valid, - }; - - return GetDataVector(reply); -} - -std::vector<u8> RingController::GetErrorReply() const { - const ErrorReply reply{ - .status = DataValid::BadCRC, - }; - - return GetDataVector(reply); -} - -u8 RingController::GetCrcValue(const std::vector<u8>& data) const { - u8 crc = 0; - for (std::size_t index = 0; index < data.size(); index++) { - for (u8 i = 0x80; i > 0; i >>= 1) { - bool bit = (crc & 0x80) != 0; - if ((data[index] & i) != 0) { - bit = !bit; - } - crc <<= 1; - if (bit) { - crc ^= 0x8d; - } - } - } - return crc; -} - -template <typename T> -std::vector<u8> RingController::GetDataVector(const T& reply) const { - static_assert(std::is_trivially_copyable_v<T>); - std::vector<u8> data; - data.resize(sizeof(reply)); - std::memcpy(data.data(), &reply, sizeof(reply)); - return data; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h deleted file mode 100644 index f42f3ea41..000000000 --- a/src/core/hle/service/hid/hidbus/ringcon.h +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <span> - -#include "common/common_types.h" -#include "core/hle/service/hid/hidbus/hidbus_base.h" - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::HID { - -class RingController final : public HidbusBase { -public: - explicit RingController(Core::System& system_, KernelHelpers::ServiceContext& service_context_); - ~RingController() override; - - void OnInit() override; - - void OnRelease() override; - - // Updates ringcon transfer memory - void OnUpdate() override; - - // Returns the device ID of the joycon - u8 GetDeviceId() const override; - - // Assigns a command from data - bool SetCommand(std::span<const u8> data) override; - - // Returns a reply from a command - std::vector<u8> GetReply() const override; - -private: - // These values are obtained from a real ring controller - static constexpr s16 idle_value = 2280; - static constexpr s16 idle_deadzone = 120; - static constexpr s16 range = 2500; - - // Most missing command names are leftovers from other firmware versions - enum class RingConCommands : u32 { - GetFirmwareVersion = 0x00020000, - ReadId = 0x00020100, - JoyPolling = 0x00020101, - Unknown1 = 0x00020104, - c20105 = 0x00020105, - Unknown2 = 0x00020204, - Unknown3 = 0x00020304, - Unknown4 = 0x00020404, - ReadUnkCal = 0x00020504, - ReadFactoryCal = 0x00020A04, - Unknown5 = 0x00021104, - Unknown6 = 0x00021204, - Unknown7 = 0x00021304, - ReadUserCal = 0x00021A04, - ReadRepCount = 0x00023104, - ReadTotalPushCount = 0x00023204, - ResetRepCount = 0x04013104, - Unknown8 = 0x04011104, - Unknown9 = 0x04011204, - Unknown10 = 0x04011304, - SaveCalData = 0x10011A04, - Error = 0xFFFFFFFF, - }; - - enum class DataValid : u32 { - Valid, - BadCRC, - Cal, - }; - - struct FirmwareVersion { - u8 sub; - u8 main; - }; - static_assert(sizeof(FirmwareVersion) == 0x2, "FirmwareVersion is an invalid size"); - - struct FactoryCalibration { - s32_le os_max; - s32_le hk_max; - s32_le zero_min; - s32_le zero_max; - }; - static_assert(sizeof(FactoryCalibration) == 0x10, "FactoryCalibration is an invalid size"); - - struct CalibrationValue { - s16 value; - u16 crc; - }; - static_assert(sizeof(CalibrationValue) == 0x4, "CalibrationValue is an invalid size"); - - struct UserCalibration { - CalibrationValue os_max; - CalibrationValue hk_max; - CalibrationValue zero; - }; - static_assert(sizeof(UserCalibration) == 0xC, "UserCalibration is an invalid size"); - - struct SaveCalData { - RingConCommands command; - UserCalibration calibration; - INSERT_PADDING_BYTES_NOINIT(4); - }; - static_assert(sizeof(SaveCalData) == 0x14, "SaveCalData is an invalid size"); - static_assert(std::is_trivially_copyable_v<SaveCalData>, - "SaveCalData must be trivially copyable"); - - struct FirmwareVersionReply { - DataValid status; - FirmwareVersion firmware; - INSERT_PADDING_BYTES(0x2); - }; - static_assert(sizeof(FirmwareVersionReply) == 0x8, "FirmwareVersionReply is an invalid size"); - - struct Cmd020105Reply { - DataValid status; - u8 data; - INSERT_PADDING_BYTES(0x3); - }; - static_assert(sizeof(Cmd020105Reply) == 0x8, "Cmd020105Reply is an invalid size"); - - struct StatusReply { - DataValid status; - }; - static_assert(sizeof(StatusReply) == 0x4, "StatusReply is an invalid size"); - - struct GetThreeByteReply { - DataValid status; - std::array<u8, 3> data; - u8 crc; - }; - static_assert(sizeof(GetThreeByteReply) == 0x8, "GetThreeByteReply is an invalid size"); - - struct ReadUnkCalReply { - DataValid status; - u16 data; - INSERT_PADDING_BYTES(0x2); - }; - static_assert(sizeof(ReadUnkCalReply) == 0x8, "ReadUnkCalReply is an invalid size"); - - struct ReadFactoryCalReply { - DataValid status; - FactoryCalibration calibration; - }; - static_assert(sizeof(ReadFactoryCalReply) == 0x14, "ReadFactoryCalReply is an invalid size"); - - struct ReadUserCalReply { - DataValid status; - UserCalibration calibration; - INSERT_PADDING_BYTES(0x4); - }; - static_assert(sizeof(ReadUserCalReply) == 0x14, "ReadUserCalReply is an invalid size"); - - struct ReadIdReply { - DataValid status; - u16 id_l_x0; - u16 id_l_x0_2; - u16 id_l_x4; - u16 id_h_x0; - u16 id_h_x0_2; - u16 id_h_x4; - }; - static_assert(sizeof(ReadIdReply) == 0x10, "ReadIdReply is an invalid size"); - - struct ErrorReply { - DataValid status; - INSERT_PADDING_BYTES(0x3); - }; - static_assert(sizeof(ErrorReply) == 0x8, "ErrorReply is an invalid size"); - - struct RingConData { - DataValid status; - s16_le data; - INSERT_PADDING_BYTES(0x2); - }; - static_assert(sizeof(RingConData) == 0x8, "RingConData is an invalid size"); - - // Returns RingConData struct with pressure sensor values - RingConData GetSensorValue() const; - - // Returns 8 byte reply with firmware version - std::vector<u8> GetFirmwareVersionReply() const; - - // Returns 16 byte reply with ID values - std::vector<u8> GetReadIdReply() const; - - // (STUBBED) Returns 8 byte reply - std::vector<u8> GetC020105Reply() const; - - // (STUBBED) Returns 8 byte empty reply - std::vector<u8> GetReadUnkCalReply() const; - - // Returns 20 byte reply with factory calibration values - std::vector<u8> GetReadFactoryCalReply() const; - - // Returns 20 byte reply with user calibration values - std::vector<u8> GetReadUserCalReply() const; - - // Returns 8 byte reply - std::vector<u8> GetReadRepCountReply() const; - - // Returns 8 byte reply - std::vector<u8> GetReadTotalPushCountReply() const; - - // Returns 8 byte reply - std::vector<u8> GetResetRepCountReply() const; - - // Returns 4 byte save data reply - std::vector<u8> GetSaveDataReply() const; - - // Returns 8 byte error reply - std::vector<u8> GetErrorReply() const; - - // Returns 8 bit redundancy check from provided data - u8 GetCrcValue(const std::vector<u8>& data) const; - - // Converts structs to an u8 vector equivalent - template <typename T> - std::vector<u8> GetDataVector(const T& reply) const; - - RingConCommands command{RingConCommands::Error}; - - // These counters are used in multitasking mode while the switch is sleeping - // Total steps taken - u8 total_rep_count = 0; - // Total times the ring was pushed - u8 total_push_count = 0; - - const u8 device_id = 0x20; - const FirmwareVersion version = { - .sub = 0x0, - .main = 0x2c, - }; - const FactoryCalibration factory_calibration = { - .os_max = idle_value + range + idle_deadzone, - .hk_max = idle_value - range - idle_deadzone, - .zero_min = idle_value - idle_deadzone, - .zero_max = idle_value + idle_deadzone, - }; - UserCalibration user_calibration = { - .os_max = {.value = range, .crc = 228}, - .hk_max = {.value = -range, .crc = 239}, - .zero = {.value = idle_value, .crc = 225}, - }; - - Core::HID::EmulatedController* input; -}; -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp deleted file mode 100644 index 36573274e..000000000 --- a/src/core/hle/service/hid/hidbus/starlink.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/hidbus/starlink.h" - -namespace Service::HID { -constexpr u8 DEVICE_ID = 0x28; - -Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_) - : HidbusBase(system_, service_context_) {} -Starlink::~Starlink() = default; - -void Starlink::OnInit() { - return; -} - -void Starlink::OnRelease() { - return; -}; - -void Starlink::OnUpdate() { - if (!is_activated) { - return; - } - if (!device_enabled) { - return; - } - if (!polling_mode_enabled || transfer_memory == 0) { - return; - } - - LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode); -} - -u8 Starlink::GetDeviceId() const { - return DEVICE_ID; -} - -std::vector<u8> Starlink::GetReply() const { - return {}; -} - -bool Starlink::SetCommand(std::span<const u8> data) { - LOG_ERROR(Service_HID, "Command not implemented"); - return false; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h deleted file mode 100644 index a276aa88f..000000000 --- a/src/core/hle/service/hid/hidbus/starlink.h +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hle/service/hid/hidbus/hidbus_base.h" - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::HID { - -class Starlink final : public HidbusBase { -public: - explicit Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_); - ~Starlink() override; - - void OnInit() override; - - void OnRelease() override; - - // Updates ringcon transfer memory - void OnUpdate() override; - - // Returns the device ID of the joycon - u8 GetDeviceId() const override; - - // Assigns a command from data - bool SetCommand(std::span<const u8> data) override; - - // Returns a reply from a command - std::vector<u8> GetReply() const override; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp deleted file mode 100644 index 8160b7218..000000000 --- a/src/core/hle/service/hid/hidbus/stubbed.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/hidbus/stubbed.h" - -namespace Service::HID { -constexpr u8 DEVICE_ID = 0xFF; - -HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_) - : HidbusBase(system_, service_context_) {} -HidbusStubbed::~HidbusStubbed() = default; - -void HidbusStubbed::OnInit() { - return; -} - -void HidbusStubbed::OnRelease() { - return; -}; - -void HidbusStubbed::OnUpdate() { - if (!is_activated) { - return; - } - if (!device_enabled) { - return; - } - if (!polling_mode_enabled || transfer_memory == 0) { - return; - } - - LOG_ERROR(Service_HID, "Polling mode not supported {}", polling_mode); -} - -u8 HidbusStubbed::GetDeviceId() const { - return DEVICE_ID; -} - -std::vector<u8> HidbusStubbed::GetReply() const { - return {}; -} - -bool HidbusStubbed::SetCommand(std::span<const u8> data) { - LOG_ERROR(Service_HID, "Command not implemented"); - return false; -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h deleted file mode 100644 index 2e58d42fc..000000000 --- a/src/core/hle/service/hid/hidbus/stubbed.h +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hle/service/hid/hidbus/hidbus_base.h" - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::HID { - -class HidbusStubbed final : public HidbusBase { -public: - explicit HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_); - ~HidbusStubbed() override; - - void OnInit() override; - - void OnRelease() override; - - // Updates ringcon transfer memory - void OnUpdate() override; - - // Returns the device ID of the joycon - u8 GetDeviceId() const override; - - // Assigns a command from data - bool SetCommand(std::span<const u8> data) override; - - // Returns a reply from a command - std::vector<u8> GetReply() const override; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 008debfd1..18e544f2f 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -6,22 +6,22 @@ #include "core/core.h" #include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/service/hid/errors.h" -#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/hid/irs.h" -#include "core/hle/service/hid/irsensor/clustering_processor.h" -#include "core/hle/service/hid/irsensor/image_transfer_processor.h" -#include "core/hle/service/hid/irsensor/ir_led_processor.h" -#include "core/hle/service/hid/irsensor/moment_processor.h" -#include "core/hle/service/hid/irsensor/pointing_processor.h" -#include "core/hle/service/hid/irsensor/tera_plugin_processor.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/irsensor/clustering_processor.h" +#include "hid_core/irsensor/image_transfer_processor.h" +#include "hid_core/irsensor/ir_led_processor.h" +#include "hid_core/irsensor/moment_processor.h" +#include "hid_core/irsensor/pointing_processor.h" +#include "hid_core/irsensor/tera_plugin_processor.h" namespace Service::IRS { @@ -315,7 +315,7 @@ void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) { if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && npad_id != Core::HID::NpadIdType::Handheld) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(Service::HID::InvalidNpadId); + rb.Push(Service::HID::ResultInvalidNpadId); return; } diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index c8e6dab17..06b7279ee 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -4,10 +4,10 @@ #pragma once #include "core/core.h" -#include "core/hid/hid_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irsensor/processor_base.h" #include "core/hle/service/service.h" +#include "hid_core/hid_types.h" +#include "hid_core/irsensor/irs_types.h" +#include "hid_core/irsensor/processor_base.h" namespace Core::HID { class EmulatedController; diff --git a/src/core/hle/service/hid/irs_ring_lifo.h b/src/core/hle/service/hid/irs_ring_lifo.h deleted file mode 100644 index 255d1d296..000000000 --- a/src/core/hle/service/hid/irs_ring_lifo.h +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include <array> - -#include "common/common_types.h" - -namespace Service::IRS { - -template <typename State, std::size_t max_buffer_size> -struct Lifo { - s64 sampling_number{}; - s64 buffer_count{}; - std::array<State, max_buffer_size> entries{}; - - const State& ReadCurrentEntry() const { - return entries[GetBufferTail()]; - } - - const State& ReadPreviousEntry() const { - return entries[GetPreviousEntryIndex()]; - } - - s64 GetBufferTail() const { - return sampling_number % max_buffer_size; - } - - std::size_t GetPreviousEntryIndex() const { - return static_cast<size_t>((GetBufferTail() + max_buffer_size - 1) % max_buffer_size); - } - - std::size_t GetNextEntryIndex() const { - return static_cast<size_t>((GetBufferTail() + 1) % max_buffer_size); - } - - void WriteNextEntry(const State& new_state) { - if (buffer_count < static_cast<s64>(max_buffer_size)) { - buffer_count++; - } - sampling_number++; - entries[GetBufferTail()] = new_state; - } -}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.cpp b/src/core/hle/service/hid/irsensor/clustering_processor.cpp deleted file mode 100644 index c559eb0d5..000000000 --- a/src/core/hle/service/hid/irsensor/clustering_processor.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include <queue> - -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/irsensor/clustering_processor.h" - -namespace Service::IRS { -ClusteringProcessor::ClusteringProcessor(Core::System& system_, - Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index) - : device{device_format}, system{system_} { - npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index); - - device.mode = Core::IrSensor::IrSensorMode::ClusteringProcessor; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - SetDefaultConfig(); - - shared_memory = std::construct_at( - reinterpret_cast<ClusteringSharedMemory*>(&device_format.state.processor_raw_data)); - - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, - .is_npad_service = true, - }; - callback_key = npad_device->SetCallback(engine_callback); -} - -ClusteringProcessor::~ClusteringProcessor() { - npad_device->DeleteCallback(callback_key); -}; - -void ClusteringProcessor::StartProcessor() { - device.camera_status = Core::IrSensor::IrCameraStatus::Available; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; -} - -void ClusteringProcessor::SuspendProcessor() {} - -void ClusteringProcessor::StopProcessor() {} - -void ClusteringProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { - if (type != Core::HID::ControllerTriggerType::IrSensor) { - return; - } - - next_state = {}; - const auto& camera_data = npad_device->GetCamera(); - auto filtered_image = camera_data.data; - - RemoveLowIntensityData(filtered_image); - - const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x); - const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y); - const auto window_end_x = - window_start_x + static_cast<std::size_t>(current_config.window_of_interest.width); - const auto window_end_y = - window_start_y + static_cast<std::size_t>(current_config.window_of_interest.height); - - for (std::size_t y = window_start_y; y < window_end_y; y++) { - for (std::size_t x = window_start_x; x < window_end_x; x++) { - u8 pixel = GetPixel(filtered_image, x, y); - if (pixel == 0) { - continue; - } - const auto cluster = GetClusterProperties(filtered_image, x, y); - if (cluster.pixel_count > current_config.pixel_count_max) { - continue; - } - if (cluster.pixel_count < current_config.pixel_count_min) { - continue; - } - // Cluster object limit reached - if (next_state.object_count >= next_state.data.size()) { - continue; - } - next_state.data[next_state.object_count] = cluster; - next_state.object_count++; - } - } - - next_state.sampling_number = camera_data.sample; - next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count(); - next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; - shared_memory->clustering_lifo.WriteNextEntry(next_state); - - if (!IsProcessorActive()) { - StartProcessor(); - } -} - -void ClusteringProcessor::RemoveLowIntensityData(std::vector<u8>& data) { - for (u8& pixel : data) { - if (pixel < current_config.pixel_count_min) { - pixel = 0; - } - } -} - -ClusteringProcessor::ClusteringData ClusteringProcessor::GetClusterProperties(std::vector<u8>& data, - std::size_t x, - std::size_t y) { - using DataPoint = Common::Point<std::size_t>; - std::queue<DataPoint> search_points{}; - ClusteringData current_cluster = GetPixelProperties(data, x, y); - SetPixel(data, x, y, 0); - search_points.emplace<DataPoint>({x, y}); - - while (!search_points.empty()) { - const auto point = search_points.front(); - search_points.pop(); - - // Avoid negative numbers - if (point.x == 0 || point.y == 0) { - continue; - } - - std::array<DataPoint, 4> new_points{ - DataPoint{point.x - 1, point.y}, - {point.x, point.y - 1}, - {point.x + 1, point.y}, - {point.x, point.y + 1}, - }; - - for (const auto new_point : new_points) { - if (new_point.x >= width) { - continue; - } - if (new_point.y >= height) { - continue; - } - if (GetPixel(data, new_point.x, new_point.y) < current_config.object_intensity_min) { - continue; - } - const ClusteringData cluster = GetPixelProperties(data, new_point.x, new_point.y); - current_cluster = MergeCluster(current_cluster, cluster); - SetPixel(data, new_point.x, new_point.y, 0); - search_points.emplace<DataPoint>({new_point.x, new_point.y}); - } - } - - return current_cluster; -} - -ClusteringProcessor::ClusteringData ClusteringProcessor::GetPixelProperties( - const std::vector<u8>& data, std::size_t x, std::size_t y) const { - return { - .average_intensity = GetPixel(data, x, y) / 255.0f, - .centroid = - { - .x = static_cast<f32>(x), - .y = static_cast<f32>(y), - - }, - .pixel_count = 1, - .bound = - { - .x = static_cast<s16>(x), - .y = static_cast<s16>(y), - .width = 1, - .height = 1, - }, - }; -} - -ClusteringProcessor::ClusteringData ClusteringProcessor::MergeCluster( - const ClusteringData a, const ClusteringData b) const { - const f32 a_pixel_count = static_cast<f32>(a.pixel_count); - const f32 b_pixel_count = static_cast<f32>(b.pixel_count); - const f32 pixel_count = a_pixel_count + b_pixel_count; - const f32 average_intensity = - (a.average_intensity * a_pixel_count + b.average_intensity * b_pixel_count) / pixel_count; - const Core::IrSensor::IrsCentroid centroid = { - .x = (a.centroid.x * a_pixel_count + b.centroid.x * b_pixel_count) / pixel_count, - .y = (a.centroid.y * a_pixel_count + b.centroid.y * b_pixel_count) / pixel_count, - }; - s16 bound_start_x = a.bound.x < b.bound.x ? a.bound.x : b.bound.x; - s16 bound_start_y = a.bound.y < b.bound.y ? a.bound.y : b.bound.y; - s16 a_bound_end_x = a.bound.x + a.bound.width; - s16 a_bound_end_y = a.bound.y + a.bound.height; - s16 b_bound_end_x = b.bound.x + b.bound.width; - s16 b_bound_end_y = b.bound.y + b.bound.height; - - const Core::IrSensor::IrsRect bound = { - .x = bound_start_x, - .y = bound_start_y, - .width = a_bound_end_x > b_bound_end_x ? static_cast<s16>(a_bound_end_x - bound_start_x) - : static_cast<s16>(b_bound_end_x - bound_start_x), - .height = a_bound_end_y > b_bound_end_y ? static_cast<s16>(a_bound_end_y - bound_start_y) - : static_cast<s16>(b_bound_end_y - bound_start_y), - }; - - return { - .average_intensity = average_intensity, - .centroid = centroid, - .pixel_count = static_cast<u32>(pixel_count), - .bound = bound, - }; -} - -u8 ClusteringProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const { - if ((y * width) + x >= data.size()) { - return 0; - } - return data[(y * width) + x]; -} - -void ClusteringProcessor::SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value) { - if ((y * width) + x >= data.size()) { - return; - } - data[(y * width) + x] = value; -} - -void ClusteringProcessor::SetDefaultConfig() { - using namespace std::literals::chrono_literals; - current_config.camera_config.exposure_time = std::chrono::microseconds(200ms).count(); - current_config.camera_config.gain = 2; - current_config.camera_config.is_negative_used = false; - current_config.camera_config.light_target = Core::IrSensor::CameraLightTarget::BrightLeds; - current_config.window_of_interest = { - .x = 0, - .y = 0, - .width = width, - .height = height, - }; - current_config.pixel_count_min = 3; - current_config.pixel_count_max = static_cast<u32>(GetDataSize(format)); - current_config.is_external_light_filter_enabled = true; - current_config.object_intensity_min = 150; - - npad_device->SetCameraFormat(format); -} - -void ClusteringProcessor::SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config) { - current_config.camera_config.exposure_time = config.camera_config.exposure_time; - current_config.camera_config.gain = config.camera_config.gain; - current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; - current_config.camera_config.light_target = - static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); - current_config.window_of_interest = config.window_of_interest; - current_config.pixel_count_min = config.pixel_count_min; - current_config.pixel_count_max = config.pixel_count_max; - current_config.is_external_light_filter_enabled = config.is_external_light_filter_enabled; - current_config.object_intensity_min = config.object_intensity_min; - - LOG_INFO(Service_IRS, - "Processor config, exposure_time={}, gain={}, is_negative_used={}, " - "light_target={}, window_of_interest=({}, {}, {}, {}), pixel_count_min={}, " - "pixel_count_max={}, is_external_light_filter_enabled={}, object_intensity_min={}", - current_config.camera_config.exposure_time, current_config.camera_config.gain, - current_config.camera_config.is_negative_used, - current_config.camera_config.light_target, current_config.window_of_interest.x, - current_config.window_of_interest.y, current_config.window_of_interest.width, - current_config.window_of_interest.height, current_config.pixel_count_min, - current_config.pixel_count_max, current_config.is_external_light_filter_enabled, - current_config.object_intensity_min); - - npad_device->SetCameraFormat(format); -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/clustering_processor.h b/src/core/hle/service/hid/irsensor/clustering_processor.h deleted file mode 100644 index 83f34734a..000000000 --- a/src/core/hle/service/hid/irsensor/clustering_processor.h +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irs_ring_lifo.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Core { -class System; -} - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::IRS { -class ClusteringProcessor final : public ProcessorBase { -public: - explicit ClusteringProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index); - ~ClusteringProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedClusteringProcessorConfig config); - -private: - static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size320x240; - static constexpr std::size_t width = 320; - static constexpr std::size_t height = 240; - - // This is nn::irsensor::ClusteringProcessorConfig - struct ClusteringProcessorConfig { - Core::IrSensor::CameraConfig camera_config; - Core::IrSensor::IrsRect window_of_interest; - u32 pixel_count_min; - u32 pixel_count_max; - u32 object_intensity_min; - bool is_external_light_filter_enabled; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(ClusteringProcessorConfig) == 0x30, - "ClusteringProcessorConfig is an invalid size"); - - // This is nn::irsensor::AdaptiveClusteringProcessorConfig - struct AdaptiveClusteringProcessorConfig { - Core::IrSensor::AdaptiveClusteringMode mode; - Core::IrSensor::AdaptiveClusteringTargetDistance target_distance; - }; - static_assert(sizeof(AdaptiveClusteringProcessorConfig) == 0x8, - "AdaptiveClusteringProcessorConfig is an invalid size"); - - // This is nn::irsensor::ClusteringData - struct ClusteringData { - f32 average_intensity; - Core::IrSensor::IrsCentroid centroid; - u32 pixel_count; - Core::IrSensor::IrsRect bound; - }; - static_assert(sizeof(ClusteringData) == 0x18, "ClusteringData is an invalid size"); - - // This is nn::irsensor::ClusteringProcessorState - struct ClusteringProcessorState { - s64 sampling_number; - u64 timestamp; - u8 object_count; - INSERT_PADDING_BYTES(3); - Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; - std::array<ClusteringData, 0x10> data; - }; - static_assert(sizeof(ClusteringProcessorState) == 0x198, - "ClusteringProcessorState is an invalid size"); - - struct ClusteringSharedMemory { - Service::IRS::Lifo<ClusteringProcessorState, 6> clustering_lifo; - static_assert(sizeof(clustering_lifo) == 0x9A0, "clustering_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x11F); - }; - static_assert(sizeof(ClusteringSharedMemory) == 0xE20, - "ClusteringSharedMemory is an invalid size"); - - void OnControllerUpdate(Core::HID::ControllerTriggerType type); - void RemoveLowIntensityData(std::vector<u8>& data); - ClusteringData GetClusterProperties(std::vector<u8>& data, std::size_t x, std::size_t y); - ClusteringData GetPixelProperties(const std::vector<u8>& data, std::size_t x, - std::size_t y) const; - ClusteringData MergeCluster(const ClusteringData a, const ClusteringData b) const; - u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const; - void SetPixel(std::vector<u8>& data, std::size_t x, std::size_t y, u8 value); - - // Sets config parameters of the camera - void SetDefaultConfig(); - - ClusteringSharedMemory* shared_memory = nullptr; - ClusteringProcessorState next_state{}; - - ClusteringProcessorConfig current_config{}; - Core::IrSensor::DeviceFormat& device; - Core::HID::EmulatedController* npad_device; - int callback_key{}; - - Core::System& system; -}; -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp deleted file mode 100644 index 22067a591..000000000 --- a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/irsensor/image_transfer_processor.h" -#include "core/memory.h" - -namespace Service::IRS { -ImageTransferProcessor::ImageTransferProcessor(Core::System& system_, - Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index) - : device{device_format}, system{system_} { - npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index); - - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, - .is_npad_service = true, - }; - callback_key = npad_device->SetCallback(engine_callback); - - device.mode = Core::IrSensor::IrSensorMode::ImageTransferProcessor; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; -} - -ImageTransferProcessor::~ImageTransferProcessor() { - npad_device->DeleteCallback(callback_key); -}; - -void ImageTransferProcessor::StartProcessor() { - is_active = true; - device.camera_status = Core::IrSensor::IrCameraStatus::Available; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; - processor_state.sampling_number = 0; - processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; -} - -void ImageTransferProcessor::SuspendProcessor() {} - -void ImageTransferProcessor::StopProcessor() {} - -void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { - if (type != Core::HID::ControllerTriggerType::IrSensor) { - return; - } - if (transfer_memory == 0) { - return; - } - - const auto& camera_data = npad_device->GetCamera(); - - // This indicates how much ambient light is present - processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; - processor_state.sampling_number = camera_data.sample; - - if (camera_data.format != current_config.origin_format) { - LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format, - current_config.origin_format); - system.ApplicationMemory().ZeroBlock(transfer_memory, - GetDataSize(current_config.trimming_format)); - return; - } - - if (current_config.origin_format > current_config.trimming_format) { - LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}", - current_config.origin_format, current_config.trimming_format); - system.ApplicationMemory().ZeroBlock(transfer_memory, - GetDataSize(current_config.trimming_format)); - return; - } - - std::vector<u8> window_data{}; - const auto origin_width = GetDataWidth(current_config.origin_format); - const auto origin_height = GetDataHeight(current_config.origin_format); - const auto trimming_width = GetDataWidth(current_config.trimming_format); - const auto trimming_height = GetDataHeight(current_config.trimming_format); - window_data.resize(GetDataSize(current_config.trimming_format)); - - if (trimming_width + current_config.trimming_start_x > origin_width || - trimming_height + current_config.trimming_start_y > origin_height) { - LOG_WARNING(Service_IRS, - "Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})", - current_config.trimming_start_x, current_config.trimming_start_y, - trimming_width, trimming_height, origin_width, origin_height); - system.ApplicationMemory().ZeroBlock(transfer_memory, - GetDataSize(current_config.trimming_format)); - return; - } - - for (std::size_t y = 0; y < trimming_height; y++) { - for (std::size_t x = 0; x < trimming_width; x++) { - const std::size_t window_index = (y * trimming_width) + x; - const std::size_t origin_index = - ((y + current_config.trimming_start_y) * origin_width) + x + - current_config.trimming_start_x; - window_data[window_index] = camera_data.data[origin_index]; - } - } - - system.ApplicationMemory().WriteBlock(transfer_memory, window_data.data(), - GetDataSize(current_config.trimming_format)); - - if (!IsProcessorActive()) { - StartProcessor(); - } -} - -void ImageTransferProcessor::SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config) { - current_config.camera_config.exposure_time = config.camera_config.exposure_time; - current_config.camera_config.gain = config.camera_config.gain; - current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; - current_config.camera_config.light_target = - static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); - current_config.origin_format = - static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format); - current_config.trimming_format = - static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.format); - current_config.trimming_start_x = 0; - current_config.trimming_start_y = 0; - - npad_device->SetCameraFormat(current_config.origin_format); -} - -void ImageTransferProcessor::SetConfig( - Core::IrSensor::PackedImageTransferProcessorExConfig config) { - current_config.camera_config.exposure_time = config.camera_config.exposure_time; - current_config.camera_config.gain = config.camera_config.gain; - current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; - current_config.camera_config.light_target = - static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); - current_config.origin_format = - static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.origin_format); - current_config.trimming_format = - static_cast<Core::IrSensor::ImageTransferProcessorFormat>(config.trimming_format); - current_config.trimming_start_x = config.trimming_start_x; - current_config.trimming_start_y = config.trimming_start_y; - - npad_device->SetCameraFormat(current_config.origin_format); -} - -void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { - transfer_memory = t_mem; -} - -Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState( - std::vector<u8>& data) const { - const auto size = GetDataSize(current_config.trimming_format); - data.resize(size); - system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size); - return processor_state; -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.h b/src/core/hle/service/hid/irsensor/image_transfer_processor.h deleted file mode 100644 index 7f42d8453..000000000 --- a/src/core/hle/service/hid/irsensor/image_transfer_processor.h +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/typed_address.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Core { -class System; -} - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::IRS { -class ImageTransferProcessor final : public ProcessorBase { -public: - explicit ImageTransferProcessor(Core::System& system_, - Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index); - ~ImageTransferProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedImageTransferProcessorConfig config); - void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config); - - // Transfer memory where the image data will be stored - void SetTransferMemoryAddress(Common::ProcessAddress t_mem); - - Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const; - -private: - // This is nn::irsensor::ImageTransferProcessorConfig - struct ImageTransferProcessorConfig { - Core::IrSensor::CameraConfig camera_config; - Core::IrSensor::ImageTransferProcessorFormat format; - }; - static_assert(sizeof(ImageTransferProcessorConfig) == 0x20, - "ImageTransferProcessorConfig is an invalid size"); - - // This is nn::irsensor::ImageTransferProcessorExConfig - struct ImageTransferProcessorExConfig { - Core::IrSensor::CameraConfig camera_config; - Core::IrSensor::ImageTransferProcessorFormat origin_format; - Core::IrSensor::ImageTransferProcessorFormat trimming_format; - u16 trimming_start_x; - u16 trimming_start_y; - bool is_external_light_filter_enabled; - INSERT_PADDING_BYTES(3); - }; - static_assert(sizeof(ImageTransferProcessorExConfig) == 0x28, - "ImageTransferProcessorExConfig is an invalid size"); - - void OnControllerUpdate(Core::HID::ControllerTriggerType type); - - ImageTransferProcessorExConfig current_config{}; - Core::IrSensor::ImageTransferProcessorState processor_state{}; - Core::IrSensor::DeviceFormat& device; - Core::HID::EmulatedController* npad_device; - int callback_key{}; - - Core::System& system; - Common::ProcessAddress transfer_memory{}; -}; -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp b/src/core/hle/service/hid/irsensor/ir_led_processor.cpp deleted file mode 100644 index 8e6dd99e4..000000000 --- a/src/core/hle/service/hid/irsensor/ir_led_processor.cpp +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/hle/service/hid/irsensor/ir_led_processor.h" - -namespace Service::IRS { -IrLedProcessor::IrLedProcessor(Core::IrSensor::DeviceFormat& device_format) - : device(device_format) { - device.mode = Core::IrSensor::IrSensorMode::IrLedProcessor; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; -} - -IrLedProcessor::~IrLedProcessor() = default; - -void IrLedProcessor::StartProcessor() {} - -void IrLedProcessor::SuspendProcessor() {} - -void IrLedProcessor::StopProcessor() {} - -void IrLedProcessor::SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config) { - current_config.light_target = - static_cast<Core::IrSensor::CameraLightTarget>(config.light_target); -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/ir_led_processor.h b/src/core/hle/service/hid/irsensor/ir_led_processor.h deleted file mode 100644 index c3d8693c9..000000000 --- a/src/core/hle/service/hid/irsensor/ir_led_processor.h +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Service::IRS { -class IrLedProcessor final : public ProcessorBase { -public: - explicit IrLedProcessor(Core::IrSensor::DeviceFormat& device_format); - ~IrLedProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedIrLedProcessorConfig config); - -private: - // This is nn::irsensor::IrLedProcessorConfig - struct IrLedProcessorConfig { - Core::IrSensor::CameraLightTarget light_target; - }; - static_assert(sizeof(IrLedProcessorConfig) == 0x4, "IrLedProcessorConfig is an invalid size"); - - struct IrLedProcessorState { - s64 sampling_number; - u64 timestamp; - std::array<u8, 0x8> data; - }; - static_assert(sizeof(IrLedProcessorState) == 0x18, "IrLedProcessorState is an invalid size"); - - IrLedProcessorConfig current_config{}; - Core::IrSensor::DeviceFormat& device; -}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/moment_processor.cpp b/src/core/hle/service/hid/irsensor/moment_processor.cpp deleted file mode 100644 index cf045bda7..000000000 --- a/src/core/hle/service/hid/irsensor/moment_processor.cpp +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/irsensor/moment_processor.h" - -namespace Service::IRS { -static constexpr auto format = Core::IrSensor::ImageTransferProcessorFormat::Size40x30; -static constexpr std::size_t ImageWidth = 40; -static constexpr std::size_t ImageHeight = 30; - -MomentProcessor::MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index) - : device(device_format), system{system_} { - npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index); - - device.mode = Core::IrSensor::IrSensorMode::MomentProcessor; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; - - shared_memory = std::construct_at( - reinterpret_cast<MomentSharedMemory*>(&device_format.state.processor_raw_data)); - - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, - .is_npad_service = true, - }; - callback_key = npad_device->SetCallback(engine_callback); -} - -MomentProcessor::~MomentProcessor() { - npad_device->DeleteCallback(callback_key); -}; - -void MomentProcessor::StartProcessor() { - device.camera_status = Core::IrSensor::IrCameraStatus::Available; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Ready; -} - -void MomentProcessor::SuspendProcessor() {} - -void MomentProcessor::StopProcessor() {} - -void MomentProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType type) { - if (type != Core::HID::ControllerTriggerType::IrSensor) { - return; - } - - next_state = {}; - const auto& camera_data = npad_device->GetCamera(); - - const auto window_width = static_cast<std::size_t>(current_config.window_of_interest.width); - const auto window_height = static_cast<std::size_t>(current_config.window_of_interest.height); - const auto window_start_x = static_cast<std::size_t>(current_config.window_of_interest.x); - const auto window_start_y = static_cast<std::size_t>(current_config.window_of_interest.y); - - const std::size_t block_width = window_width / Columns; - const std::size_t block_height = window_height / Rows; - - for (std::size_t row = 0; row < Rows; row++) { - for (std::size_t column = 0; column < Columns; column++) { - const size_t x_pos = (column * block_width) + window_start_x; - const size_t y_pos = (row * block_height) + window_start_y; - auto& statistic = next_state.statistic[column + (row * Columns)]; - statistic = GetStatistic(camera_data.data, x_pos, y_pos, block_width, block_height); - } - } - - next_state.sampling_number = camera_data.sample; - next_state.timestamp = system.CoreTiming().GetGlobalTimeNs().count(); - next_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low; - shared_memory->moment_lifo.WriteNextEntry(next_state); - - if (!IsProcessorActive()) { - StartProcessor(); - } -} - -u8 MomentProcessor::GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const { - if ((y * ImageWidth) + x >= data.size()) { - return 0; - } - return data[(y * ImageWidth) + x]; -} - -MomentProcessor::MomentStatistic MomentProcessor::GetStatistic(const std::vector<u8>& data, - std::size_t start_x, - std::size_t start_y, - std::size_t width, - std::size_t height) const { - // The actual implementation is always 320x240 - static constexpr std::size_t RealWidth = 320; - static constexpr std::size_t RealHeight = 240; - static constexpr std::size_t Threshold = 30; - MomentStatistic statistic{}; - std::size_t active_points{}; - - // Sum all data points on the block that meet with the threshold - for (std::size_t y = 0; y < width; y++) { - for (std::size_t x = 0; x < height; x++) { - const size_t x_pos = x + start_x; - const size_t y_pos = y + start_y; - const auto pixel = - GetPixel(data, x_pos * ImageWidth / RealWidth, y_pos * ImageHeight / RealHeight); - - if (pixel < Threshold) { - continue; - } - - statistic.average_intensity += pixel; - - statistic.centroid.x += static_cast<float>(x_pos); - statistic.centroid.y += static_cast<float>(y_pos); - - active_points++; - } - } - - // Return an empty field if no points were available - if (active_points == 0) { - return {}; - } - - // Finally calculate the actual centroid and average intensity - statistic.centroid.x /= static_cast<float>(active_points); - statistic.centroid.y /= static_cast<float>(active_points); - statistic.average_intensity /= static_cast<f32>(width * height); - - return statistic; -} - -void MomentProcessor::SetConfig(Core::IrSensor::PackedMomentProcessorConfig config) { - current_config.camera_config.exposure_time = config.camera_config.exposure_time; - current_config.camera_config.gain = config.camera_config.gain; - current_config.camera_config.is_negative_used = config.camera_config.is_negative_used; - current_config.camera_config.light_target = - static_cast<Core::IrSensor::CameraLightTarget>(config.camera_config.light_target); - current_config.window_of_interest = config.window_of_interest; - current_config.preprocess = - static_cast<Core::IrSensor::MomentProcessorPreprocess>(config.preprocess); - current_config.preprocess_intensity_threshold = config.preprocess_intensity_threshold; - - npad_device->SetCameraFormat(format); -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/moment_processor.h b/src/core/hle/service/hid/irsensor/moment_processor.h deleted file mode 100644 index 398cfbdc1..000000000 --- a/src/core/hle/service/hid/irsensor/moment_processor.h +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irs_ring_lifo.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Core { -class System; -} - -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - -namespace Service::IRS { -class MomentProcessor final : public ProcessorBase { -public: - explicit MomentProcessor(Core::System& system_, Core::IrSensor::DeviceFormat& device_format, - std::size_t npad_index); - ~MomentProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedMomentProcessorConfig config); - -private: - static constexpr std::size_t Columns = 8; - static constexpr std::size_t Rows = 6; - - // This is nn::irsensor::MomentProcessorConfig - struct MomentProcessorConfig { - Core::IrSensor::CameraConfig camera_config; - Core::IrSensor::IrsRect window_of_interest; - Core::IrSensor::MomentProcessorPreprocess preprocess; - u32 preprocess_intensity_threshold; - }; - static_assert(sizeof(MomentProcessorConfig) == 0x28, - "MomentProcessorConfig is an invalid size"); - - // This is nn::irsensor::MomentStatistic - struct MomentStatistic { - f32 average_intensity; - Core::IrSensor::IrsCentroid centroid; - }; - static_assert(sizeof(MomentStatistic) == 0xC, "MomentStatistic is an invalid size"); - - // This is nn::irsensor::MomentProcessorState - struct MomentProcessorState { - s64 sampling_number; - u64 timestamp; - Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; - INSERT_PADDING_BYTES(4); - std::array<MomentStatistic, Columns * Rows> statistic; - }; - static_assert(sizeof(MomentProcessorState) == 0x258, "MomentProcessorState is an invalid size"); - - struct MomentSharedMemory { - Service::IRS::Lifo<MomentProcessorState, 6> moment_lifo; - }; - static_assert(sizeof(MomentSharedMemory) == 0xE20, "MomentSharedMemory is an invalid size"); - - void OnControllerUpdate(Core::HID::ControllerTriggerType type); - u8 GetPixel(const std::vector<u8>& data, std::size_t x, std::size_t y) const; - MomentStatistic GetStatistic(const std::vector<u8>& data, std::size_t start_x, - std::size_t start_y, std::size_t width, std::size_t height) const; - - MomentSharedMemory* shared_memory = nullptr; - MomentProcessorState next_state{}; - - MomentProcessorConfig current_config{}; - Core::IrSensor::DeviceFormat& device; - Core::HID::EmulatedController* npad_device; - int callback_key{}; - - Core::System& system; -}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.cpp b/src/core/hle/service/hid/irsensor/pointing_processor.cpp deleted file mode 100644 index 929f177fc..000000000 --- a/src/core/hle/service/hid/irsensor/pointing_processor.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/hle/service/hid/irsensor/pointing_processor.h" - -namespace Service::IRS { -PointingProcessor::PointingProcessor(Core::IrSensor::DeviceFormat& device_format) - : device(device_format) { - device.mode = Core::IrSensor::IrSensorMode::PointingProcessorMarker; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; -} - -PointingProcessor::~PointingProcessor() = default; - -void PointingProcessor::StartProcessor() {} - -void PointingProcessor::SuspendProcessor() {} - -void PointingProcessor::StopProcessor() {} - -void PointingProcessor::SetConfig(Core::IrSensor::PackedPointingProcessorConfig config) { - current_config.window_of_interest = config.window_of_interest; -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/pointing_processor.h b/src/core/hle/service/hid/irsensor/pointing_processor.h deleted file mode 100644 index d63423aff..000000000 --- a/src/core/hle/service/hid/irsensor/pointing_processor.h +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Service::IRS { -class PointingProcessor final : public ProcessorBase { -public: - explicit PointingProcessor(Core::IrSensor::DeviceFormat& device_format); - ~PointingProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedPointingProcessorConfig config); - -private: - // This is nn::irsensor::PointingProcessorConfig - struct PointingProcessorConfig { - Core::IrSensor::IrsRect window_of_interest; - }; - static_assert(sizeof(PointingProcessorConfig) == 0x8, - "PointingProcessorConfig is an invalid size"); - - struct PointingProcessorMarkerData { - u8 pointing_status; - INSERT_PADDING_BYTES(3); - u32 unknown; - float unknown_float1; - float position_x; - float position_y; - float unknown_float2; - Core::IrSensor::IrsRect window_of_interest; - }; - static_assert(sizeof(PointingProcessorMarkerData) == 0x20, - "PointingProcessorMarkerData is an invalid size"); - - struct PointingProcessorMarkerState { - s64 sampling_number; - u64 timestamp; - std::array<PointingProcessorMarkerData, 0x3> data; - }; - static_assert(sizeof(PointingProcessorMarkerState) == 0x70, - "PointingProcessorMarkerState is an invalid size"); - - PointingProcessorConfig current_config{}; - Core::IrSensor::DeviceFormat& device; -}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/processor_base.cpp b/src/core/hle/service/hid/irsensor/processor_base.cpp deleted file mode 100644 index 4d43ca17a..000000000 --- a/src/core/hle/service/hid/irsensor/processor_base.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Service::IRS { - -ProcessorBase::ProcessorBase() {} -ProcessorBase::~ProcessorBase() = default; - -bool ProcessorBase::IsProcessorActive() const { - return is_active; -} - -std::size_t ProcessorBase::GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const { - switch (format) { - case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: - return 320 * 240; - case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: - return 160 * 120; - case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: - return 80 * 60; - case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: - return 40 * 30; - case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: - return 20 * 15; - default: - return 0; - } -} - -std::size_t ProcessorBase::GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const { - switch (format) { - case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: - return 320; - case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: - return 160; - case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: - return 80; - case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: - return 40; - case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: - return 20; - default: - return 0; - } -} - -std::size_t ProcessorBase::GetDataHeight( - Core::IrSensor::ImageTransferProcessorFormat format) const { - switch (format) { - case Core::IrSensor::ImageTransferProcessorFormat::Size320x240: - return 240; - case Core::IrSensor::ImageTransferProcessorFormat::Size160x120: - return 120; - case Core::IrSensor::ImageTransferProcessorFormat::Size80x60: - return 60; - case Core::IrSensor::ImageTransferProcessorFormat::Size40x30: - return 30; - case Core::IrSensor::ImageTransferProcessorFormat::Size20x15: - return 15; - default: - return 0; - } -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/processor_base.h b/src/core/hle/service/hid/irsensor/processor_base.h deleted file mode 100644 index bc0d2977b..000000000 --- a/src/core/hle/service/hid/irsensor/processor_base.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/hid/irs_types.h" - -namespace Service::IRS { -class ProcessorBase { -public: - explicit ProcessorBase(); - virtual ~ProcessorBase(); - - virtual void StartProcessor() = 0; - virtual void SuspendProcessor() = 0; - virtual void StopProcessor() = 0; - - bool IsProcessorActive() const; - -protected: - /// Returns the number of bytes the image uses - std::size_t GetDataSize(Core::IrSensor::ImageTransferProcessorFormat format) const; - - /// Returns the width of the image - std::size_t GetDataWidth(Core::IrSensor::ImageTransferProcessorFormat format) const; - - /// Returns the height of the image - std::size_t GetDataHeight(Core::IrSensor::ImageTransferProcessorFormat format) const; - - bool is_active{false}; -}; -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp b/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp deleted file mode 100644 index e691c840a..000000000 --- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "core/hle/service/hid/irsensor/tera_plugin_processor.h" - -namespace Service::IRS { -TeraPluginProcessor::TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format) - : device(device_format) { - device.mode = Core::IrSensor::IrSensorMode::TeraPluginProcessor; - device.camera_status = Core::IrSensor::IrCameraStatus::Unconnected; - device.camera_internal_status = Core::IrSensor::IrCameraInternalStatus::Stopped; -} - -TeraPluginProcessor::~TeraPluginProcessor() = default; - -void TeraPluginProcessor::StartProcessor() {} - -void TeraPluginProcessor::SuspendProcessor() {} - -void TeraPluginProcessor::StopProcessor() {} - -void TeraPluginProcessor::SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config) { - current_config.mode = config.mode; - current_config.unknown_1 = config.unknown_1; - current_config.unknown_2 = config.unknown_2; - current_config.unknown_3 = config.unknown_3; -} - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h b/src/core/hle/service/hid/irsensor/tera_plugin_processor.h deleted file mode 100644 index bbea7ed0b..000000000 --- a/src/core/hle/service/hid/irsensor/tera_plugin_processor.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hid/irs_types.h" -#include "core/hle/service/hid/irsensor/processor_base.h" - -namespace Service::IRS { -class TeraPluginProcessor final : public ProcessorBase { -public: - explicit TeraPluginProcessor(Core::IrSensor::DeviceFormat& device_format); - ~TeraPluginProcessor() override; - - // Called when the processor is initialized - void StartProcessor() override; - - // Called when the processor is suspended - void SuspendProcessor() override; - - // Called when the processor is stopped - void StopProcessor() override; - - // Sets config parameters of the camera - void SetConfig(Core::IrSensor::PackedTeraPluginProcessorConfig config); - -private: - // This is nn::irsensor::TeraPluginProcessorConfig - struct TeraPluginProcessorConfig { - u8 mode; - u8 unknown_1; - u8 unknown_2; - u8 unknown_3; - }; - static_assert(sizeof(TeraPluginProcessorConfig) == 0x4, - "TeraPluginProcessorConfig is an invalid size"); - - struct TeraPluginProcessorState { - s64 sampling_number; - u64 timestamp; - Core::IrSensor::CameraAmbientNoiseLevel ambient_noise_level; - std::array<u8, 0x12c> data; - }; - static_assert(sizeof(TeraPluginProcessorState) == 0x140, - "TeraPluginProcessorState is an invalid size"); - - TeraPluginProcessorConfig current_config{}; - Core::IrSensor::DeviceFormat& device; -}; - -} // namespace Service::IRS diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp deleted file mode 100644 index 84b4be3ed..000000000 --- a/src/core/hle/service/hid/resource_manager.cpp +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "common/logging/log.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hid/hid_core.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/service/hid/resource_manager.h" -#include "core/hle/service/ipc_helpers.h" - -#include "core/hle/service/hid/controllers/applet_resource.h" -#include "core/hle/service/hid/controllers/capture_button.h" -#include "core/hle/service/hid/controllers/console_six_axis.h" -#include "core/hle/service/hid/controllers/debug_mouse.h" -#include "core/hle/service/hid/controllers/debug_pad.h" -#include "core/hle/service/hid/controllers/digitizer.h" -#include "core/hle/service/hid/controllers/gesture.h" -#include "core/hle/service/hid/controllers/home_button.h" -#include "core/hle/service/hid/controllers/keyboard.h" -#include "core/hle/service/hid/controllers/mouse.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/controllers/palma.h" -#include "core/hle/service/hid/controllers/seven_six_axis.h" -#include "core/hle/service/hid/controllers/six_axis.h" -#include "core/hle/service/hid/controllers/sleep_button.h" -#include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/types/shared_memory_format.h" -#include "core/hle/service/hid/controllers/unique_pad.h" - -namespace Service::HID { - -// Updating period for each HID device. -// Period time is obtained by measuring the number of samples in a second on HW using a homebrew -// Correct npad_update_ns is 4ms this is overclocked to lower input lag -constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) -constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) -constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) - -ResourceManager::ResourceManager(Core::System& system_) - : system{system_}, service_context{system_, "hid"} { - applet_resource = std::make_shared<AppletResource>(system); -} - -ResourceManager::~ResourceManager() = default; - -void ResourceManager::Initialize() { - if (is_initialized) { - return; - } - - system.HIDCore().ReloadInputDevices(); - - InitializeHidCommonSampler(); - InitializeTouchScreenSampler(); - InitializeConsoleSixAxisSampler(); - InitializeAHidSampler(); - - is_initialized = true; -} - -std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { - return applet_resource; -} - -std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { - return capture_button; -} - -std::shared_ptr<ConsoleSixAxis> ResourceManager::GetConsoleSixAxis() const { - return console_six_axis; -} - -std::shared_ptr<DebugMouse> ResourceManager::GetDebugMouse() const { - return debug_mouse; -} - -std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const { - return debug_pad; -} - -std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const { - return digitizer; -} - -std::shared_ptr<Gesture> ResourceManager::GetGesture() const { - return gesture; -} - -std::shared_ptr<HomeButton> ResourceManager::GetHomeButton() const { - return home_button; -} - -std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() const { - return keyboard; -} - -std::shared_ptr<Mouse> ResourceManager::GetMouse() const { - return mouse; -} - -std::shared_ptr<NPad> ResourceManager::GetNpad() const { - return npad; -} - -std::shared_ptr<Palma> ResourceManager::GetPalma() const { - return palma; -} - -std::shared_ptr<SevenSixAxis> ResourceManager::GetSevenSixAxis() const { - return seven_six_axis; -} - -std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() const { - return six_axis; -} - -std::shared_ptr<SleepButton> ResourceManager::GetSleepButton() const { - return sleep_button; -} - -std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() const { - return touch_screen; -} - -std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const { - return unique_pad; -} - -Result ResourceManager::CreateAppletResource(u64 aruid) { - if (aruid == 0) { - const auto result = RegisterCoreAppletResource(); - if (result.IsError()) { - return result; - } - return GetNpad()->Activate(); - } - - const auto result = CreateAppletResourceImpl(aruid); - if (result.IsError()) { - return result; - } - - // Homebrew doesn't try to activate some controllers, so we activate them by default - npad->Activate(); - six_axis->Activate(); - touch_screen->Activate(); - - return GetNpad()->Activate(aruid); -} - -Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { - std::scoped_lock lock{shared_mutex}; - return applet_resource->CreateAppletResource(aruid); -} - -void ResourceManager::InitializeHidCommonSampler() { - debug_pad = std::make_shared<DebugPad>(system.HIDCore()); - mouse = std::make_shared<Mouse>(system.HIDCore()); - debug_mouse = std::make_shared<DebugMouse>(system.HIDCore()); - keyboard = std::make_shared<Keyboard>(system.HIDCore()); - unique_pad = std::make_shared<UniquePad>(system.HIDCore()); - npad = std::make_shared<NPad>(system.HIDCore(), service_context); - gesture = std::make_shared<Gesture>(system.HIDCore()); - home_button = std::make_shared<HomeButton>(system.HIDCore()); - sleep_button = std::make_shared<SleepButton>(system.HIDCore()); - capture_button = std::make_shared<CaptureButton>(system.HIDCore()); - digitizer = std::make_shared<Digitizer>(system.HIDCore()); - - palma = std::make_shared<Palma>(system.HIDCore(), service_context); - six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); - - debug_pad->SetAppletResource(applet_resource); - digitizer->SetAppletResource(applet_resource); - keyboard->SetAppletResource(applet_resource); - npad->SetAppletResource(applet_resource); - six_axis->SetAppletResource(applet_resource); - mouse->SetAppletResource(applet_resource); - debug_mouse->SetAppletResource(applet_resource); - home_button->SetAppletResource(applet_resource); - sleep_button->SetAppletResource(applet_resource); - capture_button->SetAppletResource(applet_resource); -} - -void ResourceManager::InitializeTouchScreenSampler() { - gesture = std::make_shared<Gesture>(system.HIDCore()); - touch_screen = std::make_shared<TouchScreen>(system.HIDCore()); - - touch_screen->SetAppletResource(applet_resource); - gesture->SetAppletResource(applet_resource); -} - -void ResourceManager::InitializeConsoleSixAxisSampler() { - console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore()); - seven_six_axis = std::make_shared<SevenSixAxis>(system); - - console_six_axis->SetAppletResource(applet_resource); -} - -void ResourceManager::InitializeAHidSampler() { - // TODO -} - -Result ResourceManager::RegisterCoreAppletResource() { - std::scoped_lock lock{shared_mutex}; - return applet_resource->RegisterCoreAppletResource(); -} - -Result ResourceManager::UnregisterCoreAppletResource() { - std::scoped_lock lock{shared_mutex}; - return applet_resource->UnregisterCoreAppletResource(); -} - -Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { - std::scoped_lock lock{shared_mutex}; - return applet_resource->RegisterAppletResourceUserId(aruid, bool_value); -} - -void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { - std::scoped_lock lock{shared_mutex}; - applet_resource->UnregisterAppletResourceUserId(aruid); -} - -Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { - std::scoped_lock lock{shared_mutex}; - return applet_resource->GetSharedMemoryHandle(out_handle, aruid); -} - -void ResourceManager::FreeAppletResourceId(u64 aruid) { - std::scoped_lock lock{shared_mutex}; - applet_resource->FreeAppletResourceId(aruid); -} - -void ResourceManager::EnableInput(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; - applet_resource->EnableInput(aruid, is_enabled); -} - -void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; - applet_resource->EnableSixAxisSensor(aruid, is_enabled); -} - -void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; - applet_resource->EnablePadInput(aruid, is_enabled); -} - -void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; - applet_resource->EnableTouchScreen(aruid, is_enabled); -} - -void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - debug_pad->OnUpdate(core_timing); - digitizer->OnUpdate(core_timing); - unique_pad->OnUpdate(core_timing); - gesture->OnUpdate(core_timing); - touch_screen->OnUpdate(core_timing); - palma->OnUpdate(core_timing); - home_button->OnUpdate(core_timing); - sleep_button->OnUpdate(core_timing); - capture_button->OnUpdate(core_timing); -} - -void ResourceManager::UpdateNpad(std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - npad->OnUpdate(core_timing); -} - -void ResourceManager::UpdateMouseKeyboard(std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - mouse->OnUpdate(core_timing); - debug_mouse->OnUpdate(core_timing); - keyboard->OnUpdate(core_timing); -} - -void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - six_axis->OnUpdate(core_timing); - seven_six_axis->OnUpdate(core_timing); - console_six_axis->OnUpdate(core_timing); -} - -IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource, - u64 applet_resource_user_id) - : ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id}, - resource_manager{resource} { - static const FunctionInfo functions[] = { - {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, - }; - RegisterHandlers(functions); - - // Register update callbacks - npad_update_event = Core::Timing::CreateEvent( - "HID::UpdatePadCallback", - [this, resource]( - s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - const auto guard = LockService(); - resource->UpdateNpad(ns_late); - return std::nullopt; - }); - default_update_event = Core::Timing::CreateEvent( - "HID::UpdateDefaultCallback", - [this, resource]( - s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - const auto guard = LockService(); - resource->UpdateControllers(ns_late); - return std::nullopt; - }); - mouse_keyboard_update_event = Core::Timing::CreateEvent( - "HID::UpdateMouseKeyboardCallback", - [this, resource]( - s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - const auto guard = LockService(); - resource->UpdateMouseKeyboard(ns_late); - return std::nullopt; - }); - motion_update_event = Core::Timing::CreateEvent( - "HID::UpdateMotionCallback", - [this, resource]( - s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - const auto guard = LockService(); - resource->UpdateMotion(ns_late); - return std::nullopt; - }); - - system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); - system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, - default_update_event); - system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, - mouse_keyboard_update_event); - system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, - motion_update_event); -} - -IAppletResource::~IAppletResource() { - system.CoreTiming().UnscheduleEvent(npad_update_event); - system.CoreTiming().UnscheduleEvent(default_update_event); - system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event); - system.CoreTiming().UnscheduleEvent(motion_update_event); - resource_manager->FreeAppletResourceId(aruid); -} - -void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) { - Kernel::KSharedMemory* handle; - const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid); - - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw); - - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(result); - rb.PushCopyObjects(handle); -} - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h deleted file mode 100644 index 70d9b6550..000000000 --- a/src/core/hle/service/hid/resource_manager.h +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Core::Timing { -struct EventType; -} - -namespace Kernel { -class KSharedMemory; -} - -namespace Service::HID { -class AppletResource; -class CaptureButton; -class Controller_Stubbed; -class ConsoleSixAxis; -class DebugMouse; -class DebugPad; -class Digitizer; -class Gesture; -class HomeButton; -class Keyboard; -class Mouse; -class NPad; -class Palma; -class SevenSixAxis; -class SixAxis; -class SleepButton; -class TouchScreen; -class UniquePad; - -class ResourceManager { - -public: - explicit ResourceManager(Core::System& system_); - ~ResourceManager(); - - void Initialize(); - - std::shared_ptr<AppletResource> GetAppletResource() const; - std::shared_ptr<CaptureButton> GetCaptureButton() const; - std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; - std::shared_ptr<DebugMouse> GetDebugMouse() const; - std::shared_ptr<DebugPad> GetDebugPad() const; - std::shared_ptr<Digitizer> GetDigitizer() const; - std::shared_ptr<Gesture> GetGesture() const; - std::shared_ptr<HomeButton> GetHomeButton() const; - std::shared_ptr<Keyboard> GetKeyboard() const; - std::shared_ptr<Mouse> GetMouse() const; - std::shared_ptr<NPad> GetNpad() const; - std::shared_ptr<Palma> GetPalma() const; - std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const; - std::shared_ptr<SixAxis> GetSixAxis() const; - std::shared_ptr<SleepButton> GetSleepButton() const; - std::shared_ptr<TouchScreen> GetTouchScreen() const; - std::shared_ptr<UniquePad> GetUniquePad() const; - - Result CreateAppletResource(u64 aruid); - - Result RegisterCoreAppletResource(); - Result UnregisterCoreAppletResource(); - Result RegisterAppletResourceUserId(u64 aruid, bool bool_value); - void UnregisterAppletResourceUserId(u64 aruid); - - Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); - void FreeAppletResourceId(u64 aruid); - - void EnableInput(u64 aruid, bool is_enabled); - void EnableSixAxisSensor(u64 aruid, bool is_enabled); - void EnablePadInput(u64 aruid, bool is_enabled); - void EnableTouchScreen(u64 aruid, bool is_enabled); - - void UpdateControllers(std::chrono::nanoseconds ns_late); - void UpdateNpad(std::chrono::nanoseconds ns_late); - void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); - void UpdateMotion(std::chrono::nanoseconds ns_late); - -private: - Result CreateAppletResourceImpl(u64 aruid); - void InitializeHidCommonSampler(); - void InitializeTouchScreenSampler(); - void InitializeConsoleSixAxisSampler(); - void InitializeAHidSampler(); - - bool is_initialized{false}; - - mutable std::mutex shared_mutex; - std::shared_ptr<AppletResource> applet_resource = nullptr; - - std::shared_ptr<CaptureButton> capture_button = nullptr; - std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; - std::shared_ptr<DebugMouse> debug_mouse = nullptr; - std::shared_ptr<DebugPad> debug_pad = nullptr; - std::shared_ptr<Digitizer> digitizer = nullptr; - std::shared_ptr<Gesture> gesture = nullptr; - std::shared_ptr<HomeButton> home_button = nullptr; - std::shared_ptr<Keyboard> keyboard = nullptr; - std::shared_ptr<Mouse> mouse = nullptr; - std::shared_ptr<NPad> npad = nullptr; - std::shared_ptr<Palma> palma = nullptr; - std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr; - std::shared_ptr<SixAxis> six_axis = nullptr; - std::shared_ptr<SleepButton> sleep_button = nullptr; - std::shared_ptr<TouchScreen> touch_screen = nullptr; - std::shared_ptr<UniquePad> unique_pad = nullptr; - - // TODO: Create these resources - // std::shared_ptr<AudioControl> audio_control = nullptr; - // std::shared_ptr<ButtonConfig> button_config = nullptr; - // std::shared_ptr<Config> config = nullptr; - // std::shared_ptr<Connection> connection = nullptr; - // std::shared_ptr<CustomConfig> custom_config = nullptr; - // std::shared_ptr<Digitizer> digitizer = nullptr; - // std::shared_ptr<Hdls> hdls = nullptr; - // std::shared_ptr<PlayReport> play_report = nullptr; - // std::shared_ptr<Rail> rail = nullptr; - - Core::System& system; - KernelHelpers::ServiceContext service_context; -}; - -class IAppletResource final : public ServiceFramework<IAppletResource> { -public: - explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource, - u64 applet_resource_user_id); - ~IAppletResource() override; - -private: - void GetSharedMemoryHandle(HLERequestContext& ctx); - - std::shared_ptr<Core::Timing::EventType> npad_update_event; - std::shared_ptr<Core::Timing::EventType> default_update_event; - std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; - std::shared_ptr<Core::Timing::EventType> motion_update_event; - - u64 aruid; - std::shared_ptr<ResourceManager> resource_manager; -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h deleted file mode 100644 index 0816784e0..000000000 --- a/src/core/hle/service/hid/ring_lifo.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> - -#include "common/common_types.h" - -namespace Service::HID { - -template <typename State> -struct AtomicStorage { - s64 sampling_number; - State state; -}; - -template <typename State, std::size_t max_buffer_size> -struct Lifo { - s64 timestamp{}; - s64 total_buffer_count = static_cast<s64>(max_buffer_size); - s64 buffer_tail{}; - s64 buffer_count{}; - std::array<AtomicStorage<State>, max_buffer_size> entries{}; - - const AtomicStorage<State>& ReadCurrentEntry() const { - return entries[buffer_tail]; - } - - const AtomicStorage<State>& ReadPreviousEntry() const { - return entries[GetPreviousEntryIndex()]; - } - - std::size_t GetPreviousEntryIndex() const { - return static_cast<size_t>((buffer_tail + max_buffer_size - 1) % max_buffer_size); - } - - std::size_t GetNextEntryIndex() const { - return static_cast<size_t>((buffer_tail + 1) % max_buffer_size); - } - - void WriteNextEntry(const State& new_state) { - if (buffer_count < static_cast<s64>(max_buffer_size) - 1) { - buffer_count++; - } - buffer_tail = GetNextEntryIndex(); - const auto& previous_entry = ReadPreviousEntry(); - entries[buffer_tail].sampling_number = previous_entry.sampling_number + 1; - entries[buffer_tail].state = new_state; - } -}; - -} // namespace Service::HID diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 39df77e43..50e1ed756 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -12,6 +12,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/scratch_buffer.h" +#include "core/guest_memory.h" #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_handle_table.h" #include "core/hle/kernel/k_process.h" @@ -23,19 +24,6 @@ #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" -namespace { -static thread_local std::array read_buffer_data_a{ - Common::ScratchBuffer<u8>(), - Common::ScratchBuffer<u8>(), - Common::ScratchBuffer<u8>(), -}; -static thread_local std::array read_buffer_data_x{ - Common::ScratchBuffer<u8>(), - Common::ScratchBuffer<u8>(), - Common::ScratchBuffer<u8>(), -}; -} // Anonymous namespace - namespace Service { SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_) @@ -181,22 +169,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { } } - buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); - buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); - buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); - buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); + buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors); + buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors); + buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors); + buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors); for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { - buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); + buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); } for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { - buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { - buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { - buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; @@ -246,7 +234,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { if (command_header->buf_c_descriptor_flags == IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); + buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } else { u32 num_buf_c_descriptors = static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; @@ -256,7 +244,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { ASSERT(num_buf_c_descriptors < 14); for (u32 i = 0; i < num_buf_c_descriptors; ++i) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); + buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } } } @@ -343,48 +331,27 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons } std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) const { - static thread_local std::array read_buffer_a{ - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); ASSERT_OR_EXECUTE_MSG( BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_a[buffer_index]; - return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), - BufferDescriptorA()[buffer_index].Size(), - &read_buffer_data_a[buffer_index]); + return gm.Read(BufferDescriptorA()[buffer_index].Address(), + BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); } std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) const { - static thread_local std::array read_buffer_x{ - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); ASSERT_OR_EXECUTE_MSG( BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_x[buffer_index]; - return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), - BufferDescriptorX()[buffer_index].Size(), - &read_buffer_data_x[buffer_index]); + return gm.Read(BufferDescriptorX()[buffer_index].Address(), + BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); } std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - static thread_local std::array read_buffer_a{ - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - }; - static thread_local std::array read_buffer_x{ - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), - }; + Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::UnsafeRead> gm(memory, 0, 0); const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; @@ -401,18 +368,14 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons ASSERT_OR_EXECUTE_MSG( BufferDescriptorA().size() > buffer_index, { return {}; }, "BufferDescriptorA invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_a[buffer_index]; - return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), - BufferDescriptorA()[buffer_index].Size(), - &read_buffer_data_a[buffer_index]); + return gm.Read(BufferDescriptorA()[buffer_index].Address(), + BufferDescriptorA()[buffer_index].Size(), &read_buffer_data_a[buffer_index]); } else { ASSERT_OR_EXECUTE_MSG( BufferDescriptorX().size() > buffer_index, { return {}; }, "BufferDescriptorX invalid buffer_index {}", buffer_index); - auto& read_buffer = read_buffer_x[buffer_index]; - return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), - BufferDescriptorX()[buffer_index].Size(), - &read_buffer_data_x[buffer_index]); + return gm.Read(BufferDescriptorX()[buffer_index].Address(), + BufferDescriptorX()[buffer_index].Size(), &read_buffer_data_x[buffer_index]); } } @@ -538,6 +501,22 @@ bool HLERequestContext::CanWriteBuffer(std::size_t buffer_index) const { } } +void HLERequestContext::AddMoveInterface(SessionRequestHandlerPtr s) { + ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve( + Kernel::LimitableResource::SessionCountMax, 1)); + + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(nullptr, 0); + Kernel::KSession::Register(kernel, session); + + auto& server = manager.lock()->GetServerManager(); + auto next_manager = std::make_shared<Service::SessionRequestManager>(kernel, server); + next_manager->SetSessionHandler(std::move(s)); + server.RegisterSession(&session->GetServerSession(), next_manager); + + AddMoveObject(&session->GetClientSession()); +} + std::string HLERequestContext::Description() const { if (!command_header) { return "No command header available"; diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 40d86943e..c2e0e5e8c 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -41,6 +41,8 @@ class KernelCore; class KHandleTable; class KProcess; class KServerSession; +template <typename T> +class KScopedAutoObject; class KThread; } // namespace Kernel @@ -232,19 +234,19 @@ public: } [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { - return buffer_x_desciptors; + return buffer_x_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { - return buffer_a_desciptors; + return buffer_a_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { - return buffer_b_desciptors; + return buffer_b_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { - return buffer_c_desciptors; + return buffer_c_descriptors; } [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { @@ -337,6 +339,8 @@ public: outgoing_move_objects.emplace_back(object); } + void AddMoveInterface(SessionRequestHandlerPtr s); + void AddCopyObject(Kernel::KAutoObject* object) { outgoing_copy_objects.emplace_back(object); } @@ -406,11 +410,11 @@ private: std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; std::optional<IPC::DataPayloadHeader> data_payload_header; std::optional<IPC::DomainMessageHeader> domain_message_header; - std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; - std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; + std::vector<IPC::BufferDescriptorX> buffer_x_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors; + std::vector<IPC::BufferDescriptorC> buffer_c_descriptors; u32_le command{}; u64 pid{}; @@ -424,6 +428,9 @@ private: Kernel::KernelCore& kernel; Core::Memory::Memory& memory; + + mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_a{}; + mutable std::array<Common::ScratchBuffer<u8>, 3> read_buffer_data_x{}; }; } // namespace Service diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 77aa6d7d1..1f2cbcb61 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -6,12 +6,12 @@ #include "core/core.h" #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/result.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/jit/jit.h" #include "core/hle/service/jit/jit_code_memory.h" #include "core/hle/service/jit/jit_context.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/service.h" #include "core/memory.h" namespace Service::JIT { @@ -21,20 +21,24 @@ struct CodeRange { u64 size; }; +using Struct32 = std::array<u64, 4>; +static_assert(sizeof(Struct32) == 32, "Struct32 has wrong size"); + class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { public: explicit IJitEnvironment(Core::System& system_, - Kernel::KScopedAutoObject<Kernel::KProcess>&& process_, + Kernel::KScopedAutoObject<Kernel::KProcess> process_, CodeMemory&& user_rx_, CodeMemory&& user_ro_) : ServiceFramework{system_, "IJitEnvironment"}, process{std::move(process_)}, user_rx{std::move(user_rx_)}, user_ro{std::move(user_ro_)}, context{system_.ApplicationMemory()} { + // clang-format off static const FunctionInfo functions[] = { - {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, - {1, &IJitEnvironment::Control, "Control"}, - {1000, &IJitEnvironment::LoadPlugin, "LoadPlugin"}, - {1001, &IJitEnvironment::GetCodeAddress, "GetCodeAddress"}, + {0, C<&IJitEnvironment::GenerateCode>, "GenerateCode"}, + {1, C<&IJitEnvironment::Control>, "Control"}, + {1000, C<&IJitEnvironment::LoadPlugin>, "LoadPlugin"}, + {1001, C<&IJitEnvironment::GetCodeAddress>, "GetCodeAddress"}, }; // clang-format on @@ -50,28 +54,10 @@ public: configuration.sys_ro_memory = configuration.user_ro_memory; } - void GenerateCode(HLERequestContext& ctx) { - LOG_DEBUG(Service_JIT, "called"); - - struct InputParameters { - u32 data_size; - u64 command; - std::array<CodeRange, 2> ranges; - Struct32 data; - }; - - struct OutputParameters { - s32 return_value; - std::array<CodeRange, 2> ranges; - }; - - IPC::RequestParser rp{ctx}; - const auto parameters{rp.PopRaw<InputParameters>()}; - - // Optional input/output buffers - const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; - std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); - + Result GenerateCode(Out<s32> out_return_value, Out<CodeRange> out_range0, + Out<CodeRange> out_range1, OutBuffer<BufferAttr_HipcMapAlias> out_buffer, + u32 data_size, u64 command, CodeRange range0, CodeRange range1, + Struct32 data, InBuffer<BufferAttr_HipcMapAlias> buffer) { // Function call prototype: // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg, // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in, @@ -83,66 +69,36 @@ public: // other arguments are used to transfer state between the game and the plugin. const VAddr ret_ptr{context.AddHeap(0u)}; - const VAddr c0_in_ptr{context.AddHeap(parameters.ranges[0])}; - const VAddr c1_in_ptr{context.AddHeap(parameters.ranges[1])}; - const VAddr c0_out_ptr{context.AddHeap(ClearSize(parameters.ranges[0]))}; - const VAddr c1_out_ptr{context.AddHeap(ClearSize(parameters.ranges[1]))}; - - const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; - const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; - const VAddr data_ptr{context.AddHeap(parameters.data)}; + const VAddr c0_in_ptr{context.AddHeap(range0)}; + const VAddr c1_in_ptr{context.AddHeap(range1)}; + const VAddr c0_out_ptr{context.AddHeap(ClearSize(range0))}; + const VAddr c1_out_ptr{context.AddHeap(ClearSize(range1))}; + + const VAddr input_ptr{context.AddHeap(buffer.data(), buffer.size())}; + const VAddr output_ptr{context.AddHeap(out_buffer.data(), out_buffer.size())}; + const VAddr data_ptr{context.AddHeap(data)}; const VAddr configuration_ptr{context.AddHeap(configuration)}; // The callback does not directly return a value, it only writes to the output pointer context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr, - configuration_ptr, parameters.command, input_ptr, input_buffer.size(), - c0_in_ptr, c1_in_ptr, data_ptr, parameters.data_size, output_ptr, - output_buffer.size()); - - const s32 return_value{context.GetHeap<s32>(ret_ptr)}; - - if (return_value == 0) { - // The callback has written to the output executable code range, - // requiring an instruction cache invalidation - Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(), - configuration.user_rx_memory.offset, - configuration.user_rx_memory.size); - - // Write back to the IPC output buffer, if provided - if (ctx.CanWriteBuffer()) { - context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); - ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); - } - - const OutputParameters out{ - .return_value = return_value, - .ranges = - { - context.GetHeap<CodeRange>(c0_out_ptr), - context.GetHeap<CodeRange>(c1_out_ptr), - }, - }; - - IPC::ResponseBuilder rb{ctx, 8}; - rb.Push(ResultSuccess); - rb.PushRaw(out); - } else { - LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - } - }; + configuration_ptr, command, input_ptr, buffer.size(), c0_in_ptr, + c1_in_ptr, data_ptr, data_size, output_ptr, out_buffer.size()); - void Control(HLERequestContext& ctx) { - LOG_DEBUG(Service_JIT, "called"); + *out_return_value = context.GetHeap<s32>(ret_ptr); + *out_range0 = context.GetHeap<CodeRange>(c0_out_ptr); + *out_range1 = context.GetHeap<CodeRange>(c1_out_ptr); + context.GetHeap(output_ptr, out_buffer.data(), out_buffer.size()); - IPC::RequestParser rp{ctx}; - const auto command{rp.PopRaw<u64>()}; + if (*out_return_value != 0) { + LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed"); + R_THROW(ResultUnknown); + } - // Optional input/output buffers - const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()}; - std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); + R_SUCCEED(); + } + Result Control(Out<s32> out_return_value, InBuffer<BufferAttr_HipcMapAlias> in_data, + OutBuffer<BufferAttr_HipcMapAlias> out_data, u64 command) { // Function call prototype: // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size, // u8* output_buf, size_t output_size); @@ -152,53 +108,30 @@ public: const VAddr ret_ptr{context.AddHeap(0u)}; const VAddr configuration_ptr{context.AddHeap(configuration)}; - const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; - const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; + const VAddr input_ptr{context.AddHeap(in_data.data(), in_data.size())}; + const VAddr output_ptr{context.AddHeap(out_data.data(), out_data.size())}; const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, - command, input_ptr, input_buffer.size(), - output_ptr, output_buffer.size())}; - - const s32 return_value{context.GetHeap<s32>(ret_ptr)}; - - if (wrapper_value == 0 && return_value == 0) { - // Write back to the IPC output buffer, if provided - if (ctx.CanWriteBuffer()) { - context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); - ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(return_value); - } else { - LOG_WARNING(Service_JIT, "plugin Control callback failed"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - } - } - - void LoadPlugin(HLERequestContext& ctx) { - LOG_DEBUG(Service_JIT, "called"); + command, input_ptr, in_data.size(), output_ptr, + out_data.size())}; - IPC::RequestParser rp{ctx}; - const auto tmem_size{rp.PopRaw<u64>()}; - const auto tmem_handle{ctx.GetCopyHandle(0)}; - const auto nro_plugin{ctx.ReadBuffer(1)}; + *out_return_value = context.GetHeap<s32>(ret_ptr); + context.GetHeap(output_ptr, out_data.data(), out_data.size()); - if (tmem_size == 0) { - LOG_ERROR(Service_JIT, "attempted to load plugin with empty transfer memory"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + if (wrapper_value == 0 && *out_return_value == 0) { + R_SUCCEED(); } - auto tmem{ctx.GetObjectFromHandle<Kernel::KTransferMemory>(tmem_handle)}; - if (tmem.IsNull()) { - LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + LOG_WARNING(Service_JIT, "plugin Control callback failed"); + R_THROW(ResultUnknown); + } + + Result LoadPlugin(u64 tmem_size, InCopyHandle<Kernel::KTransferMemory>& tmem, + InBuffer<BufferAttr_HipcMapAlias> nrr, + InBuffer<BufferAttr_HipcMapAlias> nro) { + if (!tmem) { + LOG_ERROR(Service_JIT, "Invalid transfer memory handle!"); + R_THROW(ResultUnknown); } // Set up the configuration with the required TransferMemory address @@ -206,7 +139,7 @@ public: configuration.transfer_memory.size = tmem_size; // Gather up all the callbacks from the loaded plugin - auto symbols{Core::Symbols::GetSymbols(nro_plugin, true)}; + auto symbols{Core::Symbols::GetSymbols(nro, true)}; const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; callbacks.rtld_fini = GetSymbol("_fini"); @@ -223,16 +156,12 @@ public: if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || callbacks.OnPrepared == 0) { LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + R_THROW(ResultUnknown); } - if (!context.LoadNRO(nro_plugin)) { + if (!context.LoadNRO(nro)) { LOG_ERROR(Service_JIT, "failed to load plugin"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + R_THROW(ResultUnknown); } context.MapProcessMemory(configuration.sys_ro_memory.offset, @@ -252,9 +181,7 @@ public: const auto version{context.CallFunction(callbacks.GetVersion)}; if (version != 1) { LOG_ERROR(Service_JIT, "unknown plugin version {}", version); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + R_THROW(ResultUnknown); } // Function prototype: @@ -280,22 +207,19 @@ public: const auto configuration_ptr{context.AddHeap(configuration)}; context.CallFunction(callbacks.OnPrepared, configuration_ptr); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - void GetCodeAddress(HLERequestContext& ctx) { + Result GetCodeAddress(Out<u64> rx_offset, Out<u64> ro_offset) { LOG_DEBUG(Service_JIT, "called"); - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.Push(configuration.user_rx_memory.offset); - rb.Push(configuration.user_ro_memory.offset); + *rx_offset = configuration.user_rx_memory.offset; + *ro_offset = configuration.user_ro_memory.offset; + + R_SUCCEED(); } private: - using Struct32 = std::array<u8, 32>; - struct GuestCallbacks { VAddr rtld_fini; VAddr rtld_init; @@ -335,7 +259,7 @@ public: explicit JITU(Core::System& system_) : ServiceFramework{system_, "jit:u"} { // clang-format off static const FunctionInfo functions[] = { - {0, &JITU::CreateJitEnvironment, "CreateJitEnvironment"}, + {0, C<&JITU::CreateJitEnvironment>, "CreateJitEnvironment"}, }; // clang-format on @@ -343,76 +267,33 @@ public: } private: - void CreateJitEnvironment(HLERequestContext& ctx) { - LOG_DEBUG(Service_JIT, "called"); - - struct Parameters { - u64 rx_size; - u64 ro_size; - }; - - IPC::RequestParser rp{ctx}; - const auto parameters{rp.PopRaw<Parameters>()}; - const auto process_handle{ctx.GetCopyHandle(0)}; - const auto rx_mem_handle{ctx.GetCopyHandle(1)}; - const auto ro_mem_handle{ctx.GetCopyHandle(2)}; - - if (parameters.rx_size == 0 || parameters.ro_size == 0) { - LOG_ERROR(Service_JIT, "attempted to init with empty code regions"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; - } - - auto process{ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle)}; - if (process.IsNull()) { - LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + Result CreateJitEnvironment(Out<SharedPointer<IJitEnvironment>> out_jit_environment, + u64 rx_size, u64 ro_size, InCopyHandle<Kernel::KProcess>& process, + InCopyHandle<Kernel::KCodeMemory>& rx_mem, + InCopyHandle<Kernel::KCodeMemory>& ro_mem) { + if (!process) { + LOG_ERROR(Service_JIT, "process is null"); + R_THROW(ResultUnknown); } - - auto rx_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(rx_mem_handle)}; - if (rx_mem.IsNull()) { - LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + if (!rx_mem) { + LOG_ERROR(Service_JIT, "rx_mem is null"); + R_THROW(ResultUnknown); } - - auto ro_mem{ctx.GetObjectFromHandle<Kernel::KCodeMemory>(ro_mem_handle)}; - if (ro_mem.IsNull()) { - LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultUnknown); - return; + if (!ro_mem) { + LOG_ERROR(Service_JIT, "ro_mem is null"); + R_THROW(ResultUnknown); } CodeMemory rx, ro; - Result res; - - res = rx.Initialize(*process, *rx_mem, parameters.rx_size, - Kernel::Svc::MemoryPermission::ReadExecute, generate_random); - if (R_FAILED(res)) { - LOG_ERROR(Service_JIT, "rx_mem could not be mapped for handle=0x{:08X}", rx_mem_handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); - return; - } - res = ro.Initialize(*process, *ro_mem, parameters.ro_size, - Kernel::Svc::MemoryPermission::Read, generate_random); - if (R_FAILED(res)) { - LOG_ERROR(Service_JIT, "ro_mem could not be mapped for handle=0x{:08X}", ro_mem_handle); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); - return; - } + R_TRY(rx.Initialize(*process, *rx_mem, rx_size, Kernel::Svc::MemoryPermission::ReadExecute, + generate_random)); + R_TRY(ro.Initialize(*process, *ro_mem, ro_size, Kernel::Svc::MemoryPermission::Read, + generate_random)); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IJitEnvironment>(system, std::move(process), std::move(rx), - std::move(ro)); + *out_jit_environment = + std::make_shared<IJitEnvironment>(system, process.Get(), std::move(rx), std::move(ro)); + R_SUCCEED(); } private: diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp index f51e63564..f080f7ffa 100644 --- a/src/core/hle/service/kernel_helpers.cpp +++ b/src/core/hle/service/kernel_helpers.cpp @@ -65,6 +65,9 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) { } void ServiceContext::CloseEvent(Kernel::KEvent* event) { + if (!event) { + return; + } event->GetReadableEvent().Close(); event->Close(); } diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index c28eed926..b4d16fed5 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -4,15 +4,18 @@ #include <memory> #include "common/logging/log.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/mii/mii.h" #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/mii/mii_result.h" #include "core/hle/service/mii/types/char_info.h" +#include "core/hle/service/mii/types/raw_data.h" #include "core/hle/service/mii/types/store_data.h" #include "core/hle/service/mii/types/ver3_store_data.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/service.h" +#include "core/hle/service/set/system_settings_server.h" +#include "core/hle/service/sm/sm.h" namespace Service::Mii { @@ -24,549 +27,302 @@ public: is_system_} { // clang-format off static const FunctionInfo functions[] = { - {0, &IDatabaseService::IsUpdated, "IsUpdated"}, - {1, &IDatabaseService::IsFullDatabase, "IsFullDatabase"}, - {2, &IDatabaseService::GetCount, "GetCount"}, - {3, &IDatabaseService::Get, "Get"}, - {4, &IDatabaseService::Get1, "Get1"}, - {5, &IDatabaseService::UpdateLatest, "UpdateLatest"}, - {6, &IDatabaseService::BuildRandom, "BuildRandom"}, - {7, &IDatabaseService::BuildDefault, "BuildDefault"}, - {8, &IDatabaseService::Get2, "Get2"}, - {9, &IDatabaseService::Get3, "Get3"}, - {10, &IDatabaseService::UpdateLatest1, "UpdateLatest1"}, - {11, &IDatabaseService::FindIndex, "FindIndex"}, - {12, &IDatabaseService::Move, "Move"}, - {13, &IDatabaseService::AddOrReplace, "AddOrReplace"}, - {14, &IDatabaseService::Delete, "Delete"}, - {15, &IDatabaseService::DestroyFile, "DestroyFile"}, - {16, &IDatabaseService::DeleteFile, "DeleteFile"}, - {17, &IDatabaseService::Format, "Format"}, + {0, D<&IDatabaseService::IsUpdated>, "IsUpdated"}, + {1, D<&IDatabaseService::IsFullDatabase>, "IsFullDatabase"}, + {2, D<&IDatabaseService::GetCount>, "GetCount"}, + {3, D<&IDatabaseService::Get>, "Get"}, + {4, D<&IDatabaseService::Get1>, "Get1"}, + {5, D<&IDatabaseService::UpdateLatest>, "UpdateLatest"}, + {6, D<&IDatabaseService::BuildRandom>, "BuildRandom"}, + {7, D<&IDatabaseService::BuildDefault>, "BuildDefault"}, + {8, D<&IDatabaseService::Get2>, "Get2"}, + {9, D<&IDatabaseService::Get3>, "Get3"}, + {10, D<&IDatabaseService::UpdateLatest1>, "UpdateLatest1"}, + {11, D<&IDatabaseService::FindIndex>, "FindIndex"}, + {12, D<&IDatabaseService::Move>, "Move"}, + {13, D<&IDatabaseService::AddOrReplace>, "AddOrReplace"}, + {14, D<&IDatabaseService::Delete>, "Delete"}, + {15, D<&IDatabaseService::DestroyFile>, "DestroyFile"}, + {16, D<&IDatabaseService::DeleteFile>, "DeleteFile"}, + {17, D<&IDatabaseService::Format>, "Format"}, {18, nullptr, "Import"}, {19, nullptr, "Export"}, - {20, &IDatabaseService::IsBrokenDatabaseWithClearFlag, "IsBrokenDatabaseWithClearFlag"}, - {21, &IDatabaseService::GetIndex, "GetIndex"}, - {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, - {23, &IDatabaseService::Convert, "Convert"}, - {24, &IDatabaseService::ConvertCoreDataToCharInfo, "ConvertCoreDataToCharInfo"}, - {25, &IDatabaseService::ConvertCharInfoToCoreData, "ConvertCharInfoToCoreData"}, - {26, &IDatabaseService::Append, "Append"}, + {20, D<&IDatabaseService::IsBrokenDatabaseWithClearFlag>, "IsBrokenDatabaseWithClearFlag"}, + {21, D<&IDatabaseService::GetIndex>, "GetIndex"}, + {22, D<&IDatabaseService::SetInterfaceVersion>, "SetInterfaceVersion"}, + {23, D<&IDatabaseService::Convert>, "Convert"}, + {24, D<&IDatabaseService::ConvertCoreDataToCharInfo>, "ConvertCoreDataToCharInfo"}, + {25, D<&IDatabaseService::ConvertCharInfoToCoreData>, "ConvertCharInfoToCoreData"}, + {26, D<&IDatabaseService::Append>, "Append"}, }; // clang-format on RegisterHandlers(functions); + m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>( + "set:sys", true); manager->Initialize(metadata); } private: - void IsUpdated(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - + Result IsUpdated(Out<bool> out_is_updated, SourceFlag source_flag) { LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); - const bool is_updated = manager->IsUpdated(metadata, source_flag); + *out_is_updated = manager->IsUpdated(metadata, source_flag); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(is_updated); + R_SUCCEED(); } - void IsFullDatabase(HLERequestContext& ctx) { + Result IsFullDatabase(Out<bool> out_is_full_database) { LOG_DEBUG(Service_Mii, "called"); - const bool is_full_database = manager->IsFullDatabase(); + *out_is_full_database = manager->IsFullDatabase(); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(is_full_database); + R_SUCCEED(); } - void GetCount(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - - const u32 mii_count = manager->GetCount(metadata, source_flag); + Result GetCount(Out<u32> out_mii_count, SourceFlag source_flag) { + *out_mii_count = manager->GetCount(metadata, source_flag); - LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count); + LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, + *out_mii_count); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(mii_count); + R_SUCCEED(); } - void Get(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()}; - - u32 mii_count{}; - std::vector<CharInfoElement> char_info_elements(output_size); - const auto result = manager->Get(metadata, char_info_elements, mii_count, source_flag); - - if (mii_count != 0) { - ctx.WriteBuffer(char_info_elements); - } + Result Get(Out<u32> out_mii_count, SourceFlag source_flag, + OutArray<CharInfoElement, BufferAttr_HipcMapAlias> char_info_element_buffer) { + const auto result = + manager->Get(metadata, char_info_element_buffer, *out_mii_count, source_flag); - LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, - output_size, mii_count); + LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, + *out_mii_count); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(mii_count); + R_RETURN(result); } - void Get1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()}; + Result Get1(Out<u32> out_mii_count, SourceFlag source_flag, + OutArray<CharInfo, BufferAttr_HipcMapAlias> char_info_buffer) { + const auto result = manager->Get(metadata, char_info_buffer, *out_mii_count, source_flag); - u32 mii_count{}; - std::vector<CharInfo> char_info(output_size); - const auto result = manager->Get(metadata, char_info, mii_count, source_flag); + LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, + *out_mii_count); - if (mii_count != 0) { - ctx.WriteBuffer(char_info); - } - - LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, - output_size, mii_count); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(mii_count); + R_RETURN(result); } - void UpdateLatest(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto char_info{rp.PopRaw<CharInfo>()}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - + Result UpdateLatest(Out<CharInfo> out_char_info, CharInfo& char_info, SourceFlag source_flag) { LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); - CharInfo new_char_info{}; - const auto result = manager->UpdateLatest(metadata, new_char_info, char_info, source_flag); - if (result.IsFailure()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw(new_char_info); + R_RETURN(manager->UpdateLatest(metadata, *out_char_info, char_info, source_flag)); } - void BuildRandom(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto age{rp.PopRaw<Age>()}; - const auto gender{rp.PopRaw<Gender>()}; - const auto race{rp.PopRaw<Race>()}; - + Result BuildRandom(Out<CharInfo> out_char_info, Age age, Gender gender, Race race) { LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race); - if (age > Age::All) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultInvalidArgument); - return; - } - - if (gender > Gender::All) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultInvalidArgument); - return; - } - - if (race > Race::All) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultInvalidArgument); - return; - } - - CharInfo char_info{}; - manager->BuildRandom(char_info, age, gender, race); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw(char_info); - } + R_UNLESS(age <= Age::All, ResultInvalidArgument); + R_UNLESS(gender <= Gender::All, ResultInvalidArgument); + R_UNLESS(race <= Race::All, ResultInvalidArgument); - void BuildDefault(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto index{rp.Pop<u32>()}; + manager->BuildRandom(*out_char_info, age, gender, race); - LOG_DEBUG(Service_Mii, "called with index={}", index); + R_SUCCEED(); + } - if (index > 5) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultInvalidArgument); - return; - } + Result BuildDefault(Out<CharInfo> out_char_info, s32 index) { + LOG_DEBUG(Service_Mii, "called with index={}", index); + R_UNLESS(index < static_cast<s32>(RawData::DefaultMii.size()), ResultInvalidArgument); - CharInfo char_info{}; - manager->BuildDefault(char_info, index); + manager->BuildDefault(*out_char_info, index); - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw(char_info); + R_SUCCEED(); } - void Get2(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - const auto output_size{ctx.GetWriteBufferNumElements<StoreDataElement>()}; + Result Get2(Out<u32> out_mii_count, SourceFlag source_flag, + OutArray<StoreDataElement, BufferAttr_HipcMapAlias> store_data_element_buffer) { + const auto result = + manager->Get(metadata, store_data_element_buffer, *out_mii_count, source_flag); - u32 mii_count{}; - std::vector<StoreDataElement> store_data_elements(output_size); - const auto result = manager->Get(metadata, store_data_elements, mii_count, source_flag); + LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, + *out_mii_count); - if (mii_count != 0) { - ctx.WriteBuffer(store_data_elements); - } - - LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, - output_size, mii_count); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(mii_count); + R_RETURN(result); } - void Get3(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - const auto output_size{ctx.GetWriteBufferNumElements<StoreData>()}; - - u32 mii_count{}; - std::vector<StoreData> store_data(output_size); - const auto result = manager->Get(metadata, store_data, mii_count, source_flag); + Result Get3(Out<u32> out_mii_count, SourceFlag source_flag, + OutArray<StoreData, BufferAttr_HipcMapAlias> store_data_buffer) { + const auto result = manager->Get(metadata, store_data_buffer, *out_mii_count, source_flag); - if (mii_count != 0) { - ctx.WriteBuffer(store_data); - } + LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, + *out_mii_count); - LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, - output_size, mii_count); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(mii_count); + R_RETURN(result); } - void UpdateLatest1(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto store_data{rp.PopRaw<StoreData>()}; - const auto source_flag{rp.PopRaw<SourceFlag>()}; - + Result UpdateLatest1(Out<StoreData> out_store_data, StoreData& store_data, + SourceFlag source_flag) { LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); + R_UNLESS(is_system, ResultPermissionDenied); - Result result = ResultSuccess; - if (!is_system) { - result = ResultPermissionDenied; - } - - StoreData new_store_data{}; - if (result.IsSuccess()) { - result = manager->UpdateLatest(metadata, new_store_data, store_data, source_flag); - } - - if (result.IsFailure()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(StoreData) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw<StoreData>(new_store_data); + R_RETURN(manager->UpdateLatest(metadata, *out_store_data, store_data, source_flag)); } - void FindIndex(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto create_id{rp.PopRaw<Common::UUID>()}; - const auto is_special{rp.PopRaw<bool>()}; - + Result FindIndex(Out<s32> out_index, Common::UUID create_id, bool is_special) { LOG_INFO(Service_Mii, "called with create_id={}, is_special={}", create_id.FormattedString(), is_special); - const s32 index = manager->FindIndex(create_id, is_special); + *out_index = manager->FindIndex(create_id, is_special); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(index); + R_SUCCEED(); } - void Move(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto create_id{rp.PopRaw<Common::UUID>()}; - const auto new_index{rp.PopRaw<s32>()}; - + Result Move(Common::UUID create_id, s32 new_index) { LOG_INFO(Service_Mii, "called with create_id={}, new_index={}", create_id.FormattedString(), new_index); + R_UNLESS(is_system, ResultPermissionDenied); - Result result = ResultSuccess; - if (!is_system) { - result = ResultPermissionDenied; - } + const u32 count = manager->GetCount(metadata, SourceFlag::Database); - if (result.IsSuccess()) { - const u32 count = manager->GetCount(metadata, SourceFlag::Database); - if (new_index < 0 || new_index >= static_cast<s32>(count)) { - result = ResultInvalidArgument; - } - } + R_UNLESS(new_index >= 0 && new_index < static_cast<s32>(count), ResultInvalidArgument); - if (result.IsSuccess()) { - result = manager->Move(metadata, new_index, create_id); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->Move(metadata, new_index, create_id)); } - void AddOrReplace(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto store_data{rp.PopRaw<StoreData>()}; - + Result AddOrReplace(StoreData& store_data) { LOG_INFO(Service_Mii, "called"); + R_UNLESS(is_system, ResultPermissionDenied); - Result result = ResultSuccess; - - if (!is_system) { - result = ResultPermissionDenied; - } + const auto result = manager->AddOrReplace(metadata, store_data); - if (result.IsSuccess()) { - result = manager->AddOrReplace(metadata, store_data); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(result); } - void Delete(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto create_id{rp.PopRaw<Common::UUID>()}; - + Result Delete(Common::UUID create_id) { LOG_INFO(Service_Mii, "called, create_id={}", create_id.FormattedString()); + R_UNLESS(is_system, ResultPermissionDenied); - Result result = ResultSuccess; - - if (!is_system) { - result = ResultPermissionDenied; - } - - if (result.IsSuccess()) { - result = manager->Delete(metadata, create_id); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->Delete(metadata, create_id)); } - void DestroyFile(HLERequestContext& ctx) { - // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - const bool is_db_test_mode_enabled = false; + Result DestroyFile() { + bool is_db_test_mode_enabled{}; + m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled"); LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); + R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly); - Result result = ResultSuccess; - - if (!is_db_test_mode_enabled) { - result = ResultTestModeOnly; - } - - if (result.IsSuccess()) { - result = manager->DestroyFile(metadata); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->DestroyFile(metadata)); } - void DeleteFile(HLERequestContext& ctx) { - // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - const bool is_db_test_mode_enabled = false; + Result DeleteFile() { + bool is_db_test_mode_enabled{}; + m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled"); LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); + R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly); - Result result = ResultSuccess; - - if (!is_db_test_mode_enabled) { - result = ResultTestModeOnly; - } - - if (result.IsSuccess()) { - result = manager->DeleteFile(); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->DeleteFile()); } - void Format(HLERequestContext& ctx) { - // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - const bool is_db_test_mode_enabled = false; + Result Format() { + bool is_db_test_mode_enabled{}; + m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled"); LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); + R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly); - Result result = ResultSuccess; - - if (!is_db_test_mode_enabled) { - result = ResultTestModeOnly; - } - - if (result.IsSuccess()) { - result = manager->Format(metadata); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->Format(metadata)); } - void IsBrokenDatabaseWithClearFlag(HLERequestContext& ctx) { + Result IsBrokenDatabaseWithClearFlag(Out<bool> out_is_broken_with_clear_flag) { LOG_DEBUG(Service_Mii, "called"); + R_UNLESS(is_system, ResultPermissionDenied); - bool is_broken_with_clear_flag = false; - Result result = ResultSuccess; + *out_is_broken_with_clear_flag = manager->IsBrokenWithClearFlag(metadata); - if (!is_system) { - result = ResultPermissionDenied; - } - - if (result.IsSuccess()) { - is_broken_with_clear_flag = manager->IsBrokenWithClearFlag(metadata); - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push<u8>(is_broken_with_clear_flag); + R_SUCCEED(); } - void GetIndex(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto info{rp.PopRaw<CharInfo>()}; - + Result GetIndex(Out<s32> out_index, CharInfo& char_info) { LOG_DEBUG(Service_Mii, "called"); - s32 index{}; - const auto result = manager->GetIndex(metadata, info, index); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); - rb.Push(index); + R_RETURN(manager->GetIndex(metadata, char_info, *out_index)); } - void SetInterfaceVersion(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto interface_version{rp.PopRaw<u32>()}; - + Result SetInterfaceVersion(u32 interface_version) { LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version); manager->SetInterfaceVersion(metadata, interface_version); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - void Convert(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto mii_v3{rp.PopRaw<Ver3StoreData>()}; - + Result Convert(Out<CharInfo> out_char_info, Ver3StoreData& mii_v3) { LOG_INFO(Service_Mii, "called"); - CharInfo char_info{}; - const auto result = manager->ConvertV3ToCharInfo(char_info, mii_v3); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; - rb.Push(result); - rb.PushRaw<CharInfo>(char_info); + R_RETURN(manager->ConvertV3ToCharInfo(*out_char_info, mii_v3)); } - void ConvertCoreDataToCharInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto core_data{rp.PopRaw<CoreData>()}; - + Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, CoreData& core_data) { LOG_INFO(Service_Mii, "called"); - CharInfo char_info{}; - const auto result = manager->ConvertCoreDataToCharInfo(char_info, core_data); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; - rb.Push(result); - rb.PushRaw<CharInfo>(char_info); + R_RETURN(manager->ConvertCoreDataToCharInfo(*out_char_info, core_data)); } - void ConvertCharInfoToCoreData(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto char_info{rp.PopRaw<CharInfo>()}; - + Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, CharInfo& char_info) { LOG_INFO(Service_Mii, "called"); - CoreData core_data{}; - const auto result = manager->ConvertCharInfoToCoreData(core_data, char_info); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)}; - rb.Push(result); - rb.PushRaw<CoreData>(core_data); + R_RETURN(manager->ConvertCharInfoToCoreData(*out_core_data, char_info)); } - void Append(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto char_info{rp.PopRaw<CharInfo>()}; - + Result Append(CharInfo& char_info) { LOG_INFO(Service_Mii, "called"); - const auto result = manager->Append(metadata, char_info); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + R_RETURN(manager->Append(metadata, char_info)); } std::shared_ptr<MiiManager> manager = nullptr; DatabaseSessionMetadata metadata{}; bool is_system{}; + + std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; }; -MiiDBModule::MiiDBModule(Core::System& system_, const char* name_, - std::shared_ptr<MiiManager> mii_manager, bool is_system_) +IStaticService::IStaticService(Core::System& system_, const char* name_, + std::shared_ptr<MiiManager> mii_manager, bool is_system_) : ServiceFramework{system_, name_}, manager{mii_manager}, is_system{is_system_} { // clang-format off static const FunctionInfo functions[] = { - {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, + {0, D<&IStaticService::GetDatabaseService>, "GetDatabaseService"}, }; // clang-format on RegisterHandlers(functions); - - if (manager == nullptr) { - manager = std::make_shared<MiiManager>(); - } } -MiiDBModule::~MiiDBModule() = default; - -void MiiDBModule::GetDatabaseService(HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IDatabaseService>(system, manager, is_system); +IStaticService::~IStaticService() = default; +Result IStaticService::GetDatabaseService( + Out<SharedPointer<IDatabaseService>> out_database_service) { LOG_DEBUG(Service_Mii, "called"); + + *out_database_service = std::make_shared<IDatabaseService>(system, manager, is_system); + + R_SUCCEED(); } -std::shared_ptr<MiiManager> MiiDBModule::GetMiiManager() { +std::shared_ptr<MiiManager> IStaticService::GetMiiManager() { return manager; } -class MiiImg final : public ServiceFramework<MiiImg> { +class IImageDatabaseService final : public ServiceFramework<IImageDatabaseService> { public: - explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} { + explicit IImageDatabaseService(Core::System& system_) : ServiceFramework{system_, "miiimg"} { // clang-format off static const FunctionInfo functions[] = { - {0, &MiiImg::Initialize, "Initialize"}, + {0, D<&IImageDatabaseService::Initialize>, "Initialize"}, {10, nullptr, "Reload"}, - {11, &MiiImg::GetCount, "GetCount"}, + {11, D<&IImageDatabaseService::GetCount>, "GetCount"}, {12, nullptr, "IsEmpty"}, {13, nullptr, "IsFull"}, {14, nullptr, "GetAttribute"}, @@ -585,31 +341,30 @@ public: } private: - void Initialize(HLERequestContext& ctx) { + Result Initialize() { LOG_INFO(Service_Mii, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + R_SUCCEED(); } - void GetCount(HLERequestContext& ctx) { + Result GetCount(Out<u32> out_count) { LOG_DEBUG(Service_Mii, "called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); + *out_count = 0; + + R_SUCCEED(); } }; void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - std::shared_ptr<MiiManager> manager = nullptr; + std::shared_ptr<MiiManager> manager = std::make_shared<MiiManager>(); server_manager->RegisterNamedService( - "mii:e", std::make_shared<MiiDBModule>(system, "mii:e", manager, true)); + "mii:e", std::make_shared<IStaticService>(system, "mii:e", manager, true)); server_manager->RegisterNamedService( - "mii:u", std::make_shared<MiiDBModule>(system, "mii:u", manager, false)); - server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system)); + "mii:u", std::make_shared<IStaticService>(system, "mii:u", manager, false)); + server_manager->RegisterNamedService("miiimg", std::make_shared<IImageDatabaseService>(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h index 9aa4426f6..8683ac1a5 100644 --- a/src/core/hle/service/mii/mii.h +++ b/src/core/hle/service/mii/mii.h @@ -3,7 +3,7 @@ #pragma once -#include "core/hle/service/service.h" +#include "core/hle/service/cmif_types.h" namespace Core { class System; @@ -11,19 +11,20 @@ class System; namespace Service::Mii { class MiiManager; +class IDatabaseService; -class MiiDBModule final : public ServiceFramework<MiiDBModule> { +class IStaticService final : public ServiceFramework<IStaticService> { public: - explicit MiiDBModule(Core::System& system_, const char* name_, - std::shared_ptr<MiiManager> mii_manager, bool is_system_); - ~MiiDBModule() override; + explicit IStaticService(Core::System& system_, const char* name_, + std::shared_ptr<MiiManager> mii_manager, bool is_system_); + ~IStaticService() override; std::shared_ptr<MiiManager> GetMiiManager(); private: - void GetDatabaseService(HLERequestContext& ctx); + Result GetDatabaseService(Out<SharedPointer<IDatabaseService>> out_database_service); - std::shared_ptr<MiiManager> manager = nullptr; + std::shared_ptr<MiiManager> manager{nullptr}; bool is_system{}; }; diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp index 9556e9193..4274a92c9 100644 --- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp +++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp @@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto { bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { const auto& amiibo_data = ntag_file.user_memory; LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); - LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); + LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container); LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); @@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { if (ntag_file.static_lock != 0xE00F) { return false; } - if (ntag_file.compability_container != 0xEEFF10F1U) { + if (ntag_file.compatibility_container != 0xEEFF10F1U) { return false; } if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { @@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; encoded_data.internal_number = nfc_data.internal_number; encoded_data.static_lock = nfc_data.static_lock; - encoded_data.compability_container = nfc_data.compability_container; + encoded_data.compatibility_container = nfc_data.compatibility_container; encoded_data.hmac_data = nfc_data.user_memory.hmac_data; encoded_data.constant_value = nfc_data.user_memory.constant_value; encoded_data.write_counter = nfc_data.user_memory.write_counter; @@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; nfc_data.internal_number = encoded_data.internal_number; nfc_data.static_lock = encoded_data.static_lock; - nfc_data.compability_container = encoded_data.compability_container; + nfc_data.compatibility_container = encoded_data.compatibility_container; nfc_data.user_memory.hmac_data = encoded_data.hmac_data; nfc_data.user_memory.constant_value = encoded_data.constant_value; nfc_data.user_memory.write_counter = encoded_data.write_counter; @@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou out_data.uid_crc_check2 = in_data.uid_crc_check2; out_data.internal_number = in_data.internal_number; out_data.static_lock = in_data.static_lock; - out_data.compability_container = in_data.compability_container; + out_data.compatibility_container = in_data.compatibility_container; out_data.constant_value = in_data.constant_value; out_data.write_counter = in_data.write_counter; diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index f97e5b44c..1e2d2d212 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/service/glue/time/static.h" +#include "core/hle/service/psc/time/steady_clock.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used @@ -22,9 +24,6 @@ #include "common/string_util.h" #include "common/tiny_mt.h" #include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/mii/mii_manager.h" @@ -32,7 +31,11 @@ #include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/mifare_result.h" #include "core/hle/service/nfc/nfc_result.h" -#include "core/hle/service/time/time_manager.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/frontend/emulated_controller.h" +#include "hid_core/hid_core.h" +#include "hid_core/hid_types.h" namespace Service::NFC { NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, @@ -75,7 +78,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { return; } - if (!is_initalized) { + if (!is_initialized) { return; } @@ -207,7 +210,7 @@ void NfcDevice::Initialize() { return; } - is_initalized = npad_device->AddNfcHandle(); + is_initialized = npad_device->AddNfcHandle(); } void NfcDevice::Finalize() { @@ -226,7 +229,7 @@ void NfcDevice::Finalize() { } device_state = DeviceState::Unavailable; - is_initalized = false; + is_initialized = false; } Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { @@ -393,8 +396,7 @@ Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> paramet return result; } -Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, - std::span<const u8> command_data, +Result NfcDevice::SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data, std::span<u8> out_data) { // Not implemented return ResultSuccess; @@ -441,7 +443,10 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target device_state = DeviceState::TagMounted; mount_target = mount_target_; - if (!is_corrupted && mount_target != NFP::MountTarget::Rom) { + const bool create_backup = + mount_target == NFP::MountTarget::All || mount_target == NFP::MountTarget::Ram || + (mount_target == NFP::MountTarget::Rom && HasBackup(encrypted_tag_data.uuid).IsError()); + if (!is_corrupted && create_backup) { std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); WriteBackupData(encrypted_tag_data.uuid, data); @@ -1396,27 +1401,41 @@ void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings, } NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const { - const auto& time_zone_manager = - system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager(); - Time::TimeZone::CalendarInfo calendar_info{}; + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; + static_service->GetTimeZoneService(timezone_service); + + Service::PSC::Time::CalendarTime calendar_time{}; + Service::PSC::Time::CalendarAdditionalInfo additional_info{}; + NFP::AmiiboDate amiibo_date{}; amiibo_date.SetYear(2000); amiibo_date.SetMonth(1); amiibo_date.SetDay(1); - if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) { - amiibo_date.SetYear(calendar_info.time.year); - amiibo_date.SetMonth(calendar_info.time.month); - amiibo_date.SetDay(calendar_info.time.day); + if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) == + ResultSuccess) { + amiibo_date.SetYear(calendar_time.year); + amiibo_date.SetMonth(calendar_time.month); + amiibo_date.SetDay(calendar_time.day); } return amiibo_date; } -u64 NfcDevice::GetCurrentPosixTime() const { - auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; - return standard_steady_clock.GetCurrentTimePoint(system).time_point; +s64 NfcDevice::GetCurrentPosixTime() const { + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; + static_service->GetStandardSteadyClock(steady_clock); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); + return time_point.time_point; } u64 NfcDevice::RemoveVersionByte(u64 application_id) const { diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index d8efe25ec..d59202d18 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h @@ -11,7 +11,6 @@ #include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/service.h" -#include "core/hle/service/time/clock_types.h" namespace Kernel { class KEvent; @@ -49,8 +48,8 @@ public: Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters); - Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout, - std::span<const u8> command_data, std::span<u8> out_data); + Result SendCommandByPassThrough(const s64& timeout, std::span<const u8> command_data, + std::span<u8> out_data); Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target); Result Unmount(); @@ -108,7 +107,7 @@ private: NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const; void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const; NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const; - u64 GetCurrentPosixTime() const; + s64 GetCurrentPosixTime() const; u64 RemoveVersionByte(u64 application_id) const; void UpdateSettingsCrc(); void UpdateRegisterInfoCrc(); @@ -126,7 +125,7 @@ private: Kernel::KEvent* deactivate_event = nullptr; Kernel::KEvent* availability_change_event = nullptr; - bool is_initalized{}; + bool is_initialized{}; NfcProtocol allowed_protocols{}; DeviceState device_state{DeviceState::Unavailable}; diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index ad534177d..b60699c45 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp @@ -5,15 +5,17 @@ #include "common/logging/log.h" #include "core/core.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" -#include "core/hle/service/hid/hid_util.h" +#include "core/hle/service/glue/time/static.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device_manager.h" #include "core/hle/service/nfc/nfc_result.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/time_manager.h" +#include "core/hle/service/psc/time/steady_clock.h" +#include "core/hle/service/service.h" +#include "core/hle/service/sm/sm.h" +#include "hid_core/hid_types.h" +#include "hid_core/hid_util.h" namespace Service::NFC { @@ -82,11 +84,19 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max continue; } if (skip_fatal_errors) { - constexpr u64 MinimumRecoveryTime = 60; - auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; - const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point - - time_since_last_error; + constexpr s64 MinimumRecoveryTime = 60; + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", + true); + + std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; + static_service->GetStandardSteadyClock(steady_clock); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); + + const s64 elapsed_time = time_point.time_point - time_since_last_error; if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { continue; } @@ -250,8 +260,7 @@ Result DeviceManager::WriteMifare(u64 device_handle, return result; } -Result DeviceManager::SendCommandByPassThrough(u64 device_handle, - const Time::Clock::TimeSpanType& timeout, +Result DeviceManager::SendCommandByPassThrough(u64 device_handle, const s64& timeout, std::span<const u8> command_data, std::span<u8> out_data) { std::scoped_lock lock{mutex}; @@ -741,8 +750,16 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || operation_result == ResultUnknown115) { - auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; - time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point; + auto static_service = + system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); + + std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; + static_service->GetStandardSteadyClock(steady_clock); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); + + time_since_last_error = time_point.time_point; } return operation_result; diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index c9f038e32..c56a2fbda 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h @@ -8,13 +8,12 @@ #include <optional> #include <span> -#include "core/hid/hid_types.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nfc/mifare_types.h" #include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/service.h" -#include "core/hle/service/time/clock_types.h" +#include "hid_core/hid_types.h" namespace Service::NFC { class NfcDevice; @@ -42,7 +41,7 @@ public: std::span<MifareReadBlockData> read_data); Result WriteMifare(u64 device_handle, std::span<const MifareWriteBlockParameter> write_parameters); - Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout, + Result SendCommandByPassThrough(u64 device_handle, const s64& timeout, std::span<const u8> command_data, std::span<u8> out_data); // Nfp device manager @@ -92,7 +91,7 @@ private: const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; bool is_initialized = false; - u64 time_since_last_error = 0; + s64 time_since_last_error = 0; mutable std::mutex mutex; std::array<std::shared_ptr<NfcDevice>, 10> devices{}; diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index 179c7ba2c..3e2c7deab 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp @@ -3,7 +3,6 @@ #include "common/logging/log.h" #include "core/core.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nfc/common/device.h" @@ -14,7 +13,7 @@ #include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_types.h" #include "core/hle/service/nfp/nfp_result.h" -#include "core/hle/service/time/clock_types.h" +#include "hid_core/hid_types.h" namespace Service::NFC { @@ -261,10 +260,10 @@ void NfcInterface::WriteMifare(HLERequestContext& ctx) { void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop<u64>()}; - const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; + const auto timeout{rp.PopRaw<s64>()}; const auto command_data{ctx.ReadBuffer()}; LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", - device_handle, timeout.ToSeconds(), command_data.size()); + device_handle, timeout, command_data.size()); std::vector<u8> out_data(1); auto result = @@ -302,7 +301,7 @@ Result NfcInterface::TranslateResultToServiceError(Result result) const { return result; } - if (result.module != ErrorModule::NFC) { + if (result.GetModule() != ErrorModule::NFC) { return result; } diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp index 34ef9d82d..5ba6d1742 100644 --- a/src/core/hle/service/nfp/nfp_interface.cpp +++ b/src/core/hle/service/nfp/nfp_interface.cpp @@ -3,7 +3,6 @@ #include "common/logging/log.h" #include "core/core.h" -#include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nfc/common/device.h" @@ -12,6 +11,7 @@ #include "core/hle/service/nfp/nfp_interface.h" #include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_types.h" +#include "hid_core/hid_types.h" namespace Service::NFP { diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index f96d21220..2505eb551 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si struct NTAG215File { u8 uid_crc_check2; u8 internal_number; - u16 static_lock; // Set defined pages as read only - u32 compability_container; // Defines available memory - HashData hmac_data; // Hash - u8 constant_value; // Must be A5 - u16_be write_counter; // Number of times the amiibo has been written? - u8 amiibo_version; // Amiibo file version + u16 static_lock; // Set defined pages as read only + u32 compatibility_container; // Defines available memory + HashData hmac_data; // Hash + u8 constant_value; // Must be A5 + u16_be write_counter; // Number of times the amiibo has been written? + u8 amiibo_version; // Amiibo file version AmiiboSettings settings; Service::Mii::Ver3StoreData owner_mii; // Mii data u64_be application_id; // Game id @@ -278,7 +278,7 @@ struct EncryptedNTAG215File { u8 uuid_crc_check2; u8 internal_number; u16 static_lock; // Set defined pages as read only - u32 compability_container; // Defines available memory + u32 compatibility_container; // Defines available memory EncryptedAmiiboFile user_memory; // Writable data u32 dynamic_lock; // Dynamic lock u32 CFG0; // Defines memory protected by password diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index 036a1e9b7..d187be935 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/ns/language.h" -#include "core/hle/service/set/set.h" +#include "core/hle/service/set/settings_server.h" namespace Service::NS { @@ -415,4 +415,4 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage return std::nullopt; } } -} // namespace Service::NS
\ No newline at end of file +} // namespace Service::NS diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h index ab6b71029..dad9934f2 100644 --- a/src/core/hle/service/ns/language.h +++ b/src/core/hle/service/ns/language.h @@ -5,10 +5,7 @@ #include <optional> #include "common/common_types.h" - -namespace Service::Set { -enum class LanguageCode : u64; -} +#include "core/hle/service/set/system_settings_server.h" namespace Service::NS { /// This is nn::ns::detail::ApplicationLanguage diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index f9e0e272d..2258ee609 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -6,7 +6,7 @@ #include "core/core.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" -#include "core/file_sys/vfs.h" +#include "core/file_sys/vfs/vfs.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/glue/glue_manager.h" #include "core/hle/service/ipc_helpers.h" @@ -16,7 +16,7 @@ #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/pdm_qry.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/set/set.h" +#include "core/hle/service/set/settings_server.h" namespace Service::NS { diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp index 37ca24f5d..dc1b4d5be 100644 --- a/src/core/hle/service/nvdrv/core/container.cpp +++ b/src/core/hle/service/nvdrv/core/container.cpp @@ -2,27 +2,136 @@ // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later +#include <atomic> +#include <deque> +#include <mutex> + +#include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/heap_mapper.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "core/memory.h" #include "video_core/host1x/host1x.h" namespace Service::Nvidia::NvCore { +Session::Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_) + : id{id_}, process{process_}, asid{asid_}, has_preallocated_area{}, mapper{}, is_active{} {} + +Session::~Session() = default; + struct ContainerImpl { - explicit ContainerImpl(Tegra::Host1x::Host1x& host1x_) - : file{host1x_}, manager{host1x_}, device_file_data{} {} + explicit ContainerImpl(Container& core, Tegra::Host1x::Host1x& host1x_) + : host1x{host1x_}, file{core, host1x_}, manager{host1x_}, device_file_data{} {} + Tegra::Host1x::Host1x& host1x; NvMap file; SyncpointManager manager; Container::Host1xDeviceFileData device_file_data; + std::deque<Session> sessions; + size_t new_ids{}; + std::deque<size_t> id_pool; + std::mutex session_guard; }; Container::Container(Tegra::Host1x::Host1x& host1x_) { - impl = std::make_unique<ContainerImpl>(host1x_); + impl = std::make_unique<ContainerImpl>(*this, host1x_); } Container::~Container() = default; +SessionId Container::OpenSession(Kernel::KProcess* process) { + using namespace Common::Literals; + + std::scoped_lock lk(impl->session_guard); + for (auto& session : impl->sessions) { + if (!session.is_active) { + continue; + } + if (session.process == process) { + return session.id; + } + } + size_t new_id{}; + auto* memory_interface = &process->GetMemory(); + auto& smmu = impl->host1x.MemoryManager(); + auto asid = smmu.RegisterProcess(memory_interface); + if (!impl->id_pool.empty()) { + new_id = impl->id_pool.front(); + impl->id_pool.pop_front(); + impl->sessions[new_id] = Session{SessionId{new_id}, process, asid}; + } else { + new_id = impl->new_ids++; + impl->sessions.emplace_back(SessionId{new_id}, process, asid); + } + auto& session = impl->sessions[new_id]; + session.is_active = true; + // Optimization + if (process->IsApplication()) { + auto& page_table = process->GetPageTable().GetBasePageTable(); + auto heap_start = page_table.GetHeapRegionStart(); + + Kernel::KProcessAddress cur_addr = heap_start; + size_t region_size = 0; + VAddr region_start = 0; + while (true) { + Kernel::KMemoryInfo mem_info{}; + Kernel::Svc::PageInfo page_info{}; + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), + cur_addr)); + auto svc_mem_info = mem_info.GetSvcMemoryInfo(); + + // Check if this memory block is heap. + if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { + if (svc_mem_info.size > region_size) { + region_size = svc_mem_info.size; + region_start = svc_mem_info.base_address; + } + } + + // Check if we're done. + const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size; + if (next_address <= GetInteger(cur_addr)) { + break; + } + + cur_addr = next_address; + } + session.has_preallocated_area = false; + auto start_region = region_size >= 32_MiB ? smmu.Allocate(region_size) : 0; + if (start_region != 0) { + session.mapper = std::make_unique<HeapMapper>(region_start, start_region, region_size, + asid, impl->host1x); + smmu.TrackContinuity(start_region, region_start, region_size, asid); + session.has_preallocated_area = true; + LOG_DEBUG(Debug, "Preallocation created!"); + } + } + return SessionId{new_id}; +} + +void Container::CloseSession(SessionId session_id) { + std::scoped_lock lk(impl->session_guard); + impl->file.UnmapAllHandles(session_id); + auto& session = impl->sessions[session_id.id]; + auto& smmu = impl->host1x.MemoryManager(); + if (session.has_preallocated_area) { + const DAddr region_start = session.mapper->GetRegionStart(); + const size_t region_size = session.mapper->GetRegionSize(); + session.mapper.reset(); + smmu.Free(region_start, region_size); + session.has_preallocated_area = false; + } + session.is_active = false; + smmu.UnregisterProcess(impl->sessions[session_id.id].asid); + impl->id_pool.emplace_front(session_id.id); +} + +Session* Container::GetSession(SessionId session_id) { + std::atomic_thread_fence(std::memory_order_acquire); + return &impl->sessions[session_id.id]; +} + NvMap& Container::GetNvMapFile() { return impl->file; } diff --git a/src/core/hle/service/nvdrv/core/container.h b/src/core/hle/service/nvdrv/core/container.h index b4b63ac90..b4d3938a8 100644 --- a/src/core/hle/service/nvdrv/core/container.h +++ b/src/core/hle/service/nvdrv/core/container.h @@ -8,24 +8,56 @@ #include <memory> #include <unordered_map> +#include "core/device_memory_manager.h" #include "core/hle/service/nvdrv/nvdata.h" +namespace Kernel { +class KProcess; +} + namespace Tegra::Host1x { class Host1x; } // namespace Tegra::Host1x namespace Service::Nvidia::NvCore { +class HeapMapper; class NvMap; class SyncpointManager; struct ContainerImpl; +struct SessionId { + size_t id; +}; + +struct Session { + Session(SessionId id_, Kernel::KProcess* process_, Core::Asid asid_); + ~Session(); + + Session(const Session&) = delete; + Session& operator=(const Session&) = delete; + Session(Session&&) = default; + Session& operator=(Session&&) = default; + + SessionId id; + Kernel::KProcess* process; + Core::Asid asid; + bool has_preallocated_area{}; + std::unique_ptr<HeapMapper> mapper{}; + bool is_active{}; +}; + class Container { public: explicit Container(Tegra::Host1x::Host1x& host1x); ~Container(); + SessionId OpenSession(Kernel::KProcess* process); + void CloseSession(SessionId id); + + Session* GetSession(SessionId id); + NvMap& GetNvMapFile(); const NvMap& GetNvMapFile() const; diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.cpp b/src/core/hle/service/nvdrv/core/heap_mapper.cpp new file mode 100644 index 000000000..096dc5deb --- /dev/null +++ b/src/core/hle/service/nvdrv/core/heap_mapper.cpp @@ -0,0 +1,175 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include <mutex> + +#include <boost/container/small_vector.hpp> +#define BOOST_NO_MT +#include <boost/pool/detail/mutex.hpp> +#undef BOOST_NO_MT +#include <boost/icl/interval.hpp> +#include <boost/icl/interval_base_set.hpp> +#include <boost/icl/interval_set.hpp> +#include <boost/icl/split_interval_map.hpp> +#include <boost/pool/pool.hpp> +#include <boost/pool/pool_alloc.hpp> +#include <boost/pool/poolfwd.hpp> + +#include "core/hle/service/nvdrv/core/heap_mapper.h" +#include "video_core/host1x/host1x.h" + +namespace boost { +template <typename T> +class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>; +} + +namespace Service::Nvidia::NvCore { + +using IntervalCompare = std::less<DAddr>; +using IntervalInstance = boost::icl::interval_type_default<DAddr, std::less>; +using IntervalAllocator = boost::fast_pool_allocator<DAddr>; +using IntervalSet = boost::icl::interval_set<DAddr>; +using IntervalType = typename IntervalSet::interval_type; + +template <typename Type> +struct counter_add_functor : public boost::icl::identity_based_inplace_combine<Type> { + // types + typedef counter_add_functor<Type> type; + typedef boost::icl::identity_based_inplace_combine<Type> base_type; + + // public member functions + void operator()(Type& current, const Type& added) const { + current += added; + if (current < base_type::identity_element()) { + current = base_type::identity_element(); + } + } + + // public static functions + static void version(Type&){}; +}; + +using OverlapCombine = counter_add_functor<int>; +using OverlapSection = boost::icl::inter_section<int>; +using OverlapCounter = boost::icl::split_interval_map<DAddr, int>; + +struct HeapMapper::HeapMapperInternal { + HeapMapperInternal(Tegra::Host1x::Host1x& host1x) : device_memory{host1x.MemoryManager()} {} + ~HeapMapperInternal() = default; + + template <typename Func> + void ForEachInOverlapCounter(OverlapCounter& current_range, VAddr cpu_addr, u64 size, + Func&& func) { + const DAddr start_address = cpu_addr; + const DAddr end_address = start_address + size; + const IntervalType search_interval{start_address, end_address}; + auto it = current_range.lower_bound(search_interval); + if (it == current_range.end()) { + return; + } + auto end_it = current_range.upper_bound(search_interval); + for (; it != end_it; it++) { + auto& inter = it->first; + DAddr inter_addr_end = inter.upper(); + DAddr inter_addr = inter.lower(); + if (inter_addr_end > end_address) { + inter_addr_end = end_address; + } + if (inter_addr < start_address) { + inter_addr = start_address; + } + func(inter_addr, inter_addr_end, it->second); + } + } + + void RemoveEachInOverlapCounter(OverlapCounter& current_range, + const IntervalType search_interval, int subtract_value) { + bool any_removals = false; + current_range.add(std::make_pair(search_interval, subtract_value)); + do { + any_removals = false; + auto it = current_range.lower_bound(search_interval); + if (it == current_range.end()) { + return; + } + auto end_it = current_range.upper_bound(search_interval); + for (; it != end_it; it++) { + if (it->second <= 0) { + any_removals = true; + current_range.erase(it); + break; + } + } + } while (any_removals); + } + + IntervalSet base_set; + OverlapCounter mapping_overlaps; + Tegra::MaxwellDeviceMemoryManager& device_memory; + std::mutex guard; +}; + +HeapMapper::HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid, + Tegra::Host1x::Host1x& host1x) + : m_vaddress{start_vaddress}, m_daddress{start_daddress}, m_size{size}, m_asid{asid} { + m_internal = std::make_unique<HeapMapperInternal>(host1x); +} + +HeapMapper::~HeapMapper() { + m_internal->device_memory.Unmap(m_daddress, m_size); +} + +DAddr HeapMapper::Map(VAddr start, size_t size) { + std::scoped_lock lk(m_internal->guard); + m_internal->base_set.clear(); + const IntervalType interval{start, start + size}; + m_internal->base_set.insert(interval); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, + [this](VAddr start_addr, VAddr end_addr, int) { + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.subtract(other); + }); + if (!m_internal->base_set.empty()) { + auto it = m_internal->base_set.begin(); + auto end_it = m_internal->base_set.end(); + for (; it != end_it; it++) { + const VAddr inter_addr_end = it->upper(); + const VAddr inter_addr = it->lower(); + const size_t offset = inter_addr - m_vaddress; + const size_t sub_size = inter_addr_end - inter_addr; + m_internal->device_memory.Map(m_daddress + offset, m_vaddress + offset, sub_size, + m_asid); + } + } + m_internal->mapping_overlaps += std::make_pair(interval, 1); + m_internal->base_set.clear(); + return m_daddress + (start - m_vaddress); +} + +void HeapMapper::Unmap(VAddr start, size_t size) { + std::scoped_lock lk(m_internal->guard); + m_internal->base_set.clear(); + m_internal->ForEachInOverlapCounter(m_internal->mapping_overlaps, start, size, + [this](VAddr start_addr, VAddr end_addr, int value) { + if (value <= 1) { + const IntervalType other{start_addr, end_addr}; + m_internal->base_set.insert(other); + } + }); + if (!m_internal->base_set.empty()) { + auto it = m_internal->base_set.begin(); + auto end_it = m_internal->base_set.end(); + for (; it != end_it; it++) { + const VAddr inter_addr_end = it->upper(); + const VAddr inter_addr = it->lower(); + const size_t offset = inter_addr - m_vaddress; + const size_t sub_size = inter_addr_end - inter_addr; + m_internal->device_memory.Unmap(m_daddress + offset, sub_size); + } + } + const IntervalType to_remove{start, start + size}; + m_internal->RemoveEachInOverlapCounter(m_internal->mapping_overlaps, to_remove, -1); + m_internal->base_set.clear(); +} + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/heap_mapper.h b/src/core/hle/service/nvdrv/core/heap_mapper.h new file mode 100644 index 000000000..491a12e4f --- /dev/null +++ b/src/core/hle/service/nvdrv/core/heap_mapper.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <memory> + +#include "common/common_types.h" +#include "core/device_memory_manager.h" + +namespace Tegra::Host1x { +class Host1x; +} // namespace Tegra::Host1x + +namespace Service::Nvidia::NvCore { + +class HeapMapper { +public: + HeapMapper(VAddr start_vaddress, DAddr start_daddress, size_t size, Core::Asid asid, + Tegra::Host1x::Host1x& host1x); + ~HeapMapper(); + + bool IsInBounds(VAddr start, size_t size) const { + VAddr end = start + size; + return start >= m_vaddress && end <= (m_vaddress + m_size); + } + + DAddr Map(VAddr start, size_t size); + + void Unmap(VAddr start, size_t size); + + DAddr GetRegionStart() const { + return m_daddress; + } + + size_t GetRegionSize() const { + return m_size; + } + +private: + struct HeapMapperInternal; + VAddr m_vaddress; + DAddr m_daddress; + size_t m_size; + Core::Asid m_asid; + std::unique_ptr<HeapMapperInternal> m_internal; +}; + +} // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/nvmap.cpp b/src/core/hle/service/nvdrv/core/nvmap.cpp index 0ca05257e..bc1c033c6 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.cpp +++ b/src/core/hle/service/nvdrv/core/nvmap.cpp @@ -2,14 +2,19 @@ // SPDX-FileCopyrightText: 2022 Skyline Team and Contributors // SPDX-License-Identifier: GPL-3.0-or-later +#include <functional> + #include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/core/heap_mapper.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/memory.h" #include "video_core/host1x/host1x.h" using Core::Memory::YUZU_PAGESIZE; +constexpr size_t BIG_PAGE_SIZE = YUZU_PAGESIZE * 16; namespace Service::Nvidia::NvCore { NvMap::Handle::Handle(u64 size_, Id id_) @@ -17,9 +22,9 @@ NvMap::Handle::Handle(u64 size_, Id id_) flags.raw = 0; } -NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) { +NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, + NvCore::SessionId pSessionId) { std::scoped_lock lock(mutex); - // Handles cannot be allocated twice if (allocated) { return NvResult::AccessDenied; @@ -28,6 +33,7 @@ NvResult NvMap::Handle::Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress) flags = pFlags; kind = pKind; align = pAlign < YUZU_PAGESIZE ? YUZU_PAGESIZE : pAlign; + session_id = pSessionId; // This flag is only applicable for handles with an address passed if (pAddress) { @@ -63,7 +69,7 @@ NvResult NvMap::Handle::Duplicate(bool internal_session) { return NvResult::Success; } -NvMap::NvMap(Tegra::Host1x::Host1x& host1x_) : host1x{host1x_} {} +NvMap::NvMap(Container& core_, Tegra::Host1x::Host1x& host1x_) : host1x{host1x_}, core{core_} {} void NvMap::AddHandle(std::shared_ptr<Handle> handle_description) { std::scoped_lock lock(handles_lock); @@ -78,12 +84,30 @@ void NvMap::UnmapHandle(Handle& handle_description) { handle_description.unmap_queue_entry.reset(); } + // Free and unmap the handle from Host1x GMMU + if (handle_description.pin_virt_address) { + host1x.GMMU().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address), + handle_description.aligned_size); + host1x.Allocator().Free(handle_description.pin_virt_address, + static_cast<u32>(handle_description.aligned_size)); + handle_description.pin_virt_address = 0; + } + // Free and unmap the handle from the SMMU - host1x.MemoryManager().Unmap(static_cast<GPUVAddr>(handle_description.pin_virt_address), - handle_description.aligned_size); - host1x.Allocator().Free(handle_description.pin_virt_address, - static_cast<u32>(handle_description.aligned_size)); - handle_description.pin_virt_address = 0; + const size_t map_size = handle_description.aligned_size; + if (!handle_description.in_heap) { + auto& smmu = host1x.MemoryManager(); + size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE); + smmu.Unmap(handle_description.d_address, map_size); + smmu.Free(handle_description.d_address, static_cast<size_t>(aligned_up)); + handle_description.d_address = 0; + return; + } + const VAddr vaddress = handle_description.address; + auto* session = core.GetSession(handle_description.session_id); + session->mapper->Unmap(vaddress, map_size); + handle_description.d_address = 0; + handle_description.in_heap = false; } bool NvMap::TryRemoveHandle(const Handle& handle_description) { @@ -124,22 +148,33 @@ std::shared_ptr<NvMap::Handle> NvMap::GetHandle(Handle::Id handle) { } } -VAddr NvMap::GetHandleAddress(Handle::Id handle) { +DAddr NvMap::GetHandleAddress(Handle::Id handle) { std::scoped_lock lock(handles_lock); try { - return handles.at(handle)->address; + return handles.at(handle)->d_address; } catch (std::out_of_range&) { return 0; } } -u32 NvMap::PinHandle(NvMap::Handle::Id handle) { +DAddr NvMap::PinHandle(NvMap::Handle::Id handle, bool low_area_pin) { auto handle_description{GetHandle(handle)}; if (!handle_description) [[unlikely]] { return 0; } std::scoped_lock lock(handle_description->mutex); + const auto map_low_area = [&] { + if (handle_description->pin_virt_address == 0) { + auto& gmmu_allocator = host1x.Allocator(); + auto& gmmu = host1x.GMMU(); + u32 address = + gmmu_allocator.Allocate(static_cast<u32>(handle_description->aligned_size)); + gmmu.Map(static_cast<GPUVAddr>(address), handle_description->d_address, + handle_description->aligned_size); + handle_description->pin_virt_address = address; + } + }; if (!handle_description->pins) { // If we're in the unmap queue we can just remove ourselves and return since we're already // mapped @@ -151,37 +186,58 @@ u32 NvMap::PinHandle(NvMap::Handle::Id handle) { unmap_queue.erase(*handle_description->unmap_queue_entry); handle_description->unmap_queue_entry.reset(); + if (low_area_pin) { + map_low_area(); + handle_description->pins++; + return static_cast<DAddr>(handle_description->pin_virt_address); + } + handle_description->pins++; - return handle_description->pin_virt_address; + return handle_description->d_address; } } + using namespace std::placeholders; // If not then allocate some space and map it - u32 address{}; - auto& smmu_allocator = host1x.Allocator(); - auto& smmu_memory_manager = host1x.MemoryManager(); - while ((address = smmu_allocator.Allocate( - static_cast<u32>(handle_description->aligned_size))) == 0) { - // Free handles until the allocation succeeds - std::scoped_lock queueLock(unmap_queue_lock); - if (auto freeHandleDesc{unmap_queue.front()}) { - // Handles in the unmap queue are guaranteed not to be pinned so don't bother - // checking if they are before unmapping - std::scoped_lock freeLock(freeHandleDesc->mutex); - if (handle_description->pin_virt_address) - UnmapHandle(*freeHandleDesc); - } else { - LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); + DAddr address{}; + auto& smmu = host1x.MemoryManager(); + auto* session = core.GetSession(handle_description->session_id); + const VAddr vaddress = handle_description->address; + const size_t map_size = handle_description->aligned_size; + if (session->has_preallocated_area && session->mapper->IsInBounds(vaddress, map_size)) { + handle_description->d_address = session->mapper->Map(vaddress, map_size); + handle_description->in_heap = true; + } else { + size_t aligned_up = Common::AlignUp(map_size, BIG_PAGE_SIZE); + while ((address = smmu.Allocate(aligned_up)) == 0) { + // Free handles until the allocation succeeds + std::scoped_lock queueLock(unmap_queue_lock); + if (auto freeHandleDesc{unmap_queue.front()}) { + // Handles in the unmap queue are guaranteed not to be pinned so don't bother + // checking if they are before unmapping + std::scoped_lock freeLock(freeHandleDesc->mutex); + if (handle_description->d_address) + UnmapHandle(*freeHandleDesc); + } else { + LOG_CRITICAL(Service_NVDRV, "Ran out of SMMU address space!"); + } } + + handle_description->d_address = address; + smmu.Map(address, vaddress, map_size, session->asid, true); + handle_description->in_heap = false; } + } - smmu_memory_manager.Map(static_cast<GPUVAddr>(address), handle_description->address, - handle_description->aligned_size); - handle_description->pin_virt_address = address; + if (low_area_pin) { + map_low_area(); } handle_description->pins++; - return handle_description->pin_virt_address; + if (low_area_pin) { + return static_cast<DAddr>(handle_description->pin_virt_address); + } + return handle_description->d_address; } void NvMap::UnpinHandle(Handle::Id handle) { @@ -232,7 +288,7 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna LOG_WARNING(Service_NVDRV, "User duplicate count imbalance detected!"); } else if (handle_description->dupes == 0) { // Force unmap the handle - if (handle_description->pin_virt_address) { + if (handle_description->d_address) { std::scoped_lock queueLock(unmap_queue_lock); UnmapHandle(*handle_description); } @@ -270,4 +326,17 @@ std::optional<NvMap::FreeInfo> NvMap::FreeHandle(Handle::Id handle, bool interna return freeInfo; } +void NvMap::UnmapAllHandles(NvCore::SessionId session_id) { + auto handles_copy = [&] { + std::scoped_lock lk{handles_lock}; + return handles; + }(); + + for (auto& [id, handle] : handles_copy) { + if (handle->session_id.id == session_id.id) { + FreeHandle(id, false); + } + } +} + } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/nvmap.h b/src/core/hle/service/nvdrv/core/nvmap.h index a8e573890..b8be599ae 100644 --- a/src/core/hle/service/nvdrv/core/nvmap.h +++ b/src/core/hle/service/nvdrv/core/nvmap.h @@ -14,6 +14,7 @@ #include "common/bit_field.h" #include "common/common_types.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Tegra { @@ -25,6 +26,8 @@ class Host1x; } // namespace Tegra namespace Service::Nvidia::NvCore { + +class Container; /** * @brief The nvmap core class holds the global state for nvmap and provides methods to manage * handles @@ -48,7 +51,7 @@ public: using Id = u32; Id id; //!< A globally unique identifier for this handle - s32 pins{}; + s64 pins{}; u32 pin_virt_address{}; std::optional<typename std::list<std::shared_ptr<Handle>>::iterator> unmap_queue_entry{}; @@ -61,15 +64,18 @@ public: } flags{}; static_assert(sizeof(Flags) == sizeof(u32)); - u64 address{}; //!< The memory location in the guest's AS that this handle corresponds to, - //!< this can also be in the nvdrv tmem + VAddr address{}; //!< The memory location in the guest's AS that this handle corresponds to, + //!< this can also be in the nvdrv tmem bool is_shared_mem_mapped{}; //!< If this nvmap has been mapped with the MapSharedMem IPC //!< call u8 kind{}; //!< Used for memory compression bool allocated{}; //!< If the handle has been allocated with `Alloc` + bool in_heap{}; + NvCore::SessionId session_id{}; - u64 dma_map_addr{}; //! remove me after implementing pinning. + DAddr d_address{}; //!< The memory location in the device's AS that this handle corresponds + //!< to, this can also be in the nvdrv tmem Handle(u64 size, Id id); @@ -77,7 +83,8 @@ public: * @brief Sets up the handle with the given memory config, can allocate memory from the tmem * if a 0 address is passed */ - [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress); + [[nodiscard]] NvResult Alloc(Flags pFlags, u32 pAlign, u8 pKind, u64 pAddress, + NvCore::SessionId pSessionId); /** * @brief Increases the dupe counter of the handle for the given session @@ -108,7 +115,7 @@ public: bool can_unlock; //!< If the address region is ready to be unlocked }; - explicit NvMap(Tegra::Host1x::Host1x& host1x); + explicit NvMap(Container& core, Tegra::Host1x::Host1x& host1x); /** * @brief Creates an unallocated handle of the given size @@ -117,7 +124,7 @@ public: std::shared_ptr<Handle> GetHandle(Handle::Id handle); - VAddr GetHandleAddress(Handle::Id handle); + DAddr GetHandleAddress(Handle::Id handle); /** * @brief Maps a handle into the SMMU address space @@ -125,7 +132,7 @@ public: * number of calls to `UnpinHandle` * @return The SMMU virtual address that the handle has been mapped to */ - u32 PinHandle(Handle::Id handle); + DAddr PinHandle(Handle::Id handle, bool low_area_pin); /** * @brief When this has been called an equal number of times to `PinHandle` for the supplied @@ -145,6 +152,8 @@ public: */ std::optional<FreeInfo> FreeHandle(Handle::Id handle, bool internal_session); + void UnmapAllHandles(NvCore::SessionId session_id); + private: std::list<std::shared_ptr<Handle>> unmap_queue{}; std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue` @@ -172,5 +181,7 @@ private: * @return If the handle was removed from the map */ bool TryRemoveHandle(const Handle& handle_description); + + Container& core; }; } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h index a04538d5d..8adaddc60 100644 --- a/src/core/hle/service/nvdrv/devices/nvdevice.h +++ b/src/core/hle/service/nvdrv/devices/nvdevice.h @@ -7,6 +7,7 @@ #include <vector> #include "common/common_types.h" +#include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/nvdata.h" namespace Core { @@ -62,7 +63,7 @@ public: * Called once a device is opened * @param fd The device fd */ - virtual void OnOpen(DeviceFD fd) = 0; + virtual void OnOpen(NvCore::SessionId session_id, DeviceFD fd) = 0; /** * Called once a device is closed diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 05a43d8dc..c1ebbd62d 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -35,14 +35,14 @@ NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in return NvResult::NotImplemented; } -void nvdisp_disp0::OnOpen(DeviceFD fd) {} +void nvdisp_disp0::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvdisp_disp0::OnClose(DeviceFD fd) {} void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat format, u32 width, u32 height, u32 stride, android::BufferTransformFlags transform, const Common::Rectangle<int>& crop_rect, std::array<Service::Nvidia::NvFence, 4>& fences, u32 num_fences) { - const VAddr addr = nvmap.GetHandleAddress(buffer_handle); + const DAddr addr = nvmap.GetHandleAddress(buffer_handle); LOG_TRACE(Service, "Drawing from address {:X} offset {:08X} Width {} Height {} Stride {} Format {}", addr, offset, width, height, stride, format); diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h index daee05fe8..5f13a50a2 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; /// Performs a screen flip, drawing the buffer pointed to by the handle. diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 6b3639008..e6646ba04 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -86,7 +86,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i return NvResult::NotImplemented; } -void nvhost_as_gpu::OnOpen(DeviceFD fd) {} +void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { @@ -206,6 +206,8 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { static_cast<u32>(aligned_size >> page_size_bits)); } + nvmap.UnpinHandle(mapping->handle); + // Sparse mappings shouldn't be fully unmapped, just returned to their sparse state // Only FreeSpace can unmap them fully if (mapping->sparse_alloc) { @@ -293,12 +295,12 @@ NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) { return NvResult::BadValue; } - VAddr cpu_address{static_cast<VAddr>( - handle->address + - (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; + DAddr base = nvmap.PinHandle(entry.handle, false); + DAddr device_address{static_cast<DAddr>( + base + (static_cast<u64>(entry.handle_offset_big_pages) << vm.big_page_size_bits))}; - gmmu->Map(virtual_address, cpu_address, size, static_cast<Tegra::PTEKind>(entry.kind), - use_big_pages); + gmmu->Map(virtual_address, device_address, size, + static_cast<Tegra::PTEKind>(entry.kind), use_big_pages); } } @@ -331,9 +333,9 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } u64 gpu_address{static_cast<u64>(params.offset + params.buffer_offset)}; - VAddr cpu_address{mapping->ptr + params.buffer_offset}; + VAddr device_address{mapping->ptr + params.buffer_offset}; - gmmu->Map(gpu_address, cpu_address, params.mapping_size, + gmmu->Map(gpu_address, device_address, params.mapping_size, static_cast<Tegra::PTEKind>(params.kind), mapping->big_page); return NvResult::Success; @@ -349,7 +351,8 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::BadValue; } - VAddr cpu_address{static_cast<VAddr>(handle->address + params.buffer_offset)}; + DAddr device_address{ + static_cast<DAddr>(nvmap.PinHandle(params.handle, false) + params.buffer_offset)}; u64 size{params.mapping_size ? params.mapping_size : handle->orig_size}; bool big_page{[&]() { @@ -373,15 +376,14 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { } const bool use_big_pages = alloc->second.big_pages && big_page; - gmmu->Map(params.offset, cpu_address, size, static_cast<Tegra::PTEKind>(params.kind), + gmmu->Map(params.offset, device_address, size, static_cast<Tegra::PTEKind>(params.kind), use_big_pages); - auto mapping{std::make_shared<Mapping>(cpu_address, params.offset, size, true, - use_big_pages, alloc->second.sparse)}; + auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size, + true, use_big_pages, alloc->second.sparse)}; alloc->second.mappings.push_back(mapping); mapping_map[params.offset] = mapping; } else { - auto& allocator{big_page ? *vm.big_page_allocator : *vm.small_page_allocator}; u32 page_size{big_page ? vm.big_page_size : VM::YUZU_PAGESIZE}; u32 page_size_bits{big_page ? vm.big_page_size_bits : VM::PAGE_SIZE_BITS}; @@ -394,11 +396,11 @@ NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { return NvResult::InsufficientMemory; } - gmmu->Map(params.offset, cpu_address, Common::AlignUp(size, page_size), + gmmu->Map(params.offset, device_address, Common::AlignUp(size, page_size), static_cast<Tegra::PTEKind>(params.kind), big_page); - auto mapping{ - std::make_shared<Mapping>(cpu_address, params.offset, size, false, big_page, false)}; + auto mapping{std::make_shared<Mapping>(params.handle, device_address, params.offset, size, + false, big_page, false)}; mapping_map[params.offset] = mapping; } @@ -433,6 +435,8 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { gmmu->Unmap(params.offset, mapping->size); } + nvmap.UnpinHandle(mapping->handle); + mapping_map.erase(params.offset); } catch (const std::out_of_range&) { LOG_WARNING(Service_NVDRV, "Couldn't find region to unmap at 0x{:X}", params.offset); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 932997e75..7d0a99988 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -55,7 +55,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; @@ -90,7 +90,7 @@ private: u64_le align; }; }; - static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); + static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size"); struct IoctlFreeSpace { u64_le offset{}; @@ -159,16 +159,18 @@ private: NvCore::NvMap& nvmap; struct Mapping { - VAddr ptr; + NvCore::NvMap::Handle::Id handle; + DAddr ptr; u64 offset; u64 size; bool fixed; bool big_page; // Only valid if fixed == false bool sparse_alloc; - Mapping(VAddr ptr_, u64 offset_, u64 size_, bool fixed_, bool big_page_, bool sparse_alloc_) - : ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), big_page(big_page_), - sparse_alloc(sparse_alloc_) {} + Mapping(NvCore::NvMap::Handle::Id handle_, DAddr ptr_, u64 offset_, u64 size_, bool fixed_, + bool big_page_, bool sparse_alloc_) + : handle(handle_), ptr(ptr_), offset(offset_), size(size_), fixed(fixed_), + big_page(big_page_), sparse_alloc(sparse_alloc_) {} }; struct Allocation { @@ -212,9 +214,6 @@ private: bool initialised{}; } vm; std::shared_ptr<Tegra::MemoryManager> gmmu; - - // s32 channel{}; - // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index b8dd34e24..250d01de3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -76,7 +76,7 @@ NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inp return NvResult::NotImplemented; } -void nvhost_ctrl::OnOpen(DeviceFD fd) {} +void nvhost_ctrl::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 992124b60..403f1a746 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -32,7 +32,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 61a2df121..ddd85678b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices { nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) : nvdevice{system_}, events_interface{events_interface_} { error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); - unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); + unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent"); } nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { events_interface.FreeEvent(error_notifier_event); @@ -82,7 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> return NvResult::NotImplemented; } -void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} +void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index d170299bd..d2ab05b21 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -28,7 +28,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index b0395c2f0..bf12d69a5 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -120,7 +120,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu return NvResult::NotImplemented; } -void nvhost_gpu::OnOpen(DeviceFD fd) {} +void nvhost_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 88fd228ff..e34a978db 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -47,7 +47,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index f43914e1b..2c0ac2a46 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -35,7 +35,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in case 0x7: return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output); case 0x9: - return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); + return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output, fd); case 0xa: return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output); default: @@ -68,9 +68,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(DeviceFD fd) { +void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream started"); system.SetNVDECActive(true); + sessions[fd] = session_id; } void nvhost_nvdec::OnClose(DeviceFD fd) { @@ -81,6 +82,10 @@ void nvhost_nvdec::OnClose(DeviceFD fd) { system.GPU().ClearCdmaInstance(iter->second); } system.SetNVDECActive(false); + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } } } // 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 ad2233c49..627686757 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h @@ -20,7 +20,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; 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 74c701b95..a0a7bfa40 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -8,6 +8,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" @@ -95,6 +96,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); auto& gpu = system.GPU(); + auto* session = core.GetSession(sessions[fd]); + if (gpu.UseNvdec()) { for (std::size_t i = 0; i < syncpt_increments.size(); i++) { const SyncptIncr& syncpt_incr = syncpt_increments[i]; @@ -106,8 +109,8 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De const auto object = nvmap.GetHandle(cmd_buffer.memory_id); ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;); Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); - system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), - cmdlist.size() * sizeof(u32)); + session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(), + cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } // Some games expect command_buffers to be written back @@ -133,10 +136,12 @@ NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) { +NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, + DeviceFD fd) { const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); for (size_t i = 0; i < num_entries; i++) { - entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); + DAddr pin_address = nvmap.PinHandle(entries[i].map_handle, true); + entries[i].map_address = static_cast<u32>(pin_address); } return NvResult::Success; 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 7ce748e18..900db81d2 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -4,7 +4,9 @@ #pragma once #include <deque> +#include <unordered_map> #include <vector> + #include "common/common_types.h" #include "common/swap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" @@ -111,7 +113,7 @@ protected: NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd); NvResult GetSyncpoint(IoctlGetSyncpoint& params); NvResult GetWaitbase(IoctlGetWaitbase& params); - NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); + NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries, DeviceFD fd); NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); NvResult SetSubmitTimeout(u32 timeout); @@ -125,6 +127,7 @@ protected: NvCore::NvMap& nvmap; NvCore::ChannelType channel_type; std::array<u32, MaxSyncPoints> device_syncpoints{}; + std::unordered_map<DeviceFD, NvCore::SessionId> sessions; }; }; // namespace Devices } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index 9e6b86458..f87d53f12 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -44,7 +44,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in return NvResult::NotImplemented; } -void nvhost_nvjpg::OnOpen(DeviceFD fd) {} +void nvhost_nvjpg::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 790c97f6a..def9c254d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -22,7 +22,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; private: diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 87f8d7c22..bf090f5eb 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -33,7 +33,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 0x3: return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output); case 0x9: - return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); + return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output, fd); case 0xa: return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output); default: @@ -68,7 +68,9 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu return NvResult::NotImplemented; } -void nvhost_vic::OnOpen(DeviceFD fd) {} +void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { + sessions[fd] = session_id; +} void nvhost_vic::OnClose(DeviceFD fd) { auto& host1x_file = core.Host1xDeviceFile(); @@ -76,6 +78,7 @@ void nvhost_vic::OnClose(DeviceFD fd) { if (iter != host1x_file.fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } + sessions.erase(fd); } } // 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 cadbcb0a5..0cc04354a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h @@ -19,7 +19,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 71b2e62ec..da61a3bfe 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -36,9 +36,9 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, case 0x3: return WrapFixed(this, &nvmap::IocFromId, input, output); case 0x4: - return WrapFixed(this, &nvmap::IocAlloc, input, output); + return WrapFixed(this, &nvmap::IocAlloc, input, output, fd); case 0x5: - return WrapFixed(this, &nvmap::IocFree, input, output); + return WrapFixed(this, &nvmap::IocFree, input, output, fd); case 0x9: return WrapFixed(this, &nvmap::IocParam, input, output); case 0xe: @@ -67,8 +67,15 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st return NvResult::NotImplemented; } -void nvmap::OnOpen(DeviceFD fd) {} -void nvmap::OnClose(DeviceFD fd) {} +void nvmap::OnOpen(NvCore::SessionId session_id, DeviceFD fd) { + sessions[fd] = session_id; +} +void nvmap::OnClose(DeviceFD fd) { + auto it = sessions.find(fd); + if (it != sessions.end()) { + sessions.erase(it); + } +} NvResult nvmap::IocCreate(IocCreateParams& params) { LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); @@ -87,7 +94,7 @@ NvResult nvmap::IocCreate(IocCreateParams& params) { return NvResult::Success; } -NvResult nvmap::IocAlloc(IocAllocParams& params) { +NvResult nvmap::IocAlloc(IocAllocParams& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); if (!params.handle) { @@ -116,15 +123,15 @@ NvResult nvmap::IocAlloc(IocAllocParams& params) { return NvResult::InsufficientMemory; } - const auto result = - handle_description->Alloc(params.flags, params.align, params.kind, params.address); + const auto result = handle_description->Alloc(params.flags, params.align, params.kind, + params.address, sessions[fd]); if (result != NvResult::Success) { LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle); return result; } bool is_out_io{}; - ASSERT(system.ApplicationProcess() - ->GetPageTable() + auto process = container.GetSession(sessions[fd])->process; + ASSERT(process->GetPageTable() .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, handle_description->size, Kernel::KMemoryPermission::None, true, false) @@ -224,7 +231,7 @@ NvResult nvmap::IocParam(IocParamParams& params) { return NvResult::Success; } -NvResult nvmap::IocFree(IocFreeParams& params) { +NvResult nvmap::IocFree(IocFreeParams& params, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called"); if (!params.handle) { @@ -233,9 +240,9 @@ NvResult nvmap::IocFree(IocFreeParams& params) { } if (auto freeInfo{file.FreeHandle(params.handle, false)}) { + auto process = container.GetSession(sessions[fd])->process; if (freeInfo->can_unlock) { - ASSERT(system.ApplicationProcess() - ->GetPageTable() + ASSERT(process->GetPageTable() .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) .IsSuccess()); } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 049c11028..d07d85f88 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -33,7 +33,7 @@ public: NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output) override; - void OnOpen(DeviceFD fd) override; + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; enum class HandleParameterType : u32_le { @@ -100,11 +100,11 @@ public: static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); NvResult IocCreate(IocCreateParams& params); - NvResult IocAlloc(IocAllocParams& params); + NvResult IocAlloc(IocAllocParams& params, DeviceFD fd); NvResult IocGetId(IocGetIdParams& params); NvResult IocFromId(IocFromIdParams& params); NvResult IocParam(IocParamParams& params); - NvResult IocFree(IocFreeParams& params); + NvResult IocFree(IocFreeParams& params, DeviceFD fd); private: /// Id to use for the next handle that is created. @@ -115,6 +115,7 @@ private: NvCore::Container& container; NvCore::NvMap& file; + std::unordered_map<DeviceFD, NvCore::SessionId> sessions; }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 0e2f47075..38f35e79f 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -51,7 +51,7 @@ enum class NvResult : u32 { DispNoDisplaysAttached = 0x20003, DispModeNotSupported = 0x20004, DispNotFound = 0x20005, - DispAttachDissallowed = 0x20006, + DispAttachDisallowed = 0x20006, DispTypeNotSupported = 0x20007, DispAuthenticationFailed = 0x20008, DispNotAttached = 0x20009, diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9e46ee8dd..cb256e5b4 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -45,13 +45,22 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) { void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); auto module = std::make_shared<Module>(system); - server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv")); - server_manager->RegisterNamedService("nvdrv:a", - std::make_shared<NVDRV>(system, module, "nvdrv:a")); - server_manager->RegisterNamedService("nvdrv:s", - std::make_shared<NVDRV>(system, module, "nvdrv:s")); - server_manager->RegisterNamedService("nvdrv:t", - std::make_shared<NVDRV>(system, module, "nvdrv:t")); + const auto NvdrvInterfaceFactoryForApplication = [&, module] { + return std::make_shared<NVDRV>(system, module, "nvdrv"); + }; + const auto NvdrvInterfaceFactoryForApplets = [&, module] { + return std::make_shared<NVDRV>(system, module, "nvdrv:a"); + }; + const auto NvdrvInterfaceFactoryForSysmodules = [&, module] { + return std::make_shared<NVDRV>(system, module, "nvdrv:s"); + }; + const auto NvdrvInterfaceFactoryForTesting = [&, module] { + return std::make_shared<NVDRV>(system, module, "nvdrv:t"); + }; + server_manager->RegisterNamedService("nvdrv", NvdrvInterfaceFactoryForApplication); + server_manager->RegisterNamedService("nvdrv:a", NvdrvInterfaceFactoryForApplets); + server_manager->RegisterNamedService("nvdrv:s", NvdrvInterfaceFactoryForSysmodules); + server_manager->RegisterNamedService("nvdrv:t", NvdrvInterfaceFactoryForTesting); server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system)); nvnflinger.SetNVDrvInstance(module); ServerManager::RunServer(std::move(server_manager)); @@ -113,7 +122,7 @@ NvResult Module::VerifyFD(DeviceFD fd) const { return NvResult::Success; } -DeviceFD Module::Open(const std::string& device_name) { +DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) { auto it = builders.find(device_name); if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); @@ -124,7 +133,7 @@ DeviceFD Module::Open(const std::string& device_name) { auto& builder = it->second; auto device = builder(fd)->second; - device->OnOpen(fd); + device->OnOpen(session_id, fd); return fd; } diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index d8622b3ca..c594f0e5e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -77,7 +77,7 @@ public: NvResult VerifyFD(DeviceFD fd) const; /// Opens a device node and returns a file descriptor to it. - DeviceFD Open(const std::string& device_name); + DeviceFD Open(const std::string& device_name, NvCore::SessionId session_id); /// Sends an ioctl command to the specified file descriptor. NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output); @@ -93,6 +93,10 @@ public: NvResult QueryEvent(DeviceFD fd, u32 event_id, Kernel::KEvent*& event); + NvCore::Container& GetContainer() { + return container; + } + private: friend class EventInterface; friend class Service::Nvnflinger::Nvnflinger; diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp index c8a880e84..ffe72f281 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp +++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp @@ -3,8 +3,11 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "common/logging/log.h" +#include "common/scope_exit.h" +#include "common/string_util.h" #include "core/core.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nvdrv/nvdata.h" @@ -27,7 +30,7 @@ void NVDRV::Open(HLERequestContext& ctx) { } const auto& buffer = ctx.ReadBuffer(); - const std::string device_name(buffer.begin(), buffer.end()); + const std::string device_name(Common::StringFromBuffer(buffer)); if (device_name == "/dev/nvhost-prof-gpu") { rb.Push<DeviceFD>(0); @@ -37,7 +40,7 @@ void NVDRV::Open(HLERequestContext& ctx) { return; } - DeviceFD fd = nvdrv->Open(device_name); + DeviceFD fd = nvdrv->Open(device_name, session_id); rb.Push<DeviceFD>(fd); rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed); @@ -150,12 +153,29 @@ void NVDRV::Close(HLERequestContext& ctx) { void NVDRV::Initialize(HLERequestContext& ctx) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + SCOPE_EXIT({ + rb.Push(ResultSuccess); + rb.PushEnum(NvResult::Success); + }); - is_initialized = true; + if (is_initialized) { + // No need to initialize again + return; + } - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NvResult::Success); + IPC::RequestParser rp{ctx}; + const auto process_handle{ctx.GetCopyHandle(0)}; + // The transfer memory is lent to nvdrv as a work buffer since nvdrv is + // unable to allocate as much memory on its own. For HLE it's unnecessary to handle it + [[maybe_unused]] const auto transfer_memory_handle{ctx.GetCopyHandle(1)}; + [[maybe_unused]] const auto transfer_memory_size = rp.Pop<u32>(); + + auto& container = nvdrv->GetContainer(); + auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(process_handle); + session_id = container.OpenSession(process.GetPointerUnsafe()); + + is_initialized = true; } void NVDRV::QueryEvent(HLERequestContext& ctx) { @@ -242,6 +262,9 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* RegisterHandlers(functions); } -NVDRV::~NVDRV() = default; +NVDRV::~NVDRV() { + auto& container = nvdrv->GetContainer(); + container.CloseSession(session_id); +} } // namespace Service::Nvidia diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h index 6e98115dc..f2195ae1e 100644 --- a/src/core/hle/service/nvdrv/nvdrv_interface.h +++ b/src/core/hle/service/nvdrv/nvdrv_interface.h @@ -35,6 +35,7 @@ private: u64 pid{}; bool is_initialized{}; + NvCore::SessionId session_id{}; Common::ScratchBuffer<u8> output_buffer; Common::ScratchBuffer<u8> inline_output_buffer; }; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 2fef6cc1a..86e272b41 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -87,19 +87,20 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, R_SUCCEED(); } -Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { +Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Nvidia::DeviceFD nvmap_fd) { // Free the handle. Nvidia::Devices::nvmap::IocFreeParams free_params{ .handle = handle, }; - R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocFree(free_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); } Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, - u32 size) { + u32 size, Nvidia::DeviceFD nvmap_fd) { // Assign the allocated memory to the handle. Nvidia::Devices::nvmap::IocAllocParams alloc_params{ .handle = handle, @@ -109,16 +110,16 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce .kind = 0, .address = GetInteger(buffer), }; - R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); + R_UNLESS(nvmap.IocAlloc(alloc_params, nvmap_fd) == Nvidia::NvResult::Success, + VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); } -Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, +Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::DeviceFD nvmap_fd, Common::ProcessAddress buffer, u32 size) { // Get the nvmap device. - auto nvmap_fd = nvdrv.Open("/dev/nvmap"); auto nvmap = nvdrv.GetDevice<Nvidia::Devices::nvmap>(nvmap_fd); ASSERT(nvmap != nullptr); @@ -127,11 +128,11 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, // Ensure we maintain a clean state on failure. ON_RESULT_FAILURE { - ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle))); + ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); }; // Assign the allocated memory to the handle. - R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size)); + R_RETURN(AllocNvMapHandle(*nvmap, *out_handle, buffer, size, nvmap_fd)); } constexpr auto SharedBufferBlockLinearFormat = android::PixelFormat::Rgba8888; @@ -197,9 +198,13 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u std::addressof(m_buffer_page_group), m_system, SharedBufferSize)); + auto& container = m_nvdrv->GetContainer(); + m_session_id = container.OpenSession(m_system.ApplicationProcess()); + m_nvmap_fd = m_nvdrv->Open("/dev/nvmap", m_session_id); + // Create an nvmap handle for the buffer and assign the memory to it. - R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, map_address, - SharedBufferSize)); + R_TRY(AllocateHandleForBuffer(std::addressof(m_buffer_nvmap_handle), *m_nvdrv, m_nvmap_fd, + map_address, SharedBufferSize)); // Record the display id. m_display_id = display_id; diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h index c809c01b4..033bf4bbe 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.h @@ -4,6 +4,8 @@ #pragma once #include "common/math_util.h" +#include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/nvdata.h" #include "core/hle/service/nvnflinger/nvnflinger.h" #include "core/hle/service/nvnflinger/ui/fence.h" @@ -53,7 +55,8 @@ private: u64 m_layer_id = 0; u32 m_buffer_nvmap_handle = 0; SharedMemoryPoolLayout m_pool_layout = {}; - + Nvidia::DeviceFD m_nvmap_fd = {}; + Nvidia::NvCore::SessionId m_session_id = {}; std::unique_ptr<Kernel::KPageGroup> m_buffer_page_group; std::mutex m_guard; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index aa8aaa2d9..71d6fdb0c 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -112,9 +112,7 @@ void Nvnflinger::ShutdownLayers() { { const auto lock_guard = Lock(); for (auto& display : displays) { - for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { - display.GetLayer(layer).GetConsumer().Abandon(); - } + display.Abandon(); } is_abandoned = true; @@ -126,7 +124,7 @@ void Nvnflinger::ShutdownLayers() { void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { nvdrv = std::move(instance); - disp_fd = nvdrv->Open("/dev/nvdisp_disp0"); + disp_fd = nvdrv->Open("/dev/nvdisp_disp0", {}); } std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) { @@ -176,24 +174,28 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { display.CreateLayer(layer_id, buffer_id, nvdrv->container); } -void Nvnflinger::OpenLayer(u64 layer_id) { +bool Nvnflinger::OpenLayer(u64 layer_id) { const auto lock_guard = Lock(); for (auto& display : displays) { if (auto* layer = display.FindLayer(layer_id); layer) { - layer->Open(); + return layer->Open(); } } + + return false; } -void Nvnflinger::CloseLayer(u64 layer_id) { +bool Nvnflinger::CloseLayer(u64 layer_id) { const auto lock_guard = Lock(); for (auto& display : displays) { if (auto* layer = display.FindLayer(layer_id); layer) { - layer->Close(); + return layer->Close(); } } + + return false; } void Nvnflinger::DestroyLayer(u64 layer_id) { @@ -223,7 +225,8 @@ Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 return VI::ResultNotFound; } - return display->GetVSyncEvent(out_vsync_event); + *out_vsync_event = display->GetVSyncEvent(); + return ResultSuccess; } VI::Display* Nvnflinger::FindDisplay(u64 display_id) { diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 871285764..a60e0ae6b 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -74,10 +74,10 @@ public: [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id); /// Opens a layer on all displays for the given layer ID. - void OpenLayer(u64 layer_id); + bool OpenLayer(u64 layer_id); /// Closes a layer on all displays for the given layer ID. - void CloseLayer(u64 layer_id); + bool CloseLayer(u64 layer_id); /// Destroys the given layer ID. void DestroyLayer(u64 layer_id); diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp index ce70946ec..ede2a1193 100644 --- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp +++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp @@ -22,11 +22,13 @@ GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap, : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) { if (this->BufferId() > 0) { m_nvmap->DuplicateHandle(this->BufferId(), true); + m_nvmap->PinHandle(this->BufferId(), false); } } GraphicBuffer::~GraphicBuffer() { if (m_nvmap != nullptr && this->BufferId() > 0) { + m_nvmap->UnpinHandle(this->BufferId()); m_nvmap->FreeHandle(this->BufferId(), true); } } diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index c13ffa6f6..3d0f2aeb7 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -54,8 +54,8 @@ public: class IClkrstSession final : public ServiceFramework<IClkrstSession> { public: - explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) - : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { + explicit IClkrstSession(Core::System& system_, DeviceCode device_code_) + : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "SetClockEnabled"}, @@ -93,7 +93,7 @@ private: rb.Push<u32>(clock_rate); } - DeviceCode deivce_code; + DeviceCode device_code; u32 clock_rate{}; }; @@ -118,9 +118,9 @@ private: void OpenSession(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); - const auto unkonwn_input = rp.Pop<u32>(); + const auto unknown_input = rp.Pop<u32>(); - LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); + LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index d92499f05..b52468e41 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1}; constexpr u64 NO_PROCESS_FOUND_PID{0}; -std::optional<Kernel::KProcess*> SearchProcessList( - const std::vector<Kernel::KProcess*>& process_list, - std::function<bool(Kernel::KProcess*)> predicate) { +using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; + +template <typename F> +Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list, + F&& predicate) { const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); if (iter == process_list.end()) { - return std::nullopt; + return nullptr; } - return *iter; + return iter->GetPointerUnsafe(); } -void GetApplicationPidGeneric(HLERequestContext& ctx, - const std::vector<Kernel::KProcess*>& process_list) { - const auto process = SearchProcessList(process_list, [](const auto& proc) { - return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; - }); +void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { + auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID); + rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); } } // Anonymous namespace @@ -80,8 +79,7 @@ private: class DebugMonitor final : public ServiceFramework<DebugMonitor> { public: - explicit DebugMonitor(Core::System& system_) - : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { + explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetJitDebugProcessIdList"}, @@ -106,12 +104,11 @@ private: LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); - const auto process = - SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { - return proc->GetProgramId() == program_id; - }); + auto list = kernel.GetProcessList(); + auto process = SearchProcessList( + list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); - if (!process.has_value()) { + if (process.IsNull()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultProcessNotFound); return; @@ -119,12 +116,13 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push((*process)->GetProcessId()); + rb.Push(process->GetProcessId()); } void GetApplicationProcessId(HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); - GetApplicationPidGeneric(ctx, kernel.GetProcessList()); + auto list = kernel.GetProcessList(); + GetApplicationPidGeneric(ctx, list); } void AtmosphereGetProcessInfo(HLERequestContext& ctx) { @@ -135,11 +133,10 @@ private: LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); - const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) { - return proc->GetProcessId() == pid; - }); + auto list = kernel.GetProcessList(); + auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); - if (!process.has_value()) { + if (process.IsNull()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultProcessNotFound); return; @@ -159,7 +156,7 @@ private: OverrideStatus override_status{}; ProgramLocation program_location{ - .program_id = (*process)->GetProgramId(), + .program_id = process->GetProgramId(), .storage_id = 0, }; @@ -169,14 +166,11 @@ private: rb.PushRaw(program_location); rb.PushRaw(override_status); } - - const Kernel::KernelCore& kernel; }; class Info final : public ServiceFramework<Info> { public: - explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) - : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { + explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { static const FunctionInfo functions[] = { {0, &Info::GetProgramId, "GetProgramId"}, {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, @@ -193,11 +187,11 @@ private: LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); - const auto process = SearchProcessList(process_list, [process_id](const auto& proc) { - return proc->GetProcessId() == process_id; - }); + auto list = kernel.GetProcessList(); + auto process = SearchProcessList( + list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); - if (!process.has_value()) { + if (process.IsNull()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultProcessNotFound); return; @@ -205,7 +199,7 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push((*process)->GetProgramId()); + rb.Push(process->GetProgramId()); } void AtmosphereGetProcessId(HLERequestContext& ctx) { @@ -214,11 +208,11 @@ private: LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); - const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { - return proc->GetProgramId() == program_id; - }); + auto list = system.Kernel().GetProcessList(); + auto process = SearchProcessList( + list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); - if (!process.has_value()) { + if (process.IsNull()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultProcessNotFound); return; @@ -226,16 +220,13 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.Push((*process)->GetProcessId()); + rb.Push(process->GetProcessId()); } - - const std::vector<Kernel::KProcess*>& process_list; }; class Shell final : public ServiceFramework<Shell> { public: - explicit Shell(Core::System& system_) - : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { + explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "LaunchProgram"}, @@ -257,10 +248,9 @@ public: private: void GetApplicationProcessIdForShell(HLERequestContext& ctx) { LOG_DEBUG(Service_PM, "called"); - GetApplicationPidGeneric(ctx, kernel.GetProcessList()); + auto list = kernel.GetProcessList(); + GetApplicationPidGeneric(ctx, list); } - - const Kernel::KernelCore& kernel; }; void LoopProcess(Core::System& system) { @@ -268,8 +258,7 @@ void LoopProcess(Core::System& system) { server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); - server_manager->RegisterNamedService( - "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList())); + server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index cd0cc9287..44310756b 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp @@ -4,9 +4,13 @@ #include <memory> #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/psc/psc.h" -#include "core/hle/service/server_manager.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/psc/time/power_state_service.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/psc/time/static.h" #include "core/hle/service/service.h" namespace Service::PSC { @@ -76,6 +80,17 @@ void LoopProcess(Core::System& system) { server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); + + auto time = std::make_shared<Time::TimeManager>(system); + + server_manager->RegisterNamedService( + "time:m", std::make_shared<Time::ServiceManager>(system, time, server_manager.get())); + server_manager->RegisterNamedService( + "time:su", std::make_shared<Time::StaticService>( + system, Time::StaticServiceSetupInfo{0, 0, 0, 0, 0, 1}, time, "time:su")); + server_manager->RegisterNamedService("time:al", + std::make_shared<Time::IAlarmService>(system, time)); + ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/psc/time/alarms.cpp b/src/core/hle/service/psc/time/alarms.cpp new file mode 100644 index 000000000..5e52c19f8 --- /dev/null +++ b/src/core/hle/service/psc/time/alarms.cpp @@ -0,0 +1,209 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/alarms.h" +#include "core/hle/service/psc/time/manager.h" + +namespace Service::PSC::Time { +Alarm::Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type) + : m_ctx{ctx}, m_event{ctx.CreateEvent("Psc:Alarm:Event")} { + m_event->Clear(); + + switch (type) { + case WakeupAlarm: + m_priority = 1; + break; + case BackgroundTaskAlarm: + m_priority = 0; + break; + default: + UNREACHABLE(); + return; + } +} + +Alarm::~Alarm() { + m_ctx.CloseEvent(m_event); +} + +Alarms::Alarms(Core::System& system, StandardSteadyClockCore& steady_clock, + PowerStateRequestManager& power_state_request_manager) + : m_system{system}, m_ctx{system, "Psc:Alarms"}, m_steady_clock{steady_clock}, + m_power_state_request_manager{power_state_request_manager}, m_event{m_ctx.CreateEvent( + "Psc:Alarms:Event")} {} + +Alarms::~Alarms() { + m_ctx.CloseEvent(m_event); +} + +Result Alarms::Enable(Alarm& alarm, s64 time) { + R_UNLESS(m_steady_clock.IsInitialized(), ResultClockUninitialized); + + std::scoped_lock l{m_mutex}; + R_UNLESS(alarm.IsLinked(), ResultAlarmNotRegistered); + + auto time_ns{time + m_steady_clock.GetRawTime()}; + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + time_ns = Common::AlignUp(time_ns, one_second_ns); + alarm.SetAlertTime(time_ns); + + Insert(alarm); + R_RETURN(UpdateClosestAndSignal()); +} + +void Alarms::Disable(Alarm& alarm) { + std::scoped_lock l{m_mutex}; + if (!alarm.IsLinked()) { + return; + } + + Erase(alarm); + UpdateClosestAndSignal(); +} + +void Alarms::CheckAndSignal() { + std::scoped_lock l{m_mutex}; + if (m_alarms.empty()) { + return; + } + + bool alarm_signalled{false}; + for (auto& alarm : m_alarms) { + if (m_steady_clock.GetRawTime() >= alarm.GetAlertTime()) { + alarm.Signal(); + alarm.Lock(); + Erase(alarm); + + m_power_state_request_manager.UpdatePendingPowerStateRequestPriority( + alarm.GetPriority()); + alarm_signalled = true; + } + } + + if (!alarm_signalled) { + return; + } + + m_power_state_request_manager.SignalPowerStateRequestAvailability(); + UpdateClosestAndSignal(); +} + +bool Alarms::GetClosestAlarm(Alarm** out_alarm) { + std::scoped_lock l{m_mutex}; + auto alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front()); + *out_alarm = alarm; + return alarm != nullptr; +} + +void Alarms::Insert(Alarm& alarm) { + // Alarms are sorted by alert time, then priority + auto it{m_alarms.begin()}; + while (it != m_alarms.end()) { + if (alarm.GetAlertTime() < it->GetAlertTime() || + (alarm.GetAlertTime() == it->GetAlertTime() && + alarm.GetPriority() < it->GetPriority())) { + m_alarms.insert(it, alarm); + return; + } + it++; + } + + m_alarms.push_back(alarm); +} + +void Alarms::Erase(Alarm& alarm) { + m_alarms.erase(m_alarms.iterator_to(alarm)); +} + +Result Alarms::UpdateClosestAndSignal() { + m_closest_alarm = m_alarms.empty() ? nullptr : std::addressof(m_alarms.front()); + R_SUCCEED_IF(m_closest_alarm == nullptr); + + m_event->Signal(); + + R_SUCCEED(); +} + +IAlarmService::IAlarmService(Core::System& system_, std::shared_ptr<TimeManager> manager) + : ServiceFramework{system_, "time:al"}, m_system{system}, m_alarms{manager->m_alarms} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IAlarmService::CreateWakeupAlarm, "CreateWakeupAlarm"}, + {1, &IAlarmService::CreateBackgroundTaskAlarm, "CreateBackgroundTaskAlarm"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +void IAlarmService::CreateWakeupAlarm(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::WakeupAlarm); +} + +void IAlarmService::CreateBackgroundTaskAlarm(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<ISteadyClockAlarm>(system, m_alarms, AlarmType::BackgroundTaskAlarm); +} + +ISteadyClockAlarm::ISteadyClockAlarm(Core::System& system_, Alarms& alarms, AlarmType type) + : ServiceFramework{system_, "ISteadyClockAlarm"}, m_ctx{system, "Psc:ISteadyClockAlarm"}, + m_alarms{alarms}, m_alarm{system, m_ctx, type} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISteadyClockAlarm::GetAlarmEvent, "GetAlarmEvent"}, + {1, &ISteadyClockAlarm::Enable, "Enable"}, + {2, &ISteadyClockAlarm::Disable, "Disable"}, + {3, &ISteadyClockAlarm::IsEnabled, "IsEnabled"}, + {10, nullptr, "CreateWakeLock"}, + {11, nullptr, "DestroyWakeLock"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +void ISteadyClockAlarm::GetAlarmEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(m_alarm.GetEventHandle()); +} + +void ISteadyClockAlarm::Enable(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + auto res = m_alarms.Enable(m_alarm, time); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISteadyClockAlarm::Disable(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + m_alarms.Disable(m_alarm); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISteadyClockAlarm::IsEnabled(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<bool>(m_alarm.IsLinked()); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/alarms.h b/src/core/hle/service/psc/time/alarms.h new file mode 100644 index 000000000..597770028 --- /dev/null +++ b/src/core/hle/service/psc/time/alarms.h @@ -0,0 +1,139 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/power_state_request_manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class TimeManager; + +enum AlarmType : u32 { + WakeupAlarm = 0, + BackgroundTaskAlarm = 1, +}; + +struct Alarm : public Common::IntrusiveListBaseNode<Alarm> { + using AlarmList = Common::IntrusiveListBaseTraits<Alarm>::ListType; + + Alarm(Core::System& system, KernelHelpers::ServiceContext& ctx, AlarmType type); + ~Alarm(); + + Kernel::KReadableEvent& GetEventHandle() { + return m_event->GetReadableEvent(); + } + + s64 GetAlertTime() const { + return m_alert_time; + } + + void SetAlertTime(s64 time) { + m_alert_time = time; + } + + u32 GetPriority() const { + return m_priority; + } + + void Signal() { + m_event->Signal(); + } + + Result Lock() { + // TODO + // if (m_lock_service) { + // return m_lock_service->Lock(); + // } + R_SUCCEED(); + } + + KernelHelpers::ServiceContext& m_ctx; + + u32 m_priority; + Kernel::KEvent* m_event{}; + s64 m_alert_time{}; + // TODO + // nn::psc::sf::IPmStateLock* m_lock_service{}; +}; + +class Alarms { +public: + explicit Alarms(Core::System& system, StandardSteadyClockCore& steady_clock, + PowerStateRequestManager& power_state_request_manager); + ~Alarms(); + + Kernel::KEvent& GetEvent() { + return *m_event; + } + + s64 GetRawTime() { + return m_steady_clock.GetRawTime(); + } + + Result Enable(Alarm& alarm, s64 time); + void Disable(Alarm& alarm); + void CheckAndSignal(); + bool GetClosestAlarm(Alarm** out_alarm); + +private: + void Insert(Alarm& alarm); + void Erase(Alarm& alarm); + Result UpdateClosestAndSignal(); + + Core::System& m_system; + KernelHelpers::ServiceContext m_ctx; + + StandardSteadyClockCore& m_steady_clock; + PowerStateRequestManager& m_power_state_request_manager; + Alarm::AlarmList m_alarms; + Kernel::KEvent* m_event{}; + Alarm* m_closest_alarm{}; + std::mutex m_mutex; +}; + +class IAlarmService final : public ServiceFramework<IAlarmService> { +public: + explicit IAlarmService(Core::System& system, std::shared_ptr<TimeManager> manager); + + ~IAlarmService() override = default; + +private: + void CreateWakeupAlarm(HLERequestContext& ctx); + void CreateBackgroundTaskAlarm(HLERequestContext& ctx); + + Core::System& m_system; + Alarms& m_alarms; +}; + +class ISteadyClockAlarm final : public ServiceFramework<ISteadyClockAlarm> { +public: + explicit ISteadyClockAlarm(Core::System& system, Alarms& alarms, AlarmType type); + + ~ISteadyClockAlarm() override = default; + +private: + void GetAlarmEvent(HLERequestContext& ctx); + void Enable(HLERequestContext& ctx); + void Disable(HLERequestContext& ctx); + void IsEnabled(HLERequestContext& ctx); + + KernelHelpers::ServiceContext m_ctx; + + Alarms& m_alarms; + Alarm m_alarm; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/context_writers.cpp b/src/core/hle/service/psc/time/clocks/context_writers.cpp new file mode 100644 index 000000000..ac8700f76 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/context_writers.cpp @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" + +namespace Service::PSC::Time { + +void ContextWriter::SignalAllNodes() { + std::scoped_lock l{m_mutex}; + for (auto& operation : m_operation_events) { + operation.m_event->Signal(); + } +} + +void ContextWriter::Link(OperationEvent& operation_event) { + std::scoped_lock l{m_mutex}; + m_operation_events.push_back(operation_event); +} + +LocalSystemClockContextWriter::LocalSystemClockContextWriter(Core::System& system, + SharedMemory& shared_memory) + : m_system{system}, m_shared_memory{shared_memory} {} + +Result LocalSystemClockContextWriter::Write(SystemClockContext& context) { + if (m_in_use) { + R_SUCCEED_IF(context == m_context); + m_context = context; + } else { + m_context = context; + m_in_use = true; + } + + m_shared_memory.SetLocalSystemContext(context); + + SignalAllNodes(); + + R_SUCCEED(); +} + +NetworkSystemClockContextWriter::NetworkSystemClockContextWriter(Core::System& system, + SharedMemory& shared_memory, + SystemClockCore& system_clock) + : m_system{system}, m_shared_memory{shared_memory}, m_system_clock{system_clock} {} + +Result NetworkSystemClockContextWriter::Write(SystemClockContext& context) { + s64 time{}; + [[maybe_unused]] auto res = m_system_clock.GetCurrentTime(&time); + + if (m_in_use) { + R_SUCCEED_IF(context == m_context); + m_context = context; + } else { + m_context = context; + m_in_use = true; + } + + m_shared_memory.SetNetworkSystemContext(context); + + SignalAllNodes(); + + R_SUCCEED(); +} + +EphemeralNetworkSystemClockContextWriter::EphemeralNetworkSystemClockContextWriter( + Core::System& system) + : m_system{system} {} + +Result EphemeralNetworkSystemClockContextWriter::Write(SystemClockContext& context) { + if (m_in_use) { + R_SUCCEED_IF(context == m_context); + m_context = context; + } else { + m_context = context; + m_in_use = true; + } + + SignalAllNodes(); + + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/context_writers.h b/src/core/hle/service/psc/time/clocks/context_writers.h new file mode 100644 index 000000000..afd3725d4 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/context_writers.h @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <list> + +#include "common/common_types.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/shared_memory.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class ContextWriter { +private: + using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType; + +public: + virtual ~ContextWriter() = default; + + virtual Result Write(SystemClockContext& context) = 0; + void SignalAllNodes(); + void Link(OperationEvent& operation_event); + +private: + OperationEventList m_operation_events; + std::mutex m_mutex; +}; + +class LocalSystemClockContextWriter : public ContextWriter { +public: + explicit LocalSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory); + + Result Write(SystemClockContext& context) override; + +private: + Core::System& m_system; + + SharedMemory& m_shared_memory; + bool m_in_use{}; + SystemClockContext m_context{}; +}; + +class NetworkSystemClockContextWriter : public ContextWriter { +public: + explicit NetworkSystemClockContextWriter(Core::System& system, SharedMemory& shared_memory, + SystemClockCore& system_clock); + + Result Write(SystemClockContext& context) override; + +private: + Core::System& m_system; + + SharedMemory& m_shared_memory; + bool m_in_use{}; + SystemClockContext m_context{}; + SystemClockCore& m_system_clock; +}; + +class EphemeralNetworkSystemClockContextWriter : public ContextWriter { +public: + EphemeralNetworkSystemClockContextWriter(Core::System& system); + + Result Write(SystemClockContext& context) override; + +private: + Core::System& m_system; + + bool m_in_use{}; + SystemClockContext m_context{}; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h new file mode 100644 index 000000000..0a68867d9 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { + +class EphemeralNetworkSystemClockCore : public SystemClockCore { +public: + explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock) + : SystemClockCore{steady_clock} {} + ~EphemeralNetworkSystemClockCore() override = default; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp new file mode 100644 index 000000000..36dca6689 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.cpp @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" + +namespace Service::PSC::Time { + +void StandardLocalSystemClockCore::Initialize(SystemClockContext& context, s64 time) { + SteadyClockTimePoint time_point{}; + if (GetCurrentTimePoint(time_point) == ResultSuccess && + context.steady_time_point.IdMatches(time_point)) { + SetContextAndWrite(context); + } else if (SetCurrentTime(time) != ResultSuccess) { + LOG_ERROR(Service_Time, "Failed to SetCurrentTime"); + } + + SetInitialized(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h new file mode 100644 index 000000000..176ba3e94 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_local_system_clock_core.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { + +class StandardLocalSystemClockCore : public SystemClockCore { +public: + explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock) + : SystemClockCore{steady_clock} {} + ~StandardLocalSystemClockCore() override = default; + + void Initialize(SystemClockContext& context, s64 time); +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp new file mode 100644 index 000000000..8d6cb7db1 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.cpp @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" + +namespace Service::PSC::Time { + +void StandardNetworkSystemClockCore::Initialize(SystemClockContext& context, s64 accuracy) { + if (SetContextAndWrite(context) != ResultSuccess) { + LOG_ERROR(Service_Time, "Failed to SetContext"); + } + m_sufficient_accuracy = accuracy; + SetInitialized(); +} + +bool StandardNetworkSystemClockCore::IsAccuracySufficient() { + if (!IsInitialized()) { + return false; + } + + SystemClockContext context{}; + SteadyClockTimePoint current_time_point{}; + if (GetCurrentTimePoint(current_time_point) != ResultSuccess || + GetContext(context) != ResultSuccess) { + return false; + } + + s64 seconds{}; + if (GetSpanBetweenTimePoints(&seconds, context.steady_time_point, current_time_point) != + ResultSuccess) { + return false; + } + + if (std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(seconds)) + .count() < m_sufficient_accuracy) { + return true; + } + + return false; +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h new file mode 100644 index 000000000..933d2c8e3 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_network_system_clock_core.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <chrono> + +#include "core/hle/result.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { + +class StandardNetworkSystemClockCore : public SystemClockCore { +public: + explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock) + : SystemClockCore{steady_clock} {} + ~StandardNetworkSystemClockCore() override = default; + + void Initialize(SystemClockContext& context, s64 accuracy); + bool IsAccuracySufficient(); + +private: + s64 m_sufficient_accuracy{ + std::chrono ::duration_cast<std::chrono::nanoseconds>(std::chrono::days(10)).count()}; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp new file mode 100644 index 000000000..7a72d7aa2 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.cpp @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" + +namespace Service::PSC::Time { + +void StandardSteadyClockCore::Initialize(ClockSourceId clock_source_id, s64 rtc_offset, + s64 internal_offset, s64 test_offset, + bool is_rtc_reset_detected) { + m_clock_source_id = clock_source_id; + m_rtc_offset = rtc_offset; + m_internal_offset = internal_offset; + m_test_offset = test_offset; + if (is_rtc_reset_detected) { + SetResetDetected(); + } + SetInitialized(); +} + +void StandardSteadyClockCore::SetRtcOffset(s64 offset) { + m_rtc_offset = offset; +} + +void StandardSteadyClockCore::SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time) { + auto ticks{m_system.CoreTiming().GetClockTicks()}; + + m_continuous_adjustment_time_point.rtc_offset = ConvertToTimeSpan(ticks).count(); + m_continuous_adjustment_time_point.diff_scale = 0; + m_continuous_adjustment_time_point.shift_amount = 0; + m_continuous_adjustment_time_point.lower = time; + m_continuous_adjustment_time_point.upper = time; + m_continuous_adjustment_time_point.clock_source_id = clock_source_id; +} + +void StandardSteadyClockCore::GetContinuousAdjustment( + ContinuousAdjustmentTimePoint& out_time_point) const { + out_time_point = m_continuous_adjustment_time_point; +} + +void StandardSteadyClockCore::UpdateContinuousAdjustmentTime(s64 in_time) { + auto ticks{m_system.CoreTiming().GetClockTicks()}; + auto uptime_ns{ConvertToTimeSpan(ticks).count()}; + auto adjusted_time{((uptime_ns - m_continuous_adjustment_time_point.rtc_offset) * + m_continuous_adjustment_time_point.diff_scale) >> + m_continuous_adjustment_time_point.shift_amount}; + auto expected_time{adjusted_time + m_continuous_adjustment_time_point.lower}; + + auto last_time_point{m_continuous_adjustment_time_point.upper}; + m_continuous_adjustment_time_point.upper = in_time; + auto t1{std::min<s64>(expected_time, last_time_point)}; + expected_time = std::max<s64>(expected_time, last_time_point); + expected_time = m_continuous_adjustment_time_point.diff_scale >= 0 ? t1 : expected_time; + + auto new_diff{in_time < expected_time ? -55 : 55}; + + m_continuous_adjustment_time_point.rtc_offset = uptime_ns; + m_continuous_adjustment_time_point.shift_amount = expected_time == in_time ? 0 : 14; + m_continuous_adjustment_time_point.diff_scale = expected_time == in_time ? 0 : new_diff; + m_continuous_adjustment_time_point.lower = expected_time; +} + +Result StandardSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) { + auto current_time_ns = GetCurrentRawTimePointImpl(); + auto current_time_s = + std::chrono::duration_cast<std::chrono::seconds>(std::chrono::nanoseconds(current_time_ns)); + out_time_point.time_point = current_time_s.count(); + out_time_point.clock_source_id = m_clock_source_id; + R_SUCCEED(); +} + +s64 StandardSteadyClockCore::GetCurrentRawTimePointImpl() { + std::scoped_lock l{m_mutex}; + auto ticks{static_cast<s64>(m_system.CoreTiming().GetClockTicks())}; + auto current_time_ns = m_rtc_offset + ConvertToTimeSpan(ticks).count(); + auto time_point = std::max<s64>(current_time_ns, m_cached_time_point); + m_cached_time_point = time_point; + return time_point; +} + +s64 StandardSteadyClockCore::GetTestOffsetImpl() const { + return m_test_offset; +} + +void StandardSteadyClockCore::SetTestOffsetImpl(s64 offset) { + m_test_offset = offset; +} + +s64 StandardSteadyClockCore::GetInternalOffsetImpl() const { + return m_internal_offset; +} + +void StandardSteadyClockCore::SetInternalOffsetImpl(s64 offset) { + m_internal_offset = offset; +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h new file mode 100644 index 000000000..bbf98fcd5 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_steady_clock_core.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> + +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class StandardSteadyClockCore : public SteadyClockCore { +public: + explicit StandardSteadyClockCore(Core::System& system) : m_system{system} {} + ~StandardSteadyClockCore() override = default; + + void Initialize(ClockSourceId clock_source_id, s64 rtc_offset, s64 internal_offset, + s64 test_offset, bool is_rtc_reset_detected); + + void SetRtcOffset(s64 offset); + void SetContinuousAdjustment(ClockSourceId clock_source_id, s64 time); + void GetContinuousAdjustment(ContinuousAdjustmentTimePoint& out_time_point) const; + void UpdateContinuousAdjustmentTime(s64 time); + + Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override; + s64 GetCurrentRawTimePointImpl() override; + s64 GetTestOffsetImpl() const override; + void SetTestOffsetImpl(s64 offset) override; + s64 GetInternalOffsetImpl() const override; + void SetInternalOffsetImpl(s64 offset) override; + + Result GetRtcValueImpl(s64& out_value) override { + R_RETURN(ResultNotImplemented); + } + + Result GetSetupResultValueImpl() override { + R_SUCCEED(); + } + +private: + Core::System& m_system; + + std::mutex m_mutex; + s64 m_test_offset{}; + s64 m_internal_offset{}; + ClockSourceId m_clock_source_id{}; + s64 m_rtc_offset{}; + s64 m_cached_time_point{}; + ContinuousAdjustmentTimePoint m_continuous_adjustment_time_point{}; +}; +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp new file mode 100644 index 000000000..9e9be05d6 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" + +namespace Service::PSC::Time { + +StandardUserSystemClockCore::StandardUserSystemClockCore( + Core::System& system, StandardLocalSystemClockCore& local_clock, + StandardNetworkSystemClockCore& network_clock) + : SystemClockCore{local_clock.GetSteadyClock()}, m_system{system}, + m_ctx{m_system, "Psc:StandardUserSystemClockCore"}, m_local_system_clock{local_clock}, + m_network_system_clock{network_clock}, m_event{m_ctx.CreateEvent( + "Psc:StandardUserSystemClockCore:Event")} {} + +StandardUserSystemClockCore::~StandardUserSystemClockCore() { + m_ctx.CloseEvent(m_event); +} + +Result StandardUserSystemClockCore::SetAutomaticCorrection(bool automatic_correction) { + R_SUCCEED_IF(m_automatic_correction == automatic_correction); + R_SUCCEED_IF(!m_network_system_clock.CheckClockSourceMatches()); + + SystemClockContext context{}; + R_TRY(m_network_system_clock.GetContext(context)); + R_TRY(m_local_system_clock.SetContextAndWrite(context)); + + m_automatic_correction = automatic_correction; + R_SUCCEED(); +} + +Result StandardUserSystemClockCore::GetContext(SystemClockContext& out_context) const { + if (!m_automatic_correction) { + R_RETURN(m_local_system_clock.GetContext(out_context)); + } + + if (!m_network_system_clock.CheckClockSourceMatches()) { + R_RETURN(m_local_system_clock.GetContext(out_context)); + } + + SystemClockContext context{}; + R_TRY(m_network_system_clock.GetContext(context)); + R_TRY(m_local_system_clock.SetContextAndWrite(context)); + + R_RETURN(m_local_system_clock.GetContext(out_context)); +} + +Result StandardUserSystemClockCore::SetContext(SystemClockContext& context) { + R_RETURN(ResultNotImplemented); +} + +Result StandardUserSystemClockCore::GetTimePoint(SteadyClockTimePoint& out_time_point) { + out_time_point = m_time_point; + R_SUCCEED(); +} + +void StandardUserSystemClockCore::SetTimePointAndSignal(SteadyClockTimePoint& time_point) { + m_time_point = time_point; + m_event->Signal(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h new file mode 100644 index 000000000..a7fe7648d --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/standard_user_system_clock_core.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_event.h" +#include "core/hle/result.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class StandardUserSystemClockCore : public SystemClockCore { +public: + explicit StandardUserSystemClockCore(Core::System& system, + StandardLocalSystemClockCore& local_clock, + StandardNetworkSystemClockCore& network_clock); + ~StandardUserSystemClockCore() override; + + Kernel::KEvent& GetEvent() { + return *m_event; + } + + bool GetAutomaticCorrection() const { + return m_automatic_correction; + } + Result SetAutomaticCorrection(bool automatic_correction); + + Result GetContext(SystemClockContext& out_context) const override; + Result SetContext(SystemClockContext& context) override; + + Result GetTimePoint(SteadyClockTimePoint& out_time_point); + void SetTimePointAndSignal(SteadyClockTimePoint& time_point); + +private: + Core::System& m_system; + KernelHelpers::ServiceContext m_ctx; + + bool m_automatic_correction{}; + StandardLocalSystemClockCore& m_local_system_clock; + StandardNetworkSystemClockCore& m_network_system_clock; + SteadyClockTimePoint m_time_point{}; + Kernel::KEvent* m_event{}; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/steady_clock_core.h b/src/core/hle/service/psc/time/clocks/steady_clock_core.h new file mode 100644 index 000000000..f933cc15f --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/steady_clock_core.h @@ -0,0 +1,81 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <chrono> + +#include "core/hle/result.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { + +class SteadyClockCore { +public: + SteadyClockCore() = default; + virtual ~SteadyClockCore() = default; + + void SetInitialized() { + m_initialized = true; + } + + bool IsInitialized() const { + return m_initialized; + } + + void SetResetDetected() { + m_reset_detected = true; + } + + bool IsResetDetected() const { + return m_reset_detected; + } + + Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { + R_TRY(GetCurrentTimePointImpl(out_time_point)); + + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + out_time_point.time_point += GetTestOffsetImpl() / one_second_ns; + out_time_point.time_point += GetInternalOffsetImpl() / one_second_ns; + R_SUCCEED(); + } + + s64 GetTestOffset() const { + return GetTestOffsetImpl(); + } + + void SetTestOffset(s64 offset) { + SetTestOffsetImpl(offset); + } + + s64 GetInternalOffset() const { + return GetInternalOffsetImpl(); + } + + s64 GetRawTime() { + return GetCurrentRawTimePointImpl() + GetTestOffsetImpl() + GetInternalOffsetImpl(); + } + + Result GetRtcValue(s64& out_value) { + R_RETURN(GetRtcValueImpl(out_value)); + } + + Result GetSetupResultValue() { + R_RETURN(GetSetupResultValueImpl()); + } + +private: + virtual Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) = 0; + virtual s64 GetCurrentRawTimePointImpl() = 0; + virtual s64 GetTestOffsetImpl() const = 0; + virtual void SetTestOffsetImpl(s64 offset) = 0; + virtual s64 GetInternalOffsetImpl() const = 0; + virtual void SetInternalOffsetImpl(s64 offset) = 0; + virtual Result GetRtcValueImpl(s64& out_value) = 0; + virtual Result GetSetupResultValueImpl() = 0; + + bool m_initialized{}; + bool m_reset_detected{}; +}; +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.cpp b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp new file mode 100644 index 000000000..c507ef517 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/system_clock_core.cpp @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/system_clock_core.h" + +namespace Service::PSC::Time { + +bool SystemClockCore::CheckClockSourceMatches() { + SystemClockContext context{}; + if (GetContext(context) != ResultSuccess) { + return false; + } + + SteadyClockTimePoint time_point{}; + if (m_steady_clock.GetCurrentTimePoint(time_point) != ResultSuccess) { + return false; + } + + return context.steady_time_point.IdMatches(time_point); +} + +Result SystemClockCore::GetCurrentTime(s64* out_time) const { + R_UNLESS(out_time != nullptr, ResultInvalidArgument); + + SystemClockContext context{}; + SteadyClockTimePoint time_point{}; + + R_TRY(m_steady_clock.GetCurrentTimePoint(time_point)); + R_TRY(GetContext(context)); + + R_UNLESS(context.steady_time_point.IdMatches(time_point), ResultClockMismatch); + + *out_time = context.offset + time_point.time_point; + R_SUCCEED(); +} + +Result SystemClockCore::SetCurrentTime(s64 time) { + SteadyClockTimePoint time_point{}; + R_TRY(m_steady_clock.GetCurrentTimePoint(time_point)); + + SystemClockContext context{ + .offset = time - time_point.time_point, + .steady_time_point = time_point, + }; + R_RETURN(SetContextAndWrite(context)); +} + +Result SystemClockCore::GetContext(SystemClockContext& out_context) const { + out_context = m_context; + R_SUCCEED(); +} + +Result SystemClockCore::SetContext(SystemClockContext& context) { + m_context = context; + R_SUCCEED(); +} + +Result SystemClockCore::SetContextAndWrite(SystemClockContext& context) { + R_TRY(SetContext(context)); + + if (m_context_writer) { + R_RETURN(m_context_writer->Write(context)); + } + + R_SUCCEED(); +} + +void SystemClockCore::LinkOperationEvent(OperationEvent& operation_event) { + if (m_context_writer) { + m_context_writer->Link(operation_event); + } +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/system_clock_core.h b/src/core/hle/service/psc/time/clocks/system_clock_core.h new file mode 100644 index 000000000..73811712e --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/system_clock_core.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { +class ContextWriter; + +class SystemClockCore { +public: + explicit SystemClockCore(SteadyClockCore& steady_clock) : m_steady_clock{steady_clock} {} + virtual ~SystemClockCore() = default; + + SteadyClockCore& GetSteadyClock() { + return m_steady_clock; + } + + bool IsInitialized() const { + return m_initialized; + } + + void SetInitialized() { + m_initialized = true; + } + + void SetContextWriter(ContextWriter& context_writer) { + m_context_writer = &context_writer; + } + + bool CheckClockSourceMatches(); + + Result GetCurrentTime(s64* out_time) const; + Result SetCurrentTime(s64 time); + + Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { + R_RETURN(m_steady_clock.GetCurrentTimePoint(out_time_point)); + } + + virtual Result GetContext(SystemClockContext& out_context) const; + virtual Result SetContext(SystemClockContext& context); + Result SetContextAndWrite(SystemClockContext& context); + + void LinkOperationEvent(OperationEvent& operation_event); + +private: + bool m_initialized{}; + ContextWriter* m_context_writer{}; + SteadyClockCore& m_steady_clock; + SystemClockContext m_context{}; +}; +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp new file mode 100644 index 000000000..22da1fbcc --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <chrono> + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h" + +namespace Service::PSC::Time { + +Result TickBasedSteadyClockCore::GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) { + auto ticks{m_system.CoreTiming().GetClockTicks()}; + auto current_time_s = + std::chrono::duration_cast<std::chrono::seconds>(ConvertToTimeSpan(ticks)).count(); + out_time_point.time_point = current_time_s; + out_time_point.clock_source_id = m_clock_source_id; + R_SUCCEED(); +} + +s64 TickBasedSteadyClockCore::GetCurrentRawTimePointImpl() { + SteadyClockTimePoint time_point{}; + if (GetCurrentTimePointImpl(time_point) != ResultSuccess) { + LOG_ERROR(Service_Time, "Failed to GetCurrentTimePoint!"); + } + return std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::seconds(time_point.time_point)) + .count(); +} + +s64 TickBasedSteadyClockCore::GetTestOffsetImpl() const { + return 0; +} + +void TickBasedSteadyClockCore::SetTestOffsetImpl(s64 offset) {} + +s64 TickBasedSteadyClockCore::GetInternalOffsetImpl() const { + return 0; +} + +void TickBasedSteadyClockCore::SetInternalOffsetImpl(s64 offset) {} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h new file mode 100644 index 000000000..a7bea86a2 --- /dev/null +++ b/src/core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> + +#include "common/uuid.h" +#include "core/hle/service/psc/time/clocks/steady_clock_core.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class TickBasedSteadyClockCore : public SteadyClockCore { +public: + explicit TickBasedSteadyClockCore(Core::System& system) : m_system{system} {} + ~TickBasedSteadyClockCore() override = default; + + Result GetCurrentTimePointImpl(SteadyClockTimePoint& out_time_point) override; + s64 GetCurrentRawTimePointImpl() override; + s64 GetTestOffsetImpl() const override; + void SetTestOffsetImpl(s64 offset) override; + s64 GetInternalOffsetImpl() const override; + void SetInternalOffsetImpl(s64 offset) override; + + Result GetRtcValueImpl(s64& out_value) override { + R_RETURN(ResultNotImplemented); + } + + Result GetSetupResultValueImpl() override { + R_SUCCEED(); + } + +private: + Core::System& m_system; + + ClockSourceId m_clock_source_id{Common::UUID::MakeRandom()}; +}; +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/common.cpp b/src/core/hle/service/psc/time/common.cpp new file mode 100644 index 000000000..a6d9f02ca --- /dev/null +++ b/src/core/hle/service/psc/time/common.cpp @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { +OperationEvent::OperationEvent(Core::System& system) + : m_ctx{system, "Time:OperationEvent"}, m_event{ + m_ctx.CreateEvent("Time:OperationEvent:Event")} {} + +OperationEvent::~OperationEvent() { + m_ctx.CloseEvent(m_event); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h new file mode 100644 index 000000000..d17b31143 --- /dev/null +++ b/src/core/hle/service/psc/time/common.h @@ -0,0 +1,168 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <chrono> + +#include "common/common_types.h" +#include "common/intrusive_list.h" +#include "common/uuid.h" +#include "common/wall_clock.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/psc/time/errors.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +using ClockSourceId = Common::UUID; + +struct SteadyClockTimePoint { + constexpr bool IdMatches(SteadyClockTimePoint& other) { + return clock_source_id == other.clock_source_id; + } + bool operator==(const SteadyClockTimePoint& other) const = default; + + s64 time_point; + ClockSourceId clock_source_id; +}; +static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint has the wrong size!"); +static_assert(std::is_trivial_v<ClockSourceId>); + +struct SystemClockContext { + bool operator==(const SystemClockContext& other) const = default; + + s64 offset; + SteadyClockTimePoint steady_time_point; +}; +static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!"); +static_assert(std::is_trivial_v<SystemClockContext>); + +enum class TimeType : u8 { + UserSystemClock, + NetworkSystemClock, + LocalSystemClock, +}; + +struct CalendarTime { + s16 year; + s8 month; + s8 day; + s8 hour; + s8 minute; + s8 second; +}; +static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime has the wrong size!"); + +struct CalendarAdditionalInfo { + s32 day_of_week; + s32 day_of_year; + std::array<char, 8> name; + s32 is_dst; + s32 ut_offset; +}; +static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!"); + +struct LocationName { + std::array<char, 36> name; +}; +static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!"); + +struct RuleVersion { + std::array<char, 16> version; +}; +static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!"); + +struct ClockSnapshot { + SystemClockContext user_context; + SystemClockContext network_context; + s64 user_time; + s64 network_time; + CalendarTime user_calendar_time; + CalendarTime network_calendar_time; + CalendarAdditionalInfo user_calendar_additional_time; + CalendarAdditionalInfo network_calendar_additional_time; + SteadyClockTimePoint steady_clock_time_point; + LocationName location_name; + bool is_automatic_correction_enabled; + TimeType type; + u16 unk_CE; +}; +static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot has the wrong size!"); +static_assert(std::is_trivial_v<ClockSnapshot>); + +struct ContinuousAdjustmentTimePoint { + s64 rtc_offset; + s64 diff_scale; + s64 shift_amount; + s64 lower; + s64 upper; + ClockSourceId clock_source_id; +}; +static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38, + "ContinuousAdjustmentTimePoint has the wrong size!"); +static_assert(std::is_trivial_v<ContinuousAdjustmentTimePoint>); + +struct AlarmInfo { + s64 alert_time; + u32 priority; +}; +static_assert(sizeof(AlarmInfo) == 0x10, "AlarmInfo has the wrong size!"); + +struct StaticServiceSetupInfo { + bool can_write_local_clock; + bool can_write_user_clock; + bool can_write_network_clock; + bool can_write_timezone_device_location; + bool can_write_steady_clock; + bool can_write_uninitialized_clock; +}; +static_assert(sizeof(StaticServiceSetupInfo) == 0x6, "StaticServiceSetupInfo has the wrong size!"); + +struct OperationEvent : public Common::IntrusiveListBaseNode<OperationEvent> { + using OperationEventList = Common::IntrusiveListBaseTraits<OperationEvent>::ListType; + + OperationEvent(Core::System& system); + ~OperationEvent(); + + KernelHelpers::ServiceContext m_ctx; + Kernel::KEvent* m_event{}; +}; + +constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) { + constexpr auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + + constexpr s64 max{Common::WallClock::CNTFRQ * + (std::numeric_limits<s64>::max() / one_second_ns)}; + + if (ticks > max) { + return std::chrono::nanoseconds(std::numeric_limits<s64>::max()); + } else if (ticks < -max) { + return std::chrono::nanoseconds(std::numeric_limits<s64>::min()); + } + + auto a{ticks / Common::WallClock::CNTFRQ * one_second_ns}; + auto b{((ticks % Common::WallClock::CNTFRQ) * one_second_ns) / Common::WallClock::CNTFRQ}; + + return std::chrono::nanoseconds(a + b); +} + +constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a, + SteadyClockTimePoint& b) { + R_UNLESS(out_seconds, ResultInvalidArgument); + R_UNLESS(a.IdMatches(b), ResultInvalidArgument); + R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(), + ResultOverflow); + R_UNLESS(a.time_point < 0 || b.time_point >= a.time_point + std::numeric_limits<s64>::min(), + ResultOverflow); + + *out_seconds = b.time_point - a.time_point; + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/errors.h b/src/core/hle/service/psc/time/errors.h new file mode 100644 index 000000000..6d833a006 --- /dev/null +++ b/src/core/hle/service/psc/time/errors.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::PSC::Time { + +constexpr Result ResultPermissionDenied{ErrorModule::Time, 1}; +constexpr Result ResultClockMismatch{ErrorModule::Time, 102}; +constexpr Result ResultClockUninitialized{ErrorModule::Time, 103}; +constexpr Result ResultTimeNotFound{ErrorModule::Time, 200}; +constexpr Result ResultOverflow{ErrorModule::Time, 201}; +constexpr Result ResultFailed{ErrorModule::Time, 801}; +constexpr Result ResultInvalidArgument{ErrorModule::Time, 901}; +constexpr Result ResultTimeZoneOutOfRange{ErrorModule::Time, 902}; +constexpr Result ResultTimeZoneParseFailed{ErrorModule::Time, 903}; +constexpr Result ResultRtcTimeout{ErrorModule::Time, 988}; +constexpr Result ResultTimeZoneNotFound{ErrorModule::Time, 989}; +constexpr Result ResultNotImplemented{ErrorModule::Time, 990}; +constexpr Result ResultAlarmNotRegistered{ErrorModule::Time, 1502}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/manager.h b/src/core/hle/service/psc/time/manager.h new file mode 100644 index 000000000..62ded1247 --- /dev/null +++ b/src/core/hle/service/psc/time/manager.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/psc/time/alarms.h" +#include "core/hle/service/psc/time/clocks/context_writers.h" +#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_steady_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/tick_based_steady_clock_core.h" +#include "core/hle/service/psc/time/power_state_request_manager.h" +#include "core/hle/service/psc/time/shared_memory.h" +#include "core/hle/service/psc/time/time_zone.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { +class TimeManager { +public: + explicit TimeManager(Core::System& system) + : m_system{system}, m_standard_steady_clock{system}, m_tick_based_steady_clock{m_system}, + m_standard_local_system_clock{m_standard_steady_clock}, + m_standard_network_system_clock{m_standard_steady_clock}, + m_standard_user_system_clock{m_system, m_standard_local_system_clock, + m_standard_network_system_clock}, + m_ephemeral_network_clock{m_tick_based_steady_clock}, m_shared_memory{m_system}, + m_power_state_request_manager{m_system}, m_alarms{m_system, m_standard_steady_clock, + m_power_state_request_manager}, + m_local_system_clock_context_writer{m_system, m_shared_memory}, + m_network_system_clock_context_writer{m_system, m_shared_memory, + m_standard_user_system_clock}, + m_ephemeral_network_clock_context_writer{m_system} {} + + Core::System& m_system; + + StandardSteadyClockCore m_standard_steady_clock; + TickBasedSteadyClockCore m_tick_based_steady_clock; + StandardLocalSystemClockCore m_standard_local_system_clock; + StandardNetworkSystemClockCore m_standard_network_system_clock; + StandardUserSystemClockCore m_standard_user_system_clock; + EphemeralNetworkSystemClockCore m_ephemeral_network_clock; + TimeZone m_time_zone; + SharedMemory m_shared_memory; + PowerStateRequestManager m_power_state_request_manager; + Alarms m_alarms; + LocalSystemClockContextWriter m_local_system_clock_context_writer; + NetworkSystemClockContextWriter m_network_system_clock_context_writer; + EphemeralNetworkSystemClockContextWriter m_ephemeral_network_clock_context_writer; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/power_state_request_manager.cpp b/src/core/hle/service/psc/time/power_state_request_manager.cpp new file mode 100644 index 000000000..17de0bf4d --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_request_manager.cpp @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/power_state_request_manager.h" + +namespace Service::PSC::Time { + +PowerStateRequestManager::PowerStateRequestManager(Core::System& system) + : m_system{system}, m_ctx{system, "Psc:PowerStateRequestManager"}, + m_event{m_ctx.CreateEvent("Psc:PowerStateRequestManager:Event")} {} + +PowerStateRequestManager::~PowerStateRequestManager() { + m_ctx.CloseEvent(m_event); +} + +void PowerStateRequestManager::UpdatePendingPowerStateRequestPriority(u32 priority) { + std::scoped_lock l{m_mutex}; + if (m_has_pending_request) { + m_pending_request_priority = std::max(m_pending_request_priority, priority); + } else { + m_pending_request_priority = priority; + m_has_pending_request = true; + } +} + +void PowerStateRequestManager::SignalPowerStateRequestAvailability() { + std::scoped_lock l{m_mutex}; + if (m_has_pending_request) { + if (!m_has_available_request) { + m_has_available_request = true; + } + m_has_pending_request = false; + m_available_request_priority = m_pending_request_priority; + m_event->Signal(); + } +} + +bool PowerStateRequestManager::GetAndClearPowerStateRequest(u32& out_priority) { + std::scoped_lock l{m_mutex}; + auto had_request{m_has_available_request}; + if (m_has_available_request) { + out_priority = m_available_request_priority; + m_has_available_request = false; + m_event->Clear(); + } + return had_request; +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/power_state_request_manager.h b/src/core/hle/service/psc/time/power_state_request_manager.h new file mode 100644 index 000000000..30a0c947d --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_request_manager.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> + +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/kernel_helpers.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class PowerStateRequestManager { +public: + explicit PowerStateRequestManager(Core::System& system); + ~PowerStateRequestManager(); + + Kernel::KReadableEvent& GetReadableEvent() { + return m_event->GetReadableEvent(); + } + + void UpdatePendingPowerStateRequestPriority(u32 priority); + void SignalPowerStateRequestAvailability(); + bool GetAndClearPowerStateRequest(u32& out_priority); + +private: + Core::System& m_system; + KernelHelpers::ServiceContext m_ctx; + + Kernel::KEvent* m_event{}; + bool m_has_pending_request{}; + u32 m_pending_request_priority{}; + bool m_has_available_request{}; + u32 m_available_request_priority{}; + std::mutex m_mutex; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/power_state_service.cpp b/src/core/hle/service/psc/time/power_state_service.cpp new file mode 100644 index 000000000..b0ae71bf9 --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_service.cpp @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/psc/time/power_state_service.h" + +namespace Service::PSC::Time { + +IPowerStateRequestHandler::IPowerStateRequestHandler( + Core::System& system_, PowerStateRequestManager& power_state_request_manager) + : ServiceFramework{system_, "time:p"}, m_system{system}, m_power_state_request_manager{ + power_state_request_manager} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle, "GetPowerStateRequestEventReadableHandle"}, + {1, &IPowerStateRequestHandler::GetAndClearPowerStateRequest, "GetAndClearPowerStateRequest"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +void IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(m_power_state_request_manager.GetReadableEvent()); +} + +void IPowerStateRequestHandler::GetAndClearPowerStateRequest(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + u32 priority{}; + auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority); + + if (cleared) { + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push(priority); + rb.Push(cleared); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(cleared); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/power_state_service.h b/src/core/hle/service/psc/time/power_state_service.h new file mode 100644 index 000000000..3ebfddb79 --- /dev/null +++ b/src/core/hle/service/psc/time/power_state_service.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/power_state_request_manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class IPowerStateRequestHandler final : public ServiceFramework<IPowerStateRequestHandler> { +public: + explicit IPowerStateRequestHandler(Core::System& system, + PowerStateRequestManager& power_state_request_manager); + + ~IPowerStateRequestHandler() override = default; + +private: + void GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx); + void GetAndClearPowerStateRequest(HLERequestContext& ctx); + + Core::System& m_system; + PowerStateRequestManager& m_power_state_request_manager; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp new file mode 100644 index 000000000..60820aa9b --- /dev/null +++ b/src/core/hle/service/psc/time/service_manager.cpp @@ -0,0 +1,494 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/service/psc/time/power_state_service.h" +#include "core/hle/service/psc/time/service_manager.h" +#include "core/hle/service/psc/time/static.h" + +namespace Service::PSC::Time { + +ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManager> time, + ServerManager* server_manager) + : ServiceFramework{system_, "time:m"}, m_system{system}, m_time{std::move(time)}, + m_server_manager{*server_manager}, + m_local_system_clock{m_time->m_standard_local_system_clock}, + m_user_system_clock{m_time->m_standard_user_system_clock}, + m_network_system_clock{m_time->m_standard_network_system_clock}, + m_steady_clock{m_time->m_standard_steady_clock}, m_time_zone{m_time->m_time_zone}, + m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, + m_shared_memory{m_time->m_shared_memory}, m_alarms{m_time->m_alarms}, + m_local_system_context_writer{m_time->m_local_system_clock_context_writer}, + m_network_system_context_writer{m_time->m_network_system_clock_context_writer}, + m_ephemeral_system_context_writer{m_time->m_ephemeral_network_clock_context_writer}, + m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ServiceManager::Handle_GetStaticServiceAsUser, "GetStaticServiceAsUser"}, + {5, &ServiceManager::Handle_GetStaticServiceAsAdmin, "GetStaticServiceAsAdmin"}, + {6, &ServiceManager::Handle_GetStaticServiceAsRepair, "GetStaticServiceAsRepair"}, + {9, &ServiceManager::Handle_GetStaticServiceAsServiceManager, "GetStaticServiceAsServiceManager"}, + {10, &ServiceManager::Handle_SetupStandardSteadyClockCore, "SetupStandardSteadyClockCore"}, + {11, &ServiceManager::Handle_SetupStandardLocalSystemClockCore, "SetupStandardLocalSystemClockCore"}, + {12, &ServiceManager::Handle_SetupStandardNetworkSystemClockCore, "SetupStandardNetworkSystemClockCore"}, + {13, &ServiceManager::Handle_SetupStandardUserSystemClockCore, "SetupStandardUserSystemClockCore"}, + {14, &ServiceManager::Handle_SetupTimeZoneServiceCore, "SetupTimeZoneServiceCore"}, + {15, &ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore, "SetupEphemeralNetworkSystemClockCore"}, + {50, &ServiceManager::Handle_GetStandardLocalClockOperationEvent, "GetStandardLocalClockOperationEvent"}, + {51, &ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager, "GetStandardNetworkClockOperationEventForServiceManager"}, + {52, &ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager, "GetEphemeralNetworkClockOperationEventForServiceManager"}, + {60, &ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"}, + {100, &ServiceManager::Handle_SetStandardSteadyClockBaseTime, "SetStandardSteadyClockBaseTime"}, + {200, &ServiceManager::Handle_GetClosestAlarmUpdatedEvent, "GetClosestAlarmUpdatedEvent"}, + {201, &ServiceManager::Handle_CheckAndSignalAlarms, "CheckAndSignalAlarms"}, + {202, &ServiceManager::Handle_GetClosestAlarmInfo, "GetClosestAlarmInfo "}, + }; + // clang-format on + RegisterHandlers(functions); + + m_local_system_context_writer.Link(m_local_operation); + m_network_system_context_writer.Link(m_network_operation); + m_ephemeral_system_context_writer.Link(m_ephemeral_operation); +} + +void ServiceManager::SetupSAndP() { + if (!m_is_s_and_p_setup) { + m_is_s_and_p_setup = true; + m_server_manager.RegisterNamedService( + "time:s", std::make_shared<StaticService>( + m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s")); + m_server_manager.RegisterNamedService("time:p", + std::make_shared<IPowerStateRequestHandler>( + m_system, m_time->m_power_state_request_manager)); + } +} + +void ServiceManager::CheckAndSetupServicesSAndP() { + if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() && + m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() && + m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) { + SetupSAndP(); + } +} + +void ServiceManager::Handle_GetStaticServiceAsUser(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<StaticService> service{}; + auto res = GetStaticServiceAsUser(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<StaticService>(std::move(service)); +} + +void ServiceManager::Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<StaticService> service{}; + auto res = GetStaticServiceAsAdmin(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<StaticService>(std::move(service)); +} + +void ServiceManager::Handle_GetStaticServiceAsRepair(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<StaticService> service{}; + auto res = GetStaticServiceAsRepair(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<StaticService>(std::move(service)); +} + +void ServiceManager::Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<StaticService> service{}; + auto res = GetStaticServiceAsServiceManager(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<StaticService>(std::move(service)); +} + +void ServiceManager::Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + struct Parameters { + bool reset_detected; + Common::UUID clock_source_id; + s64 rtc_offset; + s64 internal_offset; + s64 test_offset; + }; + static_assert(sizeof(Parameters) == 0x30); + + IPC::RequestParser rp{ctx}; + auto params{rp.PopRaw<Parameters>()}; + + auto res = SetupStandardSteadyClockCore(params.clock_source_id, params.rtc_offset, + params.internal_offset, params.test_offset, + params.reset_detected); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<SystemClockContext>()}; + auto time{rp.Pop<s64>()}; + + auto res = SetupStandardLocalSystemClockCore(context, time); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<SystemClockContext>()}; + auto accuracy{rp.Pop<s64>()}; + + auto res = SetupStandardNetworkSystemClockCore(context, accuracy); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + struct Parameters { + bool automatic_correction; + SteadyClockTimePoint time_point; + }; + static_assert(sizeof(Parameters) == 0x20); + + IPC::RequestParser rp{ctx}; + auto params{rp.PopRaw<Parameters>()}; + + auto res = SetupStandardUserSystemClockCore(params.time_point, params.automatic_correction); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + struct Parameters { + u32 location_count; + LocationName name; + SteadyClockTimePoint time_point; + RuleVersion rule_version; + }; + static_assert(sizeof(Parameters) == 0x50); + + IPC::RequestParser rp{ctx}; + auto params{rp.PopRaw<Parameters>()}; + + auto rule_buffer{ctx.ReadBuffer()}; + + auto res = SetupTimeZoneServiceCore(params.name, params.time_point, params.rule_version, + params.location_count, rule_buffer); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + auto res = SetupEphemeralNetworkSystemClockCore(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetStandardLocalClockOperationEvent(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event->GetReadableEvent()); +} + +void ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetStandardNetworkClockOperationEventForServiceManager(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event); +} + +void ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetEphemeralNetworkClockOperationEventForServiceManager(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event); +} + +void ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event); +} + +void ServiceManager::Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto base_time{rp.Pop<s64>()}; + + auto res = SetStandardSteadyClockBaseTime(base_time); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetClosestAlarmUpdatedEvent(&event); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.PushCopyObjects(event->GetReadableEvent()); +} + +void ServiceManager::Handle_CheckAndSignalAlarms(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + auto res = CheckAndSignalAlarms(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ServiceManager::Handle_GetClosestAlarmInfo(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + AlarmInfo alarm_info{}; + bool is_valid{}; + s64 time{}; + auto res = GetClosestAlarmInfo(is_valid, alarm_info, time); + + struct OutParameters { + bool is_valid; + AlarmInfo alarm_info; + s64 time; + }; + static_assert(sizeof(OutParameters) == 0x20); + + OutParameters out_params{ + .is_valid = is_valid, + .alarm_info = alarm_info, + .time = time, + }; + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(OutParameters) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<OutParameters>(out_params); +} + +// =============================== Implementations =========================== + +Result ServiceManager::GetStaticService(std::shared_ptr<StaticService>& out_service, + StaticServiceSetupInfo setup_info, const char* name) { + out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name); + R_SUCCEED(); +} + +Result ServiceManager::GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service) { + R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u")); +} + +Result ServiceManager::GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service) { + R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a")); +} + +Result ServiceManager::GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service) { + R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r")); +} + +Result ServiceManager::GetStaticServiceAsServiceManager( + std::shared_ptr<StaticService>& out_service) { + R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm")); +} + +Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, + s64 internal_offset, s64 test_offset, + bool is_rtc_reset_detected) { + m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset, + is_rtc_reset_detected); + auto time = m_steady_clock.GetRawTime(); + auto ticks = m_system.CoreTiming().GetClockTicks(); + auto boot_time = time - ConvertToTimeSpan(ticks).count(); + m_shared_memory.SetSteadyClockTimePoint(clock_source_id, boot_time); + m_steady_clock.SetContinuousAdjustment(clock_source_id, boot_time); + + ContinuousAdjustmentTimePoint time_point{}; + m_steady_clock.GetContinuousAdjustment(time_point); + m_shared_memory.SetContinuousAdjustment(time_point); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) { + m_local_system_clock.SetContextWriter(m_local_system_context_writer); + m_local_system_clock.Initialize(context, time); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context, + s64 accuracy) { + // TODO this is a hack! The network clock should be updated independently, from the ntc service + // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot + // to avoid it being stuck at 0. + if (context == Service::PSC::Time::SystemClockContext{}) { + m_local_system_clock.GetContext(context); + } + + m_network_system_clock.SetContextWriter(m_network_system_context_writer); + m_network_system_clock.Initialize(context, accuracy); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, + bool automatic_correction) { + // TODO this is a hack! The user clock should be updated independently, from the ntc service + // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot + // to avoid it being stuck at 0. + if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) { + m_local_system_clock.GetCurrentTimePoint(time_point); + } + + m_user_system_clock.SetAutomaticCorrection(automatic_correction); + m_user_system_clock.SetTimePointAndSignal(time_point); + m_user_system_clock.SetInitialized(); + m_shared_memory.SetAutomaticCorrection(automatic_correction); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, + SteadyClockTimePoint& time_point, + RuleVersion& rule_version, u32 location_count, + std::span<const u8> rule_buffer) { + if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) { + LOG_ERROR(Service_Time, "Failed to parse time zone binary!"); + } + + m_time_zone.SetTimePoint(time_point); + m_time_zone.SetTotalLocationNameCount(location_count); + m_time_zone.SetRuleVersion(rule_version); + m_time_zone.SetInitialized(); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::SetupEphemeralNetworkSystemClockCore() { + m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer); + m_ephemeral_network_clock.SetInitialized(); + + CheckAndSetupServicesSAndP(); + R_SUCCEED(); +} + +Result ServiceManager::GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event) { + *out_event = m_local_operation.m_event; + R_SUCCEED(); +} + +Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager( + Kernel::KEvent** out_event) { + *out_event = m_network_operation.m_event; + R_SUCCEED(); +} + +Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager( + Kernel::KEvent** out_event) { + *out_event = m_ephemeral_operation.m_event; + R_SUCCEED(); +} + +Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( + Kernel::KEvent** out_event) { + *out_event = &m_user_system_clock.GetEvent(); + R_SUCCEED(); +} + +Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) { + m_steady_clock.SetRtcOffset(base_time); + auto time = m_steady_clock.GetRawTime(); + auto ticks = m_system.CoreTiming().GetClockTicks(); + auto diff = time - ConvertToTimeSpan(ticks).count(); + m_shared_memory.UpdateBaseTime(diff); + m_steady_clock.UpdateContinuousAdjustmentTime(diff); + + ContinuousAdjustmentTimePoint time_point{}; + m_steady_clock.GetContinuousAdjustment(time_point); + m_shared_memory.SetContinuousAdjustment(time_point); + R_SUCCEED(); +} + +Result ServiceManager::GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event) { + *out_event = &m_alarms.GetEvent(); + R_SUCCEED(); +} + +Result ServiceManager::CheckAndSignalAlarms() { + m_alarms.CheckAndSignal(); + R_SUCCEED(); +} + +Result ServiceManager::GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time) { + Alarm* alarm{nullptr}; + out_is_valid = m_alarms.GetClosestAlarm(&alarm); + if (out_is_valid) { + out_info = { + .alert_time = alarm->GetAlertTime(), + .priority = alarm->GetPriority(), + }; + out_time = m_alarms.GetRawTime(); + } + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/service_manager.h b/src/core/hle/service/psc/time/service_manager.h new file mode 100644 index 000000000..1d9952317 --- /dev/null +++ b/src/core/hle/service/psc/time/service_manager.h @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <list> +#include <memory> + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KReadableEvent; +} + +namespace Service::PSC::Time { +class StaticService; + +class ServiceManager final : public ServiceFramework<ServiceManager> { +public: + explicit ServiceManager(Core::System& system, std::shared_ptr<TimeManager> time, + ServerManager* server_manager); + ~ServiceManager() override = default; + + Result GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service); + Result GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service); + Result GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service); + Result GetStaticServiceAsServiceManager(std::shared_ptr<StaticService>& out_service); + Result SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, + s64 internal_offset, s64 test_offset, + bool is_rtc_reset_detected); + Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time); + Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy); + Result SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, + bool automatic_correction); + Result SetupTimeZoneServiceCore(LocationName& name, SteadyClockTimePoint& time_point, + RuleVersion& rule_version, u32 location_count, + std::span<const u8> rule_buffer); + Result SetupEphemeralNetworkSystemClockCore(); + Result GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event); + Result GetStandardNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); + Result GetEphemeralNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); + Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(Kernel::KEvent** out_event); + Result SetStandardSteadyClockBaseTime(s64 base_time); + Result GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event); + Result CheckAndSignalAlarms(); + Result GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time); + +private: + void CheckAndSetupServicesSAndP(); + void SetupSAndP(); + Result GetStaticService(std::shared_ptr<StaticService>& out_service, + StaticServiceSetupInfo setup_info, const char* name); + + void Handle_GetStaticServiceAsUser(HLERequestContext& ctx); + void Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx); + void Handle_GetStaticServiceAsRepair(HLERequestContext& ctx); + void Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx); + void Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx); + void Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx); + void Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx); + void Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx); + void Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx); + void Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx); + void Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx); + void Handle_GetStandardNetworkClockOperationEventForServiceManager(HLERequestContext& ctx); + void Handle_GetEphemeralNetworkClockOperationEventForServiceManager(HLERequestContext& ctx); + void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(HLERequestContext& ctx); + void Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx); + void Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx); + void Handle_CheckAndSignalAlarms(HLERequestContext& ctx); + void Handle_GetClosestAlarmInfo(HLERequestContext& ctx); + + Core::System& m_system; + std::shared_ptr<TimeManager> m_time; + ServerManager& m_server_manager; + bool m_is_s_and_p_setup{}; + StandardLocalSystemClockCore& m_local_system_clock; + StandardUserSystemClockCore& m_user_system_clock; + StandardNetworkSystemClockCore& m_network_system_clock; + StandardSteadyClockCore& m_steady_clock; + TimeZone& m_time_zone; + EphemeralNetworkSystemClockCore& m_ephemeral_network_clock; + SharedMemory& m_shared_memory; + Alarms& m_alarms; + LocalSystemClockContextWriter& m_local_system_context_writer; + NetworkSystemClockContextWriter& m_network_system_context_writer; + EphemeralNetworkSystemClockContextWriter& m_ephemeral_system_context_writer; + OperationEvent m_local_operation; + OperationEvent m_network_operation; + OperationEvent m_ephemeral_operation; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/shared_memory.cpp b/src/core/hle/service/psc/time/shared_memory.cpp new file mode 100644 index 000000000..defaceebe --- /dev/null +++ b/src/core/hle/service/psc/time/shared_memory.cpp @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/service/psc/time/shared_memory.h" + +namespace Service::PSC::Time { +namespace { +template <typename T> +constexpr inline T ReadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { + while (true) { + // Get the counter. + auto counter = p->m_counter; + + // Get the value. + auto value = p->m_value[counter % 2]; + + // Fence memory. + std::atomic_thread_fence(std::memory_order_acquire); + + // Check that the counter matches. + if (counter == p->m_counter) { + return value; + } + } +} + +template <typename T> +constexpr inline void WriteToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { + // Get the current counter. + auto counter = p->m_counter; + + // Increment the counter. + ++counter; + + // Store the updated value. + p->m_value[counter % 2] = value; + + // Fence memory. + std::atomic_thread_fence(std::memory_order_release); + + // Set the updated counter. + p->m_counter = counter; +} +} // namespace + +SharedMemory::SharedMemory(Core::System& system) + : m_system{system}, m_k_shared_memory{m_system.Kernel().GetTimeSharedMem()}, + m_shared_memory_ptr{reinterpret_cast<SharedMemoryStruct*>(m_k_shared_memory.GetPointer())} { + std::memset(m_shared_memory_ptr, 0, sizeof(*m_shared_memory_ptr)); +} + +void SharedMemory::SetLocalSystemContext(SystemClockContext& context) { + WriteToLockFreeAtomicType(&m_shared_memory_ptr->local_system_clock_contexts, context); +} + +void SharedMemory::SetNetworkSystemContext(SystemClockContext& context) { + WriteToLockFreeAtomicType(&m_shared_memory_ptr->network_system_clock_contexts, context); +} + +void SharedMemory::SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_point) { + WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, + {time_point, clock_source_id}); +} + +void SharedMemory::SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point) { + WriteToLockFreeAtomicType(&m_shared_memory_ptr->continuous_adjustment_time_points, time_point); +} + +void SharedMemory::SetAutomaticCorrection(bool automatic_correction) { + WriteToLockFreeAtomicType(&m_shared_memory_ptr->automatic_corrections, automatic_correction); +} + +void SharedMemory::UpdateBaseTime(s64 time) { + SteadyClockTimePoint time_point{ + ReadFromLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points)}; + + time_point.time_point = time; + + WriteToLockFreeAtomicType(&m_shared_memory_ptr->steady_time_points, time_point); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/shared_memory.h b/src/core/hle/service/psc/time/shared_memory.h new file mode 100644 index 000000000..f9bf97d5c --- /dev/null +++ b/src/core/hle/service/psc/time/shared_memory.h @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/common_types.h" +#include "core/hle/service/psc/time/common.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KSharedMemory; +} + +namespace Service::PSC::Time { + +template <typename T> +struct LockFreeAtomicType { + u32 m_counter; + std::array<T, 2> m_value; +}; + +struct SharedMemoryStruct { + LockFreeAtomicType<SteadyClockTimePoint> steady_time_points; + LockFreeAtomicType<SystemClockContext> local_system_clock_contexts; + LockFreeAtomicType<SystemClockContext> network_system_clock_contexts; + LockFreeAtomicType<bool> automatic_corrections; + LockFreeAtomicType<ContinuousAdjustmentTimePoint> continuous_adjustment_time_points; + std::array<char, 0xEB8> pad0148; +}; +static_assert(offsetof(SharedMemoryStruct, steady_time_points) == 0x0, + "steady_time_points are in the wrong place!"); +static_assert(offsetof(SharedMemoryStruct, local_system_clock_contexts) == 0x38, + "local_system_clock_contexts are in the wrong place!"); +static_assert(offsetof(SharedMemoryStruct, network_system_clock_contexts) == 0x80, + "network_system_clock_contexts are in the wrong place!"); +static_assert(offsetof(SharedMemoryStruct, automatic_corrections) == 0xC8, + "automatic_corrections are in the wrong place!"); +static_assert(offsetof(SharedMemoryStruct, continuous_adjustment_time_points) == 0xD0, + "continuous_adjustment_time_points are in the wrong place!"); +static_assert(sizeof(SharedMemoryStruct) == 0x1000, + "Time's SharedMemoryStruct has the wrong size!"); +static_assert(std::is_trivial_v<SharedMemoryStruct>); + +class SharedMemory { +public: + explicit SharedMemory(Core::System& system); + + Kernel::KSharedMemory& GetKSharedMemory() { + return m_k_shared_memory; + } + + void SetLocalSystemContext(SystemClockContext& context); + void SetNetworkSystemContext(SystemClockContext& context); + void SetSteadyClockTimePoint(ClockSourceId clock_source_id, s64 time_diff); + void SetContinuousAdjustment(ContinuousAdjustmentTimePoint& time_point); + void SetAutomaticCorrection(bool automatic_correction); + void UpdateBaseTime(s64 time); + +private: + Core::System& m_system; + Kernel::KSharedMemory& m_k_shared_memory; + SharedMemoryStruct* m_shared_memory_ptr; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp new file mode 100644 index 000000000..6f8cf3f88 --- /dev/null +++ b/src/core/hle/service/psc/time/static.cpp @@ -0,0 +1,500 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" +#include "core/hle/service/psc/time/clocks/standard_user_system_clock_core.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/psc/time/shared_memory.h" +#include "core/hle/service/psc/time/static.h" +#include "core/hle/service/psc/time/steady_clock.h" +#include "core/hle/service/psc/time/system_clock.h" +#include "core/hle/service/psc/time/time_zone.h" +#include "core/hle/service/psc/time/time_zone_service.h" + +namespace Service::PSC::Time { +namespace { +constexpr Result GetTimeFromTimePointAndContext(s64* out_time, SteadyClockTimePoint& time_point, + SystemClockContext& context) { + R_UNLESS(out_time != nullptr, ResultInvalidArgument); + R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch); + + *out_time = context.offset + time_point.time_point; + R_SUCCEED(); +} +} // namespace + +StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup_info, + std::shared_ptr<TimeManager> time, const char* name) + : ServiceFramework{system_, name}, m_system{system}, m_setup_info{setup_info}, m_time{time}, + m_local_system_clock{m_time->m_standard_local_system_clock}, + m_user_system_clock{m_time->m_standard_user_system_clock}, + m_network_system_clock{m_time->m_standard_network_system_clock}, + m_time_zone{m_time->m_time_zone}, + m_ephemeral_network_clock{m_time->m_ephemeral_network_clock}, m_shared_memory{ + m_time->m_shared_memory} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, + {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, + {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, + {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, + {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, + {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, + {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, + {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, + {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, + {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, + {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, + {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, + {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, + {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, + {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, + {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, + {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, + {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, + {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +Result StaticService::GetClockSnapshotImpl(ClockSnapshot& out_snapshot, + SystemClockContext& user_context, + SystemClockContext& network_context, TimeType type) { + out_snapshot.user_context = user_context; + out_snapshot.network_context = network_context; + + R_TRY( + m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot.steady_clock_time_point)); + + out_snapshot.is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection(); + + R_TRY(m_time_zone.GetLocationName(out_snapshot.location_name)); + + R_TRY(GetTimeFromTimePointAndContext( + &out_snapshot.user_time, out_snapshot.steady_clock_time_point, out_snapshot.user_context)); + + R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.user_calendar_time, + out_snapshot.user_calendar_additional_time, + out_snapshot.user_time)); + + if (GetTimeFromTimePointAndContext(&out_snapshot.network_time, + out_snapshot.steady_clock_time_point, + out_snapshot.network_context) != ResultSuccess) { + out_snapshot.network_time = 0; + } + + R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.network_calendar_time, + out_snapshot.network_calendar_additional_time, + out_snapshot.network_time)); + out_snapshot.type = type; + out_snapshot.unk_CE = 0; + R_SUCCEED(); +} + +void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<SystemClock> service{}; + auto res = GetStandardUserSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<SystemClock> service{}; + auto res = GetStandardNetworkSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<SteadyClock> service{}; + auto res = GetStandardSteadyClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(service)); +} + +void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<TimeZoneService> service{}; + auto res = GetTimeZoneService(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface(std::move(service)); +} + +void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<SystemClock> service{}; + auto res = GetStandardLocalSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + std::shared_ptr<SystemClock> service{}; + auto res = GetEphemeralNetworkSystemClock(service); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(res); + rb.PushIpcInterface<SystemClock>(std::move(service)); +} + +void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KSharedMemory* shared_memory{}; + auto res = GetSharedMemoryNativeHandle(&shared_memory); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(shared_memory); +} + +void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(m_setup_info.can_write_steady_clock ? ResultNotImplemented : ResultPermissionDenied); +} + +void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + bool is_enabled{}; + auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push<bool>(is_enabled); +} + +void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto automatic_correction{rp.Pop<bool>()}; + + auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + bool is_sufficient{}; + auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push<bool>(is_sufficient); +} + +void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + SteadyClockTimePoint time_point{}; + auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<SteadyClockTimePoint>(time_point); +} + +void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<SystemClockContext>()}; + + s64 time{}; + auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push<s64>(time); +} + +void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto type{rp.PopEnum<TimeType>()}; + + ClockSnapshot snapshot{}; + auto res = GetClockSnapshot(snapshot, type); + + ctx.WriteBuffer(snapshot); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto clock_type{rp.PopEnum<TimeType>()}; + [[maybe_unused]] auto alignment{rp.Pop<u32>()}; + auto user_context{rp.PopRaw<SystemClockContext>()}; + auto network_context{rp.PopRaw<SystemClockContext>()}; + + ClockSnapshot snapshot{}; + auto res = + GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type); + + ctx.WriteBuffer(snapshot); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + ClockSnapshot a{}; + ClockSnapshot b{}; + + auto a_buffer{ctx.ReadBuffer(0)}; + auto b_buffer{ctx.ReadBuffer(1)}; + + std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot)); + std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot)); + + s64 difference{}; + auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(difference); +} + +void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + ClockSnapshot a{}; + ClockSnapshot b{}; + + auto a_buffer{ctx.ReadBuffer(0)}; + auto b_buffer{ctx.ReadBuffer(1)}; + + std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot)); + std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot)); + + s64 time{}; + auto res = CalculateSpanBetween(time, a, b); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(time); +} + +// =============================== Implementations =========================== + +Result StaticService::GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service) { + out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock, + m_setup_info.can_write_user_clock, + m_setup_info.can_write_uninitialized_clock); + R_SUCCEED(); +} + +Result StaticService::GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { + out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock, + m_setup_info.can_write_network_clock, + m_setup_info.can_write_uninitialized_clock); + R_SUCCEED(); +} + +Result StaticService::GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service) { + out_service = + std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock, + m_setup_info.can_write_uninitialized_clock); + R_SUCCEED(); +} + +Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { + out_service = + std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone, + m_setup_info.can_write_timezone_device_location); + R_SUCCEED(); +} + +Result StaticService::GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service) { + out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock, + m_setup_info.can_write_local_clock, + m_setup_info.can_write_uninitialized_clock); + R_SUCCEED(); +} + +Result StaticService::GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { + out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock, + m_setup_info.can_write_network_clock, + m_setup_info.can_write_uninitialized_clock); + R_SUCCEED(); +} + +Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { + *out_shared_memory = &m_shared_memory.GetKSharedMemory(); + R_SUCCEED(); +} + +Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled) { + R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); + + out_is_enabled = m_user_system_clock.GetAutomaticCorrection(); + R_SUCCEED(); +} + +Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( + bool automatic_correction) { + R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(), + ResultClockUninitialized); + R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied); + + R_TRY(m_user_system_clock.SetAutomaticCorrection(automatic_correction)); + + m_shared_memory.SetAutomaticCorrection(automatic_correction); + + SteadyClockTimePoint time_point{}; + R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point)); + + m_user_system_clock.SetTimePointAndSignal(time_point); + m_user_system_clock.GetEvent().Signal(); + R_SUCCEED(); +} + +Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { + out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); + R_SUCCEED(); +} + +Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + SteadyClockTimePoint& out_time_point) { + R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); + + m_user_system_clock.GetTimePoint(out_time_point); + + R_SUCCEED(); +} + +Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, + SystemClockContext& context) { + R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); + + SteadyClockTimePoint time_point{}; + R_TRY(m_time->m_standard_steady_clock.GetCurrentTimePoint(time_point)); + + R_UNLESS(time_point.IdMatches(context.steady_time_point), ResultClockMismatch); + + auto one_second_ns{ + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; + auto ticks{m_system.CoreTiming().GetClockTicks()}; + auto current_time{ConvertToTimeSpan(ticks).count()}; + out_time = ((context.offset + time_point.time_point) - (current_time / one_second_ns)); + R_SUCCEED(); +} + +Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type) { + SystemClockContext user_context{}; + R_TRY(m_user_system_clock.GetContext(user_context)); + + SystemClockContext network_context{}; + R_TRY(m_network_system_clock.GetContext(network_context)); + + R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); +} + +Result StaticService::GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, + SystemClockContext& user_context, + SystemClockContext& network_context, + TimeType type) { + R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); +} + +Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, + ClockSnapshot& a, + ClockSnapshot& b) { + auto diff_s = + std::chrono::seconds(b.user_context.offset) - std::chrono::seconds(a.user_context.offset); + + if (a.user_context == b.user_context || + !a.user_context.steady_time_point.IdMatches(b.user_context.steady_time_point)) { + out_time = 0; + R_SUCCEED(); + } + + if (!a.is_automatic_correction_enabled || !b.is_automatic_correction_enabled) { + out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); + R_SUCCEED(); + } + + if (a.network_context.steady_time_point.IdMatches(a.steady_clock_time_point) || + b.network_context.steady_time_point.IdMatches(b.steady_clock_time_point)) { + out_time = 0; + R_SUCCEED(); + } + + out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); + R_SUCCEED(); +} + +Result StaticService::CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b) { + s64 time_s{}; + auto res = + GetSpanBetweenTimePoints(&time_s, a.steady_clock_time_point, b.steady_clock_time_point); + + if (res != ResultSuccess) { + R_UNLESS(a.network_time != 0 && b.network_time != 0, ResultTimeNotFound); + time_s = b.network_time - a.network_time; + } + + out_time = + std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count(); + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/static.h b/src/core/hle/service/psc/time/static.h new file mode 100644 index 000000000..498cd5ab5 --- /dev/null +++ b/src/core/hle/service/psc/time/static.h @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KSharedMemory; +} + +namespace Service::PSC::Time { +class TimeManager; +class StandardLocalSystemClockCore; +class StandardUserSystemClockCore; +class StandardNetworkSystemClockCore; +class TimeZone; +class SystemClock; +class SteadyClock; +class TimeZoneService; +class EphemeralNetworkSystemClockCore; +class SharedMemory; + +class StaticService final : public ServiceFramework<StaticService> { +public: + explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info, + std::shared_ptr<TimeManager> time, const char* name); + + ~StaticService() override = default; + + Result GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service); + Result GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); + Result GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service); + Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); + Result GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service); + Result GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); + Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); + Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled); + Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); + Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); + Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( + SteadyClockTimePoint& out_time_point); + Result CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, SystemClockContext& context); + Result GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type); + Result GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, + SystemClockContext& user_context, + SystemClockContext& network_context, + TimeType type); + Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, ClockSnapshot& a, + ClockSnapshot& b); + Result CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b); + +private: + Result GetClockSnapshotImpl(ClockSnapshot& out_snapshot, SystemClockContext& user_context, + SystemClockContext& network_context, TimeType type); + + void Handle_GetStandardUserSystemClock(HLERequestContext& ctx); + void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx); + void Handle_GetStandardSteadyClock(HLERequestContext& ctx); + void Handle_GetTimeZoneService(HLERequestContext& ctx); + void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx); + void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx); + void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx); + void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx); + void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx); + void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx); + void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); + void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); + void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); + void Handle_GetClockSnapshot(HLERequestContext& ctx); + void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); + void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); + void Handle_CalculateSpanBetween(HLERequestContext& ctx); + + Core::System& m_system; + StaticServiceSetupInfo m_setup_info; + std::shared_ptr<TimeManager> m_time; + StandardLocalSystemClockCore& m_local_system_clock; + StandardUserSystemClockCore& m_user_system_clock; + StandardNetworkSystemClockCore& m_network_system_clock; + TimeZone& m_time_zone; + EphemeralNetworkSystemClockCore& m_ephemeral_network_clock; + SharedMemory& m_shared_memory; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp new file mode 100644 index 000000000..1ed5c7679 --- /dev/null +++ b/src/core/hle/service/psc/time/steady_clock.cpp @@ -0,0 +1,164 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/steady_clock.h" + +namespace Service::PSC::Time { + +SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> manager, + bool can_write_steady_clock, bool can_write_uninitialized_clock) + : ServiceFramework{system_, "ISteadyClock"}, m_system{system}, + m_clock_core{manager->m_standard_steady_clock}, + m_can_write_steady_clock{can_write_steady_clock}, m_can_write_uninitialized_clock{ + can_write_uninitialized_clock} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &SteadyClock::Handle_GetCurrentTimePoint, "GetCurrentTimePoint"}, + {2, &SteadyClock::Handle_GetTestOffset, "GetTestOffset"}, + {3, &SteadyClock::Handle_SetTestOffset, "SetTestOffset"}, + {100, &SteadyClock::Handle_GetRtcValue, "GetRtcValue"}, + {101, &SteadyClock::Handle_IsRtcResetDetected, "IsRtcResetDetected"}, + {102, &SteadyClock::Handle_GetSetupResultValue, "GetSetupResultValue"}, + {200, &SteadyClock::Handle_GetInternalOffset, "GetInternalOffset"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +void SteadyClock::Handle_GetCurrentTimePoint(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + SteadyClockTimePoint time_point{}; + auto res = GetCurrentTimePoint(time_point); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<SteadyClockTimePoint>(time_point); +} + +void SteadyClock::Handle_GetTestOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s64 test_offset{}; + auto res = GetTestOffset(test_offset); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(test_offset); +} + +void SteadyClock::Handle_SetTestOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto test_offset{rp.Pop<s64>()}; + + auto res = SetTestOffset(test_offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SteadyClock::Handle_GetRtcValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s64 rtc_value{}; + auto res = GetRtcValue(rtc_value); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(rtc_value); +} + +void SteadyClock::Handle_IsRtcResetDetected(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + bool reset_detected{false}; + auto res = IsRtcResetDetected(reset_detected); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(reset_detected); +} + +void SteadyClock::Handle_GetSetupResultValue(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Result result_value{ResultSuccess}; + auto res = GetSetupResultValue(result_value); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(result_value); +} + +void SteadyClock::Handle_GetInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s64 internal_offset{}; + auto res = GetInternalOffset(internal_offset); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(internal_offset); +} + +// =============================== Implementations =========================== + +Result SteadyClock::GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.GetCurrentTimePoint(out_time_point)); +} + +Result SteadyClock::GetTestOffset(s64& out_test_offset) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + out_test_offset = m_clock_core.GetTestOffset(); + R_SUCCEED(); +} + +Result SteadyClock::SetTestOffset(s64 test_offset) { + R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied); + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + m_clock_core.SetTestOffset(test_offset); + R_SUCCEED(); +} + +Result SteadyClock::GetRtcValue(s64& out_rtc_value) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.GetRtcValue(out_rtc_value)); +} + +Result SteadyClock::IsRtcResetDetected(bool& out_is_detected) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + out_is_detected = m_clock_core.IsResetDetected(); + R_SUCCEED(); +} + +Result SteadyClock::GetSetupResultValue(Result& out_result) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + out_result = m_clock_core.GetSetupResultValue(); + R_SUCCEED(); +} + +Result SteadyClock::GetInternalOffset(s64& out_internal_offset) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + out_internal_offset = m_clock_core.GetInternalOffset(); + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/steady_clock.h b/src/core/hle/service/psc/time/steady_clock.h new file mode 100644 index 000000000..115e9b138 --- /dev/null +++ b/src/core/hle/service/psc/time/steady_clock.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class SteadyClock final : public ServiceFramework<SteadyClock> { +public: + explicit SteadyClock(Core::System& system, std::shared_ptr<TimeManager> manager, + bool can_write_steady_clock, bool can_write_uninitialized_clock); + + ~SteadyClock() override = default; + + Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point); + Result GetTestOffset(s64& out_test_offset); + Result SetTestOffset(s64 test_offset); + Result GetRtcValue(s64& out_rtc_value); + Result IsRtcResetDetected(bool& out_is_detected); + Result GetSetupResultValue(Result& out_result); + Result GetInternalOffset(s64& out_internal_offset); + +private: + void Handle_GetCurrentTimePoint(HLERequestContext& ctx); + void Handle_GetTestOffset(HLERequestContext& ctx); + void Handle_SetTestOffset(HLERequestContext& ctx); + void Handle_GetRtcValue(HLERequestContext& ctx); + void Handle_IsRtcResetDetected(HLERequestContext& ctx); + void Handle_GetSetupResultValue(HLERequestContext& ctx); + void Handle_GetInternalOffset(HLERequestContext& ctx); + + Core::System& m_system; + + StandardSteadyClockCore& m_clock_core; + bool m_can_write_steady_clock; + bool m_can_write_uninitialized_clock; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp new file mode 100644 index 000000000..13d2f1d11 --- /dev/null +++ b/src/core/hle/service/psc/time/system_clock.cpp @@ -0,0 +1,127 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/hle/service/psc/time/system_clock.h" + +namespace Service::PSC::Time { + +SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, bool can_write_clock, + bool can_write_uninitialized_clock) + : ServiceFramework{system_, "ISystemClock"}, m_system{system}, m_clock_core{clock_core}, + m_can_write_clock{can_write_clock}, m_can_write_uninitialized_clock{ + can_write_uninitialized_clock} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &SystemClock::Handle_GetCurrentTime, "GetCurrentTime"}, + {1, &SystemClock::Handle_SetCurrentTime, "SetCurrentTime"}, + {2, &SystemClock::Handle_GetSystemClockContext, "GetSystemClockContext"}, + {3, &SystemClock::Handle_SetSystemClockContext, "SetSystemClockContext"}, + {4, &SystemClock::Handle_GetOperationEventReadableHandle, "GetOperationEventReadableHandle"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +void SystemClock::Handle_GetCurrentTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + s64 time{}; + auto res = GetCurrentTime(time); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push<s64>(time); +} + +void SystemClock::Handle_SetCurrentTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + auto res = SetCurrentTime(time); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SystemClock::Handle_GetSystemClockContext(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + SystemClockContext context{}; + auto res = GetSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(SystemClockContext) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<SystemClockContext>(context); +} + +void SystemClock::Handle_SetSystemClockContext(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<SystemClockContext>()}; + + auto res = SetSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SystemClock::Handle_GetOperationEventReadableHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + Kernel::KEvent* event{}; + auto res = GetOperationEventReadableHandle(&event); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(res); + rb.PushCopyObjects(event->GetReadableEvent()); +} + +// =============================== Implementations =========================== + +Result SystemClock::GetCurrentTime(s64& out_time) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.GetCurrentTime(&out_time)); +} + +Result SystemClock::SetCurrentTime(s64 time) { + R_UNLESS(m_can_write_clock, ResultPermissionDenied); + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.SetCurrentTime(time)); +} + +Result SystemClock::GetSystemClockContext(SystemClockContext& out_context) { + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.GetContext(out_context)); +} + +Result SystemClock::SetSystemClockContext(SystemClockContext& context) { + R_UNLESS(m_can_write_clock, ResultPermissionDenied); + R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), + ResultClockUninitialized); + + R_RETURN(m_clock_core.SetContextAndWrite(context)); +} + +Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event) { + if (!m_operation_event) { + m_operation_event = std::make_unique<OperationEvent>(m_system); + R_UNLESS(m_operation_event != nullptr, ResultFailed); + + m_clock_core.LinkOperationEvent(*m_operation_event); + } + + *out_event = m_operation_event->m_event; + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/system_clock.h b/src/core/hle/service/psc/time/system_clock.h new file mode 100644 index 000000000..f30027e7b --- /dev/null +++ b/src/core/hle/service/psc/time/system_clock.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::PSC::Time { + +class SystemClock final : public ServiceFramework<SystemClock> { +public: + explicit SystemClock(Core::System& system, SystemClockCore& system_clock_core, + bool can_write_clock, bool can_write_uninitialized_clock); + + ~SystemClock() override = default; + + Result GetCurrentTime(s64& out_time); + Result SetCurrentTime(s64 time); + Result GetSystemClockContext(SystemClockContext& out_context); + Result SetSystemClockContext(SystemClockContext& context); + Result GetOperationEventReadableHandle(Kernel::KEvent** out_event); + +private: + void Handle_GetCurrentTime(HLERequestContext& ctx); + void Handle_SetCurrentTime(HLERequestContext& ctx); + void Handle_GetSystemClockContext(HLERequestContext& ctx); + void Handle_SetSystemClockContext(HLERequestContext& ctx); + void Handle_GetOperationEventReadableHandle(HLERequestContext& ctx); + + Core::System& m_system; + + SystemClockCore& m_clock_core; + bool m_can_write_clock; + bool m_can_write_uninitialized_clock; + std::unique_ptr<OperationEvent> m_operation_event{}; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp new file mode 100644 index 000000000..cfee8f866 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone.cpp @@ -0,0 +1,280 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/psc/time/time_zone.h" + +namespace Service::PSC::Time { +namespace { +constexpr Result ValidateRule(Tz::Rule& rule) { + if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) || + rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) || + rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) { + R_RETURN(ResultTimeZoneOutOfRange); + } + + for (s32 i = 0; i < rule.timecnt; i++) { + if (rule.types[i] >= rule.typecnt) { + R_RETURN(ResultTimeZoneOutOfRange); + } + } + + for (s32 i = 0; i < rule.typecnt; i++) { + if (rule.ttis[i].tt_desigidx >= static_cast<s32>(rule.chars.size())) { + R_RETURN(ResultTimeZoneOutOfRange); + } + } + R_SUCCEED(); +} + +constexpr bool GetTimeZoneTime(s64& out_time, Tz::Rule& rule, s64 time, s32 index, + s32 index_offset) { + s32 found_idx{}; + s32 expected_index{index + index_offset}; + s64 time_to_find{time + rule.ttis[rule.types[index]].tt_utoff - + rule.ttis[rule.types[expected_index]].tt_utoff}; + + if (rule.timecnt > 1 && rule.ats[0] <= time_to_find) { + s32 low{1}; + s32 high{rule.timecnt}; + + while (low < high) { + auto mid{(low + high) / 2}; + if (rule.ats[mid] <= time_to_find) { + low = mid + 1; + } else if (rule.ats[mid] > time_to_find) { + high = mid; + } + } + found_idx = low - 1; + } + + if (found_idx == expected_index) { + out_time = time_to_find; + } + return found_idx == expected_index; +} +} // namespace + +void TimeZone::SetTimePoint(SteadyClockTimePoint& time_point) { + std::scoped_lock l{m_mutex}; + m_steady_clock_time_point = time_point; +} + +void TimeZone::SetTotalLocationNameCount(u32 count) { + std::scoped_lock l{m_mutex}; + m_total_location_name_count = count; +} + +void TimeZone::SetRuleVersion(RuleVersion& rule_version) { + std::scoped_lock l{m_mutex}; + m_rule_version = rule_version; +} + +Result TimeZone::GetLocationName(LocationName& out_name) { + std::scoped_lock l{m_mutex}; + R_UNLESS(m_initialized, ResultClockUninitialized); + out_name = m_location; + R_SUCCEED(); +} + +Result TimeZone::GetTotalLocationCount(u32& out_count) { + std::scoped_lock l{m_mutex}; + if (!m_initialized) { + return ResultClockUninitialized; + } + + out_count = m_total_location_name_count; + R_SUCCEED(); +} + +Result TimeZone::GetRuleVersion(RuleVersion& out_rule_version) { + std::scoped_lock l{m_mutex}; + if (!m_initialized) { + return ResultClockUninitialized; + } + out_rule_version = m_rule_version; + R_SUCCEED(); +} + +Result TimeZone::GetTimePoint(SteadyClockTimePoint& out_time_point) { + std::scoped_lock l{m_mutex}; + if (!m_initialized) { + return ResultClockUninitialized; + } + out_time_point = m_steady_clock_time_point; + R_SUCCEED(); +} + +Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, + Tz::Rule& rule) { + std::scoped_lock l{m_mutex}; + R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule)); +} + +Result TimeZone::ToCalendarTimeWithMyRule(CalendarTime& calendar_time, + CalendarAdditionalInfo& calendar_additional, s64 time) { + // This is checked outside the mutex. Bug? + if (!m_initialized) { + return ResultClockUninitialized; + } + + std::scoped_lock l{m_mutex}; + R_RETURN(ToCalendarTimeImpl(calendar_time, calendar_additional, time, m_my_rule)); +} + +Result TimeZone::ParseBinary(LocationName& name, std::span<const u8> binary) { + std::scoped_lock l{m_mutex}; + + Tz::Rule tmp_rule{}; + R_TRY(ParseBinaryImpl(tmp_rule, binary)); + + m_my_rule = tmp_rule; + m_location = name; + + R_SUCCEED(); +} + +Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary) { + std::scoped_lock l{m_mutex}; + R_RETURN(ParseBinaryImpl(out_rule, binary)); +} + +Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar, Tz::Rule& rule) { + std::scoped_lock l{m_mutex}; + + auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1); + + if (res != ResultSuccess) { + if (res == ResultTimeZoneNotFound) { + res = ResultSuccess; + out_count = 0; + } + } else if (out_count == 2 && out_times[0] > out_times[1]) { + std::swap(out_times[0], out_times[1]); + } + R_RETURN(res); +} + +Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, + u32 out_times_count, CalendarTime& calendar) { + std::scoped_lock l{m_mutex}; + + auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1); + + if (res != ResultSuccess) { + if (res == ResultTimeZoneNotFound) { + res = ResultSuccess; + out_count = 0; + } + } else if (out_count == 2 && out_times[0] > out_times[1]) { + std::swap(out_times[0], out_times[1]); + } + R_RETURN(res); +} + +Result TimeZone::ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary) { + if (Tz::ParseTimeZoneBinary(out_rule, binary)) { + R_RETURN(ResultTimeZoneParseFailed); + } + R_SUCCEED(); +} + +Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, + Tz::Rule& rule) { + R_TRY(ValidateRule(rule)); + + Tz::CalendarTimeInternal calendar_internal{}; + time_t time_tmp{static_cast<time_t>(time)}; + if (Tz::localtime_rz(&calendar_internal, &rule, &time_tmp)) { + R_RETURN(ResultOverflow); + } + + out_calendar_time.year = static_cast<s16>(calendar_internal.tm_year + 1900); + out_calendar_time.month = static_cast<s8>(calendar_internal.tm_mon + 1); + out_calendar_time.day = static_cast<s8>(calendar_internal.tm_mday); + out_calendar_time.hour = static_cast<s8>(calendar_internal.tm_hour); + out_calendar_time.minute = static_cast<s8>(calendar_internal.tm_min); + out_calendar_time.second = static_cast<s8>(calendar_internal.tm_sec); + + out_additional_info.day_of_week = calendar_internal.tm_wday; + out_additional_info.day_of_year = calendar_internal.tm_yday; + + std::memcpy(out_additional_info.name.data(), calendar_internal.tm_zone.data(), + out_additional_info.name.size()); + out_additional_info.name[out_additional_info.name.size() - 1] = '\0'; + + out_additional_info.is_dst = calendar_internal.tm_isdst; + out_additional_info.ut_offset = calendar_internal.tm_utoff; + + R_SUCCEED(); +} + +Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar, Tz::Rule& rule, s32 is_dst) { + R_TRY(ValidateRule(rule)); + + calendar.month -= 1; + calendar.year -= 1900; + + Tz::CalendarTimeInternal internal{ + .tm_sec = calendar.second, + .tm_min = calendar.minute, + .tm_hour = calendar.hour, + .tm_mday = calendar.day, + .tm_mon = calendar.month, + .tm_year = calendar.year, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = is_dst, + .tm_zone = {}, + .tm_utoff = 0, + .time_index = 0, + }; + time_t time_tmp{}; + auto res = Tz::mktime_tzname(&time_tmp, &rule, &internal); + s64 time = static_cast<s64>(time_tmp); + + if (res == 1) { + R_RETURN(ResultOverflow); + } else if (res == 2) { + R_RETURN(ResultTimeZoneNotFound); + } + + if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute || + internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day || + internal.tm_mon != calendar.month || internal.tm_year != calendar.year) { + R_RETURN(ResultTimeZoneNotFound); + } + + if (res != 0) { + ASSERT(false); + } + + out_times[0] = time; + if (out_times_count < 2) { + out_count = 1; + R_SUCCEED(); + } + + s64 time2{}; + if (internal.time_index > 0 && GetTimeZoneTime(time2, rule, time, internal.time_index, -1)) { + out_times[1] = time2; + out_count = 2; + R_SUCCEED(); + } + + if (((internal.time_index + 1) < rule.timecnt) && + GetTimeZoneTime(time2, rule, time, internal.time_index, 1)) { + out_times[1] = time2; + out_count = 2; + R_SUCCEED(); + } + + out_count = 1; + R_SUCCEED(); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h new file mode 100644 index 000000000..ce2acca17 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone.h @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <mutex> +#include <span> + +#include <tz/tz.h> +#include "core/hle/service/psc/time/common.h" + +namespace Service::PSC::Time { + +class TimeZone { +public: + TimeZone() = default; + + bool IsInitialized() const { + return m_initialized; + } + + void SetInitialized() { + m_initialized = true; + } + + void SetTimePoint(SteadyClockTimePoint& time_point); + void SetTotalLocationNameCount(u32 count); + void SetRuleVersion(RuleVersion& rule_version); + Result GetLocationName(LocationName& out_name); + Result GetTotalLocationCount(u32& out_count); + Result GetRuleVersion(RuleVersion& out_rule_version); + Result GetTimePoint(SteadyClockTimePoint& out_time_point); + + Result ToCalendarTime(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); + Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time, + CalendarAdditionalInfo& calendar_additional, s64 time); + Result ParseBinary(LocationName& name, std::span<const u8> binary); + Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary); + Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar, Tz::Rule& rule); + Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar); + +private: + Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary); + Result ToCalendarTimeImpl(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, + Tz::Rule& rule); + Result ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar, Tz::Rule& rule, s32 is_dst); + + bool m_initialized{}; + std::recursive_mutex m_mutex; + LocationName m_location{}; + Tz::Rule m_my_rule{}; + SteadyClockTimePoint m_steady_clock_time_point{}; + u32 m_total_location_name_count{}; + RuleVersion m_rule_version{}; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp new file mode 100644 index 000000000..e304c8387 --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone_service.cpp @@ -0,0 +1,289 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <tz/tz.h> +#include "core/core.h" +#include "core/hle/service/psc/time/time_zone_service.h" + +namespace Service::PSC::Time { + +TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore& clock_core, + TimeZone& time_zone, bool can_write_timezone_device_location) + : ServiceFramework{system_, "ITimeZoneService"}, m_system{system}, m_clock_core{clock_core}, + m_time_zone{time_zone}, m_can_write_timezone_device_location{ + can_write_timezone_device_location} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, + {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, + {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, + {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, + {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, + {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, + {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, + {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, + {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, + {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, + {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, + {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, + {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, + {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, + }; + // clang-format on + RegisterHandlers(functions); +} + +void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + LocationName name{}; + auto res = GetDeviceLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(LocationName) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<LocationName>(name); +} + +void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + [[maybe_unused]] auto name{rp.PopRaw<LocationName>()}; + + if (!m_can_write_timezone_device_location) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultPermissionDenied); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + u32 count{}; + auto res = GetTotalLocationNameCount(count); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + RuleVersion rule_version{}; + auto res = GetTimeZoneRuleVersion(rule_version); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(RuleVersion) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<RuleVersion>(rule_version); +} + +void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + LocationName name{}; + SteadyClockTimePoint time_point{}; + auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name); + + IPC::ResponseBuilder rb{ctx, 2 + (sizeof(LocationName) / sizeof(u32)) + + (sizeof(SteadyClockTimePoint) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<LocationName>(name); + rb.PushRaw<SteadyClockTimePoint>(time_point); +} + +void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto name{rp.PopRaw<LocationName>()}; + + auto binary{ctx.ReadBuffer()}; + auto res = SetDeviceLocationNameWithTimeZoneRule(name, binary); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + auto binary{ctx.ReadBuffer()}; + + Tz::Rule rule{}; + auto res = ParseTimeZoneBinary(rule, binary); + + ctx.WriteBuffer(rule); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( + HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNotImplemented); +} + +void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + auto rule_buffer{ctx.ReadBuffer()}; + Tz::Rule rule{}; + std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule)); + + CalendarTime calendar_time{}; + CalendarAdditionalInfo additional_info{}; + auto res = ToCalendarTime(calendar_time, additional_info, time, rule); + + IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) + + (sizeof(CalendarAdditionalInfo) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<CalendarTime>(calendar_time); + rb.PushRaw<CalendarAdditionalInfo>(additional_info); +} + +void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto time{rp.Pop<s64>()}; + + CalendarTime calendar_time{}; + CalendarAdditionalInfo additional_info{}; + auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time); + + IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) + + (sizeof(CalendarAdditionalInfo) / sizeof(u32))}; + rb.Push(res); + rb.PushRaw<CalendarTime>(calendar_time); + rb.PushRaw<CalendarAdditionalInfo>(additional_info); +} + +void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto calendar{rp.PopRaw<CalendarTime>()}; + + auto binary{ctx.ReadBuffer()}; + + Tz::Rule rule{}; + std::memcpy(&rule, binary.data(), sizeof(Tz::Rule)); + + u32 count{}; + std::array<s64, 2> times{}; + u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; + + auto res = ToPosixTime(count, times, times_count, calendar, rule); + + ctx.WriteBuffer(times); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { + LOG_DEBUG(Service_Time, "called."); + + IPC::RequestParser rp{ctx}; + auto calendar{rp.PopRaw<CalendarTime>()}; + + u32 count{}; + std::array<s64, 2> times{}; + u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))}; + + auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar); + + ctx.WriteBuffer(times); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.Push(count); +} + +// =============================== Implementations =========================== + +Result TimeZoneService::GetDeviceLocationName(LocationName& out_location_name) { + R_RETURN(m_time_zone.GetLocationName(out_location_name)); +} + +Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { + R_RETURN(m_time_zone.GetTotalLocationCount(out_count)); +} + +Result TimeZoneService::GetTimeZoneRuleVersion(RuleVersion& out_rule_version) { + R_RETURN(m_time_zone.GetRuleVersion(out_rule_version)); +} + +Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point, + LocationName& location_name) { + R_TRY(m_time_zone.GetLocationName(location_name)); + R_RETURN(m_time_zone.GetTimePoint(out_time_point)); +} + +Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, + std::span<const u8> binary) { + R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied); + R_TRY(m_time_zone.ParseBinary(location_name, binary)); + + SteadyClockTimePoint time_point{}; + R_TRY(m_clock_core.GetCurrentTimePoint(time_point)); + + m_time_zone.SetTimePoint(time_point); + R_SUCCEED(); +} + +Result TimeZoneService::ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary) { + R_RETURN(m_time_zone.ParseBinaryInto(out_rule, binary)); +} + +Result TimeZoneService::ToCalendarTime(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, + Tz::Rule& rule) { + R_RETURN(m_time_zone.ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); +} + +Result TimeZoneService::ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, + s64 time) { + R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); +} + +Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, + u32 out_times_count, CalendarTime& calendar_time, + Tz::Rule& rule) { + R_RETURN(m_time_zone.ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); +} + +Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, + u32 out_times_count, CalendarTime& calendar_time) { + R_RETURN( + m_time_zone.ToPosixTimeWithMyRule(out_count, out_times, out_times_count, calendar_time)); +} + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/psc/time/time_zone_service.h b/src/core/hle/service/psc/time/time_zone_service.h new file mode 100644 index 000000000..074c1d4ae --- /dev/null +++ b/src/core/hle/service/psc/time/time_zone_service.h @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/psc/time/manager.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Tz { +struct Rule; +} + +namespace Service::PSC::Time { + +class TimeZoneService final : public ServiceFramework<TimeZoneService> { +public: + explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core, + TimeZone& time_zone, bool can_write_timezone_device_location); + + ~TimeZoneService() override = default; + + Result GetDeviceLocationName(LocationName& out_location_name); + Result GetTotalLocationNameCount(u32& out_count); + Result GetTimeZoneRuleVersion(RuleVersion& out_rule_version); + Result GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point, + LocationName& location_name); + Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, + std::span<const u8> binary); + Result ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary); + Result ToCalendarTime(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); + Result ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time, + CalendarAdditionalInfo& out_additional_info, s64 time); + Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar_time, Tz::Rule& rule); + Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, + CalendarTime& calendar_time); + +private: + void Handle_GetDeviceLocationName(HLERequestContext& ctx); + void Handle_SetDeviceLocationName(HLERequestContext& ctx); + void Handle_GetTotalLocationNameCount(HLERequestContext& ctx); + void Handle_LoadLocationNameList(HLERequestContext& ctx); + void Handle_LoadTimeZoneRule(HLERequestContext& ctx); + void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx); + void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx); + void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx); + void Handle_ParseTimeZoneBinary(HLERequestContext& ctx); + void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx); + void Handle_ToCalendarTime(HLERequestContext& ctx); + void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx); + void Handle_ToPosixTime(HLERequestContext& ctx); + void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx); + + Core::System& m_system; + + StandardSteadyClockCore& m_clock_core; + TimeZone& m_time_zone; + bool m_can_write_timezone_device_location; +}; + +} // namespace Service::PSC::Time diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp index f0658bb5d..51196170a 100644 --- a/src/core/hle/service/ro/ro.cpp +++ b/src/core/hle/service/ro/ro.cpp @@ -6,13 +6,13 @@ #include "common/scope_exit.h" #include "core/hle/kernel/k_process.h" +#include "core/hle/service/cmif_serialization.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ro/ro.h" #include "core/hle/service/ro/ro_nro_utils.h" #include "core/hle/service/ro/ro_results.h" #include "core/hle/service/ro/ro_types.h" #include "core/hle/service/server_manager.h" -#include "core/hle/service/service.h" namespace Service::RO { @@ -500,46 +500,64 @@ private: } }; -class RoInterface { +class RoInterface : public ServiceFramework<RoInterface> { public: - explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind) - : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {} + explicit RoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro, + NrrKind nrr_kind) + : ServiceFramework{system_, name_}, m_ro(ro), m_context_id(InvalidContextId), + m_nrr_kind(nrr_kind) { + + // clang-format off + static const FunctionInfo functions[] = { + {0, C<&RoInterface::MapManualLoadModuleMemory>, "MapManualLoadModuleMemory"}, + {1, C<&RoInterface::UnmapManualLoadModuleMemory>, "UnmapManualLoadModuleMemory"}, + {2, C<&RoInterface::RegisterModuleInfo>, "RegisterModuleInfo"}, + {3, C<&RoInterface::UnregisterModuleInfo>, "UnregisterModuleInfo"}, + {4, C<&RoInterface::RegisterProcessHandle>, "RegisterProcessHandle"}, + {10, C<&RoInterface::RegisterProcessModuleInfo>, "RegisterProcessModuleInfo"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + ~RoInterface() { m_ro->UnregisterProcess(m_context_id); } - Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address, - u64 nro_size, u64 bss_address, u64 bss_size) { - R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); - R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address, + Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid, + u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) { + R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); + R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address, nro_size, bss_address, bss_size)); } - Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) { - R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + Result UnmapManualLoadModuleMemory(ClientProcessId client_pid, u64 nro_address) { + R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address)); } - Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) { - R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + Result RegisterModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size) { + R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); R_RETURN( m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true)); } - Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) { - R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + Result UnregisterModuleInfo(ClientProcessId client_pid, u64 nrr_address) { + R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address)); } - Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) { + Result RegisterProcessHandle(ClientProcessId client_pid, + InCopyHandle<Kernel::KProcess>& process) { // Register the process. - R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid)); + R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process.Get(), *client_pid)); } - Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size, - Kernel::KProcess* process) { + Result RegisterProcessModuleInfo(ClientProcessId client_pid, u64 nrr_address, u64 nrr_size, + InCopyHandle<Kernel::KProcess>& process) { // Validate the process. - R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid)); // Register the module. R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind, @@ -552,137 +570,6 @@ private: NrrKind m_nrr_kind{}; }; -class IRoInterface : public ServiceFramework<IRoInterface> { -public: - explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro, - NrrKind nrr_kind) - : ServiceFramework{system_, name_}, interface { - ro, nrr_kind - } { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"}, - {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"}, - {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"}, - {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"}, - {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"}, - {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void MapManualLoadModuleMemory(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - struct InputParameters { - u64 client_pid; - u64 nro_address; - u64 nro_size; - u64 bss_address; - u64 bss_size; - }; - - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<InputParameters>(); - - u64 load_address = 0; - auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(), - params.nro_address, params.nro_size, - params.bss_address, params.bss_size); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(result); - rb.Push(load_address); - } - - void UnmapManualLoadModuleMemory(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - struct InputParameters { - u64 client_pid; - u64 nro_address; - }; - - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<InputParameters>(); - auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - void RegisterModuleInfo(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - struct InputParameters { - u64 client_pid; - u64 nrr_address; - u64 nrr_size; - }; - - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<InputParameters>(); - auto result = - interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - void UnregisterModuleInfo(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - struct InputParameters { - u64 client_pid; - u64 nrr_address; - }; - - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<InputParameters>(); - auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - void RegisterProcessHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); - auto client_pid = ctx.GetPID(); - auto result = interface.RegisterProcessHandle(client_pid, process.GetPointerUnsafe()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - void RegisterProcessModuleInfo(HLERequestContext& ctx) { - LOG_DEBUG(Service_LDR, "(called)"); - - struct InputParameters { - u64 client_pid; - u64 nrr_address; - u64 nrr_size; - }; - - IPC::RequestParser rp{ctx}; - auto params = rp.PopRaw<InputParameters>(); - auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0)); - - auto client_pid = ctx.GetPID(); - auto result = interface.RegisterProcessModuleInfo( - client_pid, params.nrr_address, params.nrr_size, process.GetPointerUnsafe()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - RoInterface interface; -}; - } // namespace void LoopProcess(Core::System& system) { @@ -691,11 +578,11 @@ void LoopProcess(Core::System& system) { auto ro = std::make_shared<RoContext>(); const auto RoInterfaceFactoryForUser = [&, ro] { - return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User); + return std::make_shared<RoInterface>(system, "ldr:ro", ro, NrrKind::User); }; const auto RoInterfaceFactoryForJitPlugin = [&, ro] { - return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); + return std::make_shared<RoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); }; server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser)); diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 15edb23e0..8ef49387d 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp @@ -256,8 +256,13 @@ Result ServerManager::WaitAndProcessImpl() { // Wait for a signal. s32 out_index{-1}; - R_TRY(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(), - num_objs, -1)); + R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, + wait_objs.data(), num_objs, -1)) { + R_CATCH(Kernel::ResultSessionClosed) { + // On session closed, index is updated and we don't want to return an error. + } + } + R_END_TRY_CATCH; ASSERT(out_index >= 0 && out_index < num_objs); // Set the output index. diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 39124c5fd..06cbad268 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -66,7 +66,6 @@ #include "core/hle/service/sockets/sockets.h" #include "core/hle/service/spl/spl_module.h" #include "core/hle/service/ssl/ssl.h" -#include "core/hle/service/time/time.h" #include "core/hle/service/usb/usb.h" #include "core/hle/service/vi/vi.h" #include "core/reporter.h" @@ -246,6 +245,9 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); }); + // glue depends on settings and psc, so they must come first + kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); + kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); }); @@ -269,13 +271,10 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); - kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); - kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); - kernel.RunOnGuestCoreProcess("time", [&] { Time::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); }); // clang-format on } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index d539ed0f4..22d1343d5 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -206,6 +206,22 @@ protected: RegisterHandlersBaseTipc(functions, n); } +protected: + template <bool Domain, auto F> + void CmifReplyWrap(HLERequestContext& ctx); + + /** + * Wraps the template pointer-to-member function for use in a domain session. + */ + template <auto F> + static constexpr HandlerFnP<Self> D = &Self::template CmifReplyWrap<true, F>; + + /** + * Wraps the template pointer-to-member function for use in a non-domain session. + */ + template <auto F> + static constexpr HandlerFnP<Self> C = &Self::template CmifReplyWrap<false, F>; + private: /** * This function is used to allow invocation of pointers to handlers stored in the base class diff --git a/src/core/hle/service/set/appln_settings.cpp b/src/core/hle/service/set/appln_settings.cpp deleted file mode 100644 index a5d802757..000000000 --- a/src/core/hle/service/set/appln_settings.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/appln_settings.h" - -namespace Service::Set { - -ApplnSettings DefaultApplnSettings() { - return {}; -} - -} // namespace Service::Set diff --git a/src/core/hle/service/set/appln_settings.h b/src/core/hle/service/set/appln_settings.h deleted file mode 100644 index 126375860..000000000 --- a/src/core/hle/service/set/appln_settings.h +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <cstddef> - -#include "common/common_types.h" - -namespace Service::Set { -struct ApplnSettings { - std::array<u8, 0x10> reserved_000; - - // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0 - std::array<u8, 0x10> mii_author_id; - - std::array<u8, 0x30> reserved_020; - - // nn::settings::system::ServiceDiscoveryControlSettings - std::array<u8, 0x4> service_discovery_control_settings; - - std::array<u8, 0x20> reserved_054; - - bool in_repair_process_enable_flag; - - std::array<u8, 0x3> pad_075; -}; -static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10); -static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50); -static_assert(offsetof(ApplnSettings, in_repair_process_enable_flag) == 0x74); -static_assert(sizeof(ApplnSettings) == 0x78, "ApplnSettings has the wrong size!"); - -ApplnSettings DefaultApplnSettings(); - -} // namespace Service::Set diff --git a/src/core/hle/service/set/device_settings.cpp b/src/core/hle/service/set/device_settings.cpp deleted file mode 100644 index e423ce38a..000000000 --- a/src/core/hle/service/set/device_settings.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/device_settings.h" - -namespace Service::Set { - -DeviceSettings DefaultDeviceSettings() { - return {}; -} - -} // namespace Service::Set diff --git a/src/core/hle/service/set/device_settings.h b/src/core/hle/service/set/device_settings.h deleted file mode 100644 index f291d0ebe..000000000 --- a/src/core/hle/service/set/device_settings.h +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <cstddef> - -#include "common/common_types.h" - -namespace Service::Set { -struct DeviceSettings { - std::array<u8, 0x10> reserved_000; - - // nn::settings::BatteryLot - std::array<u8, 0x18> ptm_battery_lot; - // nn::settings::system::PtmFuelGaugeParameter - std::array<u8, 0x18> ptm_fuel_gauge_parameter; - u8 ptm_battery_version; - // nn::settings::system::PtmCycleCountReliability - u32 ptm_cycle_count_reliability; - - std::array<u8, 0x48> reserved_048; - - // nn::settings::system::AnalogStickUserCalibration L - std::array<u8, 0x10> analog_user_stick_calibration_l; - // nn::settings::system::AnalogStickUserCalibration R - std::array<u8, 0x10> analog_user_stick_calibration_r; - - std::array<u8, 0x20> reserved_0B0; - - // nn::settings::system::ConsoleSixAxisSensorAccelerationBias - std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias - std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; - // nn::settings::system::ConsoleSixAxisSensorAccelerationGain - std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain - std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias - std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; - // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration - std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration; -}; -static_assert(offsetof(DeviceSettings, ptm_battery_lot) == 0x10); -static_assert(offsetof(DeviceSettings, ptm_cycle_count_reliability) == 0x44); -static_assert(offsetof(DeviceSettings, analog_user_stick_calibration_l) == 0x90); -static_assert(offsetof(DeviceSettings, console_six_axis_sensor_acceleration_bias) == 0xD0); -static_assert(offsetof(DeviceSettings, console_six_axis_sensor_angular_acceleration) == 0x13C); -static_assert(sizeof(DeviceSettings) == 0x160, "DeviceSettings has the wrong size!"); - -DeviceSettings DefaultDeviceSettings(); - -} // namespace Service::Set diff --git a/src/core/hle/service/set/factory_settings_server.cpp b/src/core/hle/service/set/factory_settings_server.cpp new file mode 100644 index 000000000..a8e307ae2 --- /dev/null +++ b/src/core/hle/service/set/factory_settings_server.cpp @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/factory_settings_server.h" + +namespace Service::Set { + +IFactorySettingsServer::IFactorySettingsServer(Core::System& system_) + : ServiceFramework{system_, "set:cal"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetBluetoothBdAddress"}, + {1, nullptr, "GetConfigurationId1"}, + {2, nullptr, "GetAccelerometerOffset"}, + {3, nullptr, "GetAccelerometerScale"}, + {4, nullptr, "GetGyroscopeOffset"}, + {5, nullptr, "GetGyroscopeScale"}, + {6, nullptr, "GetWirelessLanMacAddress"}, + {7, nullptr, "GetWirelessLanCountryCodeCount"}, + {8, nullptr, "GetWirelessLanCountryCodes"}, + {9, nullptr, "GetSerialNumber"}, + {10, nullptr, "SetInitialSystemAppletProgramId"}, + {11, nullptr, "SetOverlayDispProgramId"}, + {12, nullptr, "GetBatteryLot"}, + {14, nullptr, "GetEciDeviceCertificate"}, + {15, nullptr, "GetEticketDeviceCertificate"}, + {16, nullptr, "GetSslKey"}, + {17, nullptr, "GetSslCertificate"}, + {18, nullptr, "GetGameCardKey"}, + {19, nullptr, "GetGameCardCertificate"}, + {20, nullptr, "GetEciDeviceKey"}, + {21, nullptr, "GetEticketDeviceKey"}, + {22, nullptr, "GetSpeakerParameter"}, + {23, nullptr, "GetLcdVendorId"}, + {24, nullptr, "GetEciDeviceCertificate2"}, + {25, nullptr, "GetEciDeviceKey2"}, + {26, nullptr, "GetAmiiboKey"}, + {27, nullptr, "GetAmiiboEcqvCertificate"}, + {28, nullptr, "GetAmiiboEcdsaCertificate"}, + {29, nullptr, "GetAmiiboEcqvBlsKey"}, + {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, + {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, + {32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"}, + {33, nullptr, "GetAnalogStickModuleTypeL"}, + {34, nullptr, "GetAnalogStickModelParameterL"}, + {35, nullptr, "GetAnalogStickFactoryCalibrationL"}, + {36, nullptr, "GetAnalogStickModuleTypeR"}, + {37, nullptr, "GetAnalogStickModelParameterR"}, + {38, nullptr, "GetAnalogStickFactoryCalibrationR"}, + {39, nullptr, "GetConsoleSixAxisSensorModuleType"}, + {40, nullptr, "GetConsoleSixAxisSensorHorizontalOffset"}, + {41, nullptr, "GetBatteryVersion"}, + {42, nullptr, "GetDeviceId"}, + {43, nullptr, "GetConsoleSixAxisSensorMountType"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IFactorySettingsServer::~IFactorySettingsServer() = default; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/factory_settings_server.h b/src/core/hle/service/set/factory_settings_server.h new file mode 100644 index 000000000..e64cd1380 --- /dev/null +++ b/src/core/hle/service/set/factory_settings_server.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::Set { + +class IFactorySettingsServer final : public ServiceFramework<IFactorySettingsServer> { +public: + explicit IFactorySettingsServer(Core::System& system_); + ~IFactorySettingsServer() override; +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/firmware_debug_settings_server.cpp b/src/core/hle/service/set/firmware_debug_settings_server.cpp new file mode 100644 index 000000000..b3a5e623b --- /dev/null +++ b/src/core/hle/service/set/firmware_debug_settings_server.cpp @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/firmware_debug_settings_server.h" + +namespace Service::Set { + +IFirmwareDebugSettingsServer::IFirmwareDebugSettingsServer(Core::System& system_) + : ServiceFramework{system_, "set:fd"} { + // clang-format off + static const FunctionInfo functions[] = { + {2, nullptr, "SetSettingsItemValue"}, + {3, nullptr, "ResetSettingsItemValue"}, + {4, nullptr, "CreateSettingsItemKeyIterator"}, + {10, nullptr, "ReadSettings"}, + {11, nullptr, "ResetSettings"}, + {20, nullptr, "SetWebInspectorFlag"}, + {21, nullptr, "SetAllowedSslHosts"}, + {22, nullptr, "SetHostFsMountPoint"}, + {23, nullptr, "SetMemoryUsageRateFlag"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +IFirmwareDebugSettingsServer::~IFirmwareDebugSettingsServer() = default; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/firmware_debug_settings_server.h b/src/core/hle/service/set/firmware_debug_settings_server.h new file mode 100644 index 000000000..5dae2263e --- /dev/null +++ b/src/core/hle/service/set/firmware_debug_settings_server.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" + +namespace Core { +class System; +} + +namespace Service::Set { + +class IFirmwareDebugSettingsServer final : public ServiceFramework<IFirmwareDebugSettingsServer> { +public: + explicit IFirmwareDebugSettingsServer(Core::System& system_); + ~IFirmwareDebugSettingsServer() override; +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/private_settings.cpp b/src/core/hle/service/set/private_settings.cpp deleted file mode 100644 index 70bf65727..000000000 --- a/src/core/hle/service/set/private_settings.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/private_settings.h" - -namespace Service::Set { - -PrivateSettings DefaultPrivateSettings() { - return {}; -} - -} // namespace Service::Set diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h index b63eaf45c..b02291ce7 100644 --- a/src/core/hle/service/set/private_settings.h +++ b/src/core/hle/service/set/private_settings.h @@ -9,7 +9,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/uuid.h" -#include "core/hle/service/time/clock_types.h" +#include "core/hle/service/psc/time/common.h" namespace Service::Set { @@ -29,14 +29,14 @@ static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid s struct InitialLaunchSettings { InitialLaunchFlag flags; INSERT_PADDING_BYTES(0x4); - Service::Time::Clock::SteadyClockTimePoint timestamp; + Service::PSC::Time::SteadyClockTimePoint timestamp; }; static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); #pragma pack(push, 4) struct InitialLaunchSettingsPacked { InitialLaunchFlag flags; - Service::Time::Clock::SteadyClockTimePoint timestamp; + Service::PSC::Time::SteadyClockTimePoint timestamp; }; #pragma pack(pop) static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp deleted file mode 100644 index 2082b8ef7..000000000 --- a/src/core/hle/service/set/set.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include <array> -#include <chrono> -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/set/set.h" - -namespace Service::Set { -namespace { -constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF; -constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40; - -constexpr Result ResultInvalidLanguage{ErrorModule::Settings, 625}; - -void PushResponseLanguageCode(HLERequestContext& ctx, std::size_t num_language_codes) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(num_language_codes)); -} - -void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entries) { - const std::size_t requested_amount = ctx.GetWriteBufferNumElements<LanguageCode>(); - const std::size_t max_amount = std::min(requested_amount, max_entries); - const std::size_t copy_amount = std::min(available_language_codes.size(), max_amount); - const std::size_t copy_size = copy_amount * sizeof(LanguageCode); - - ctx.WriteBuffer(available_language_codes.data(), copy_size); - PushResponseLanguageCode(ctx, copy_amount); -} - -void GetKeyCodeMapImpl(HLERequestContext& ctx) { - const auto language_code = - available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]; - const auto key_code = - std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), - [=](const auto& element) { return element.first == language_code; }); - KeyboardLayout layout = KeyboardLayout::EnglishUs; - if (key_code == language_to_layout.cend()) { - LOG_ERROR(Service_SET, - "Could not find keyboard layout for language index {}, defaulting to English us", - Settings::values.language_index.GetValue()); - } else { - layout = key_code->second; - } - - ctx.WriteBuffer(layout); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} -} // Anonymous namespace - -LanguageCode GetLanguageCodeFromIndex(std::size_t index) { - return available_language_codes.at(index); -} - -void SET::GetAvailableLanguageCodes(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES); -} - -void SET::MakeLanguageCode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto index = rp.Pop<u32>(); - - if (index >= available_language_codes.size()) { - LOG_ERROR(Service_SET, "Invalid language code index! index={}", index); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(Set::ResultInvalidLanguage); - return; - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushEnum(available_language_codes[index]); -} - -void SET::GetAvailableLanguageCodes2(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES); -} - -void SET::GetAvailableLanguageCodeCount(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES); -} - -void SET::GetAvailableLanguageCodeCount2(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES); -} - -void SET::GetQuestFlag(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue())); -} - -void SET::GetLanguageCode(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue()); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.PushEnum( - available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]); -} - -void SET::GetRegionCode(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(Settings::values.region_index.GetValue())); -} - -void SET::GetKeyCodeMap(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); - GetKeyCodeMapImpl(ctx); -} - -void SET::GetKeyCodeMap2(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); - GetKeyCodeMapImpl(ctx); -} - -void SET::GetDeviceNickName(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - ctx.WriteBuffer(Settings::values.device_name.GetValue()); -} - -SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &SET::GetLanguageCode, "GetLanguageCode"}, - {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, - {2, &SET::MakeLanguageCode, "MakeLanguageCode"}, - {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, - {4, &SET::GetRegionCode, "GetRegionCode"}, - {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, - {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, - {7, &SET::GetKeyCodeMap, "GetKeyCodeMap"}, - {8, &SET::GetQuestFlag, "GetQuestFlag"}, - {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, - {10, nullptr, "GetFirmwareVersionForDebug"}, - {11, &SET::GetDeviceNickName, "GetDeviceNickName"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -SET::~SET() = default; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h deleted file mode 100644 index 6ef3da410..000000000 --- a/src/core/hle/service/set/set.h +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" -#include "core/hle/service/set/system_settings.h" - -namespace Core { -class System; -} - -namespace Service::Set { -enum class KeyboardLayout : u64 { - Japanese = 0, - EnglishUs = 1, - EnglishUsInternational = 2, - EnglishUk = 3, - French = 4, - FrenchCa = 5, - Spanish = 6, - SpanishLatin = 7, - German = 8, - Italian = 9, - Portuguese = 10, - Russian = 11, - Korean = 12, - ChineseSimplified = 13, - ChineseTraditional = 14, -}; - -constexpr std::array<LanguageCode, 18> available_language_codes = {{ - LanguageCode::JA, - LanguageCode::EN_US, - LanguageCode::FR, - LanguageCode::DE, - LanguageCode::IT, - LanguageCode::ES, - LanguageCode::ZH_CN, - LanguageCode::KO, - LanguageCode::NL, - LanguageCode::PT, - LanguageCode::RU, - LanguageCode::ZH_TW, - LanguageCode::EN_GB, - LanguageCode::FR_CA, - LanguageCode::ES_419, - LanguageCode::ZH_HANS, - LanguageCode::ZH_HANT, - LanguageCode::PT_BR, -}}; - -static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{ - {LanguageCode::JA, KeyboardLayout::Japanese}, - {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, - {LanguageCode::FR, KeyboardLayout::French}, - {LanguageCode::DE, KeyboardLayout::German}, - {LanguageCode::IT, KeyboardLayout::Italian}, - {LanguageCode::ES, KeyboardLayout::Spanish}, - {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, - {LanguageCode::KO, KeyboardLayout::Korean}, - {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, - {LanguageCode::PT, KeyboardLayout::Portuguese}, - {LanguageCode::RU, KeyboardLayout::Russian}, - {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, - {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, - {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, - {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, - {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, - {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, - {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, -}}; - -LanguageCode GetLanguageCodeFromIndex(std::size_t idx); - -class SET final : public ServiceFramework<SET> { -public: - explicit SET(Core::System& system_); - ~SET() override; - -private: - void GetLanguageCode(HLERequestContext& ctx); - void GetAvailableLanguageCodes(HLERequestContext& ctx); - void MakeLanguageCode(HLERequestContext& ctx); - void GetAvailableLanguageCodes2(HLERequestContext& ctx); - void GetAvailableLanguageCodeCount(HLERequestContext& ctx); - void GetAvailableLanguageCodeCount2(HLERequestContext& ctx); - void GetQuestFlag(HLERequestContext& ctx); - void GetRegionCode(HLERequestContext& ctx); - void GetKeyCodeMap(HLERequestContext& ctx); - void GetKeyCodeMap2(HLERequestContext& ctx); - void GetDeviceNickName(HLERequestContext& ctx); -}; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp deleted file mode 100644 index d2c0d536f..000000000 --- a/src/core/hle/service/set/set_cal.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/set_cal.h" - -namespace Service::Set { - -SET_CAL::SET_CAL(Core::System& system_) : ServiceFramework{system_, "set:cal"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "GetBluetoothBdAddress"}, - {1, nullptr, "GetConfigurationId1"}, - {2, nullptr, "GetAccelerometerOffset"}, - {3, nullptr, "GetAccelerometerScale"}, - {4, nullptr, "GetGyroscopeOffset"}, - {5, nullptr, "GetGyroscopeScale"}, - {6, nullptr, "GetWirelessLanMacAddress"}, - {7, nullptr, "GetWirelessLanCountryCodeCount"}, - {8, nullptr, "GetWirelessLanCountryCodes"}, - {9, nullptr, "GetSerialNumber"}, - {10, nullptr, "SetInitialSystemAppletProgramId"}, - {11, nullptr, "SetOverlayDispProgramId"}, - {12, nullptr, "GetBatteryLot"}, - {14, nullptr, "GetEciDeviceCertificate"}, - {15, nullptr, "GetEticketDeviceCertificate"}, - {16, nullptr, "GetSslKey"}, - {17, nullptr, "GetSslCertificate"}, - {18, nullptr, "GetGameCardKey"}, - {19, nullptr, "GetGameCardCertificate"}, - {20, nullptr, "GetEciDeviceKey"}, - {21, nullptr, "GetEticketDeviceKey"}, - {22, nullptr, "GetSpeakerParameter"}, - {23, nullptr, "GetLcdVendorId"}, - {24, nullptr, "GetEciDeviceCertificate2"}, - {25, nullptr, "GetEciDeviceKey2"}, - {26, nullptr, "GetAmiiboKey"}, - {27, nullptr, "GetAmiiboEcqvCertificate"}, - {28, nullptr, "GetAmiiboEcdsaCertificate"}, - {29, nullptr, "GetAmiiboEcqvBlsKey"}, - {30, nullptr, "GetAmiiboEcqvBlsCertificate"}, - {31, nullptr, "GetAmiiboEcqvBlsRootCertificate"}, - {32, nullptr, "GetUsbTypeCPowerSourceCircuitVersion"}, - {33, nullptr, "GetAnalogStickModuleTypeL"}, - {34, nullptr, "GetAnalogStickModelParameterL"}, - {35, nullptr, "GetAnalogStickFactoryCalibrationL"}, - {36, nullptr, "GetAnalogStickModuleTypeR"}, - {37, nullptr, "GetAnalogStickModelParameterR"}, - {38, nullptr, "GetAnalogStickFactoryCalibrationR"}, - {39, nullptr, "GetConsoleSixAxisSensorModuleType"}, - {40, nullptr, "GetConsoleSixAxisSensorHorizontalOffset"}, - {41, nullptr, "GetBatteryVersion"}, - {42, nullptr, "GetDeviceId"}, - {43, nullptr, "GetConsoleSixAxisSensorMountType"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -SET_CAL::~SET_CAL() = default; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h deleted file mode 100644 index 8f50278ed..000000000 --- a/src/core/hle/service/set/set_cal.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Set { - -class SET_CAL final : public ServiceFramework<SET_CAL> { -public: - explicit SET_CAL(Core::System& system_); - ~SET_CAL() override; -}; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp deleted file mode 100644 index 278ef32e1..000000000 --- a/src/core/hle/service/set/set_fd.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/set_fd.h" - -namespace Service::Set { - -SET_FD::SET_FD(Core::System& system_) : ServiceFramework{system_, "set:fd"} { - // clang-format off - static const FunctionInfo functions[] = { - {2, nullptr, "SetSettingsItemValue"}, - {3, nullptr, "ResetSettingsItemValue"}, - {4, nullptr, "CreateSettingsItemKeyIterator"}, - {10, nullptr, "ReadSettings"}, - {11, nullptr, "ResetSettings"}, - {20, nullptr, "SetWebInspectorFlag"}, - {21, nullptr, "SetAllowedSslHosts"}, - {22, nullptr, "SetHostFsMountPoint"}, - {23, nullptr, "SetMemoryUsageRateFlag"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -SET_FD::~SET_FD() = default; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h deleted file mode 100644 index 150a7cbce..000000000 --- a/src/core/hle/service/set/set_fd.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Set { - -class SET_FD final : public ServiceFramework<SET_FD> { -public: - explicit SET_FD(Core::System& system_); - ~SET_FD() override; -}; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp deleted file mode 100644 index 8e637f963..000000000 --- a/src/core/hle/service/set/set_sys.cpp +++ /dev/null @@ -1,1272 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <fstream> - -#include "common/assert.h" -#include "common/fs/file.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/string_util.h" -#include "core/core.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/errors.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/romfs.h" -#include "core/file_sys/system_archive/system_archive.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/set/set.h" -#include "core/hle/service/set/set_sys.h" - -namespace Service::Set { - -namespace { -constexpr u32 SETTINGS_VERSION{1u}; -constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); -struct SettingsHeader { - u64 magic; - u32 version; - u32 reserved; -}; -} // Anonymous namespace - -Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, - GetFirmwareVersionType type) { - constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809; - auto& fsc = system.GetFileSystemController(); - - // Attempt to load version data from disk - const FileSys::RegisteredCache* bis_system{}; - std::unique_ptr<FileSys::NCA> nca{}; - FileSys::VirtualDir romfs{}; - - bis_system = fsc.GetSystemNANDContents(); - if (bis_system) { - nca = bis_system->GetEntry(FirmwareVersionSystemDataId, FileSys::ContentRecordType::Data); - } - if (nca) { - if (auto nca_romfs = nca->GetRomFS(); nca_romfs) { - romfs = FileSys::ExtractRomFS(nca_romfs); - } - } - if (!romfs) { - romfs = FileSys::ExtractRomFS( - FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId)); - } - - const auto early_exit_failure = [](std::string_view desc, Result code) { - LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", - desc); - return code; - }; - - const auto ver_file = romfs->GetFile("file"); - if (ver_file == nullptr) { - return early_exit_failure("The system version archive didn't contain the file 'file'.", - FileSys::ERROR_INVALID_ARGUMENT); - } - - auto data = ver_file->ReadAllBytes(); - if (data.size() != sizeof(FirmwareVersionFormat)) { - return early_exit_failure("The system version file 'file' was not the correct size.", - FileSys::ERROR_OUT_OF_BOUNDS); - } - - std::memcpy(&out_firmware, data.data(), sizeof(FirmwareVersionFormat)); - - // If the command is GetFirmwareVersion (as opposed to GetFirmwareVersion2), hardware will - // zero out the REVISION_MINOR field. - if (type == GetFirmwareVersionType::Version1) { - out_firmware.revision_minor = 0; - } - - return ResultSuccess; -} - -bool SET_SYS::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) { - using settings_type = decltype(default_func()); - - if (!Common::FS::CreateDirs(path)) { - return false; - } - - auto settings_file = path / "settings.dat"; - auto exists = std::filesystem::exists(settings_file); - auto file_size_ok = exists && std::filesystem::file_size(settings_file) == - sizeof(SettingsHeader) + sizeof(settings_type); - - auto ResetToDefault = [&]() { - auto default_settings{default_func()}; - - SettingsHeader hdr{ - .magic = SETTINGS_MAGIC, - .version = SETTINGS_VERSION, - .reserved = 0u, - }; - - std::ofstream out_settings_file(settings_file, std::ios::out | std::ios::binary); - out_settings_file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); - out_settings_file.write(reinterpret_cast<const char*>(&default_settings), - sizeof(settings_type)); - out_settings_file.flush(); - out_settings_file.close(); - }; - - constexpr auto IsHeaderValid = [](std::ifstream& file) -> bool { - if (!file.is_open()) { - return false; - } - SettingsHeader hdr{}; - file.read(reinterpret_cast<char*>(&hdr), sizeof(hdr)); - return hdr.magic == SETTINGS_MAGIC && hdr.version == SETTINGS_VERSION; - }; - - if (!exists || !file_size_ok) { - ResetToDefault(); - } - - std::ifstream file(settings_file, std::ios::binary | std::ios::in); - if (!IsHeaderValid(file)) { - file.close(); - ResetToDefault(); - file = std::ifstream(settings_file, std::ios::binary | std::ios::in); - if (!IsHeaderValid(file)) { - return false; - } - } - - if constexpr (std::is_same_v<settings_type, PrivateSettings>) { - file.read(reinterpret_cast<char*>(&m_private_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { - file.read(reinterpret_cast<char*>(&m_device_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { - file.read(reinterpret_cast<char*>(&m_appln_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { - file.read(reinterpret_cast<char*>(&m_system_settings), sizeof(settings_type)); - } else { - UNREACHABLE(); - } - file.close(); - - return true; -} - -bool SET_SYS::StoreSettingsFile(std::filesystem::path& path, auto& settings) { - using settings_type = std::decay_t<decltype(settings)>; - - if (!Common::FS::IsDir(path)) { - return false; - } - - auto settings_base = path / "settings"; - auto settings_tmp_file = settings_base; - settings_tmp_file = settings_tmp_file.replace_extension("tmp"); - std::ofstream file(settings_tmp_file, std::ios::binary | std::ios::out); - if (!file.is_open()) { - return false; - } - - SettingsHeader hdr{ - .magic = SETTINGS_MAGIC, - .version = SETTINGS_VERSION, - .reserved = 0u, - }; - file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); - - if constexpr (std::is_same_v<settings_type, PrivateSettings>) { - file.write(reinterpret_cast<const char*>(&m_private_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { - file.write(reinterpret_cast<const char*>(&m_device_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { - file.write(reinterpret_cast<const char*>(&m_appln_settings), sizeof(settings_type)); - } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { - file.write(reinterpret_cast<const char*>(&m_system_settings), sizeof(settings_type)); - } else { - UNREACHABLE(); - } - file.close(); - - std::filesystem::rename(settings_tmp_file, settings_base.replace_extension("dat")); - - return true; -} - -void SET_SYS::SetLanguageCode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.language_code = rp.PopEnum<LanguageCode>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, language_code={}", m_system_settings.language_code); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - FirmwareVersionFormat firmware_data{}; - const auto result = - GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version1); - - if (result.IsSuccess()) { - ctx.WriteBuffer(firmware_data); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - FirmwareVersionFormat firmware_data{}; - const auto result = - GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version2); - - if (result.IsSuccess()) { - ctx.WriteBuffer(firmware_data); - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void SET_SYS::GetExternalSteadyClockSourceId(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - Common::UUID id{}; - auto res = GetExternalSteadyClockSourceId(id); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(Common::UUID) / sizeof(u32)}; - rb.Push(res); - rb.PushRaw(id); -} - -void SET_SYS::SetExternalSteadyClockSourceId(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::RequestParser rp{ctx}; - auto id{rp.PopRaw<Common::UUID>()}; - - auto res = SetExternalSteadyClockSourceId(id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetUserSystemClockContext(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - Service::Time::Clock::SystemClockContext context{}; - auto res = GetUserSystemClockContext(context); - - IPC::ResponseBuilder rb{ctx, - 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; - rb.Push(res); - rb.PushRaw(context); -} - -void SET_SYS::SetUserSystemClockContext(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::RequestParser rp{ctx}; - auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; - - auto res = SetUserSystemClockContext(context); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw(m_system_settings.account_settings); -} - -void SET_SYS::SetAccountSettings(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.account_settings = rp.PopRaw<AccountSettings>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, account_settings_flags={}", - m_system_settings.account_settings.flags); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetEulaVersions(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - ctx.WriteBuffer(m_system_settings.eula_versions); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(m_system_settings.eula_version_count); -} - -void SET_SYS::SetEulaVersions(HLERequestContext& ctx) { - const auto elements = ctx.GetReadBufferNumElements<EulaVersion>(); - const auto buffer_data = ctx.ReadBuffer(); - - LOG_INFO(Service_SET, "called, elements={}", elements); - ASSERT(elements <= m_system_settings.eula_versions.size()); - - m_system_settings.eula_version_count = static_cast<u32>(elements); - std::memcpy(&m_system_settings.eula_versions, buffer_data.data(), - sizeof(EulaVersion) * elements); - SetSaveNeeded(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetColorSetId(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(m_system_settings.color_set_id); -} - -void SET_SYS::SetColorSetId(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.color_set_id = rp.PopEnum<ColorSet>(); - SetSaveNeeded(); - - LOG_DEBUG(Service_SET, "called, color_set={}", m_system_settings.color_set_id); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 8}; - rb.Push(ResultSuccess); - rb.PushRaw(m_system_settings.notification_settings); -} - -void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.notification_settings = rp.PopRaw<NotificationSettings>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}", - m_system_settings.notification_settings.flags.raw, - m_system_settings.notification_settings.volume, - m_system_settings.notification_settings.start_time.hour, - m_system_settings.notification_settings.start_time.minute, - m_system_settings.notification_settings.stop_time.hour, - m_system_settings.notification_settings.stop_time.minute); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - ctx.WriteBuffer(m_system_settings.account_notification_settings); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(m_system_settings.account_notification_settings_count); -} - -void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) { - const auto elements = ctx.GetReadBufferNumElements<AccountNotificationSettings>(); - const auto buffer_data = ctx.ReadBuffer(); - - LOG_INFO(Service_SET, "called, elements={}", elements); - - ASSERT(elements <= m_system_settings.account_notification_settings.size()); - - m_system_settings.account_notification_settings_count = static_cast<u32>(elements); - std::memcpy(&m_system_settings.account_notification_settings, buffer_data.data(), - elements * sizeof(AccountNotificationSettings)); - SetSaveNeeded(); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -// FIXME: implement support for the real system_settings.ini - -template <typename T> -static std::vector<u8> ToBytes(const T& value) { - static_assert(std::is_trivially_copyable_v<T>); - - const auto* begin = reinterpret_cast<const u8*>(&value); - const auto* end = begin + sizeof(T); - - return std::vector<u8>(begin, end); -} - -using Settings = - std::map<std::string, std::map<std::string, std::vector<u8>, std::less<>>, std::less<>>; - -static Settings GetSettings() { - Settings ret; - - ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); - ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); - - // Time - ret["time"]["notify_time_to_fs_interval_seconds"] = ToBytes(s32{600}); - ret["time"]["standard_network_clock_sufficient_accuracy_minutes"] = - ToBytes(s32{43200}); // 30 days - ret["time"]["standard_steady_clock_rtc_update_interval_minutes"] = ToBytes(s32{5}); - ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0}); - ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023}); - - return ret; -} - -void SET_SYS::GetSettingsItemValueSize(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - // The category of the setting. This corresponds to the top-level keys of - // system_settings.ini. - const auto setting_category_buf{ctx.ReadBuffer(0)}; - const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; - - // The name of the setting. This corresponds to the second-level keys of - // system_settings.ini. - const auto setting_name_buf{ctx.ReadBuffer(1)}; - const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; - - auto settings{GetSettings()}; - u64 response_size{0}; - - if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) { - response_size = settings[setting_category][setting_name].size(); - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(response_size == 0 ? ResultUnknown : ResultSuccess); - rb.Push(response_size); -} - -void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) { - // The category of the setting. This corresponds to the top-level keys of - // system_settings.ini. - const auto setting_category_buf{ctx.ReadBuffer(0)}; - const std::string setting_category{setting_category_buf.begin(), setting_category_buf.end()}; - - // The name of the setting. This corresponds to the second-level keys of - // system_settings.ini. - const auto setting_name_buf{ctx.ReadBuffer(1)}; - const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; - - std::vector<u8> value; - auto response = GetSettingsItemValue(value, setting_category, setting_name); - - LOG_INFO(Service_SET, "called. category={}, name={} -- res=0x{:X}", setting_category, - setting_name, response.raw); - - ctx.WriteBuffer(value.data(), value.size()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(response); -} - -void SET_SYS::GetTvSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(ResultSuccess); - rb.PushRaw(m_system_settings.tv_settings); -} - -void SET_SYS::SetTvSettings(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.tv_settings = rp.PopRaw<TvSettings>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, - "called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, " - "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", - m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, - m_system_settings.tv_settings.constrast_ratio, - m_system_settings.tv_settings.hdmi_content_type, - m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, - m_system_settings.tv_settings.tv_resolution, - m_system_settings.tv_settings.tv_underscan); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetDebugModeFlag(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(0); -} - -void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(QuestFlag::Retail); -} - -void SET_SYS::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called"); - - Service::Time::TimeZone::LocationName name{}; - auto res = GetDeviceTimeZoneLocationName(name); - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)}; - rb.Push(res); - rb.PushRaw<Service::Time::TimeZone::LocationName>(name); -} - -void SET_SYS::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called"); - - IPC::RequestParser rp{ctx}; - auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; - - auto res = SetDeviceTimeZoneLocationName(name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::SetRegionCode(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.region_code = rp.PopEnum<RegionCode>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetNetworkSystemClockContext(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - Service::Time::Clock::SystemClockContext context{}; - auto res = GetNetworkSystemClockContext(context); - - IPC::ResponseBuilder rb{ctx, - 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; - rb.Push(res); - rb.PushRaw(context); -} - -void SET_SYS::SetNetworkSystemClockContext(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::RequestParser rp{ctx}; - auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; - - auto res = SetNetworkSystemClockContext(context); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - bool enabled{}; - auto res = IsUserSystemClockAutomaticCorrectionEnabled(enabled); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(res); - rb.PushRaw(enabled); -} - -void SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::RequestParser rp{ctx}; - auto enabled{rp.Pop<bool>()}; - - auto res = SetUserSystemClockAutomaticCorrectionEnabled(enabled); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(PrimaryAlbumStorage::SdCard); -} - -void SET_SYS::GetSleepSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - - IPC::ResponseBuilder rb{ctx, 5}; - rb.Push(ResultSuccess); - rb.PushRaw(m_system_settings.sleep_settings); -} - -void SET_SYS::SetSleepSettings(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.sleep_settings = rp.PopRaw<SleepSettings>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}", - m_system_settings.sleep_settings.flags.raw, - m_system_settings.sleep_settings.handheld_sleep_plan, - m_system_settings.sleep_settings.console_sleep_plan); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called"); - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(ResultSuccess); - rb.PushRaw(m_system_settings.initial_launch_settings_packed); -} - -void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>(); - - m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags; - m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp; - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, flags={}, timestamp={}", - m_system_settings.initial_launch_settings_packed.flags.raw, - m_system_settings.initial_launch_settings_packed.timestamp.time_point); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - - ctx.WriteBuffer(::Settings::values.device_name.GetValue()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::SetDeviceNickName(HLERequestContext& ctx) { - const std::string device_name = Common::StringFromBuffer(ctx.ReadBuffer()); - - LOG_INFO(Service_SET, "called, device_name={}", device_name); - - ::Settings::values.device_name = device_name; - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetProductModel(HLERequestContext& ctx) { - const u32 product_model = 1; - - LOG_WARNING(Service_SET, "(STUBBED) called, product_model={}", product_model); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(product_model); -} - -void SET_SYS::GetMiiAuthorId(HLERequestContext& ctx) { - const auto author_id = Common::UUID::MakeDefault(); - - LOG_WARNING(Service_SET, "(STUBBED) called, author_id={}", author_id.FormattedString()); - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(author_id); -} - -void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) { - u8 auto_update_flag{}; - - LOG_WARNING(Service_SET, "(STUBBED) called, auto_update_flag={}", auto_update_flag); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(auto_update_flag); -} - -void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) { - u8 battery_percentage_flag{1}; - - LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}", - battery_percentage_flag); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(battery_percentage_flag); -} - -void SET_SYS::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called."); - - IPC::RequestParser rp{ctx}; - auto offset{rp.Pop<s64>()}; - - auto res = SetExternalSteadyClockInternalOffset(offset); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called."); - - s64 offset{}; - auto res = GetExternalSteadyClockInternalOffset(offset); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(res); - rb.Push(offset); -} - -void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(ErrorReportSharePermission::Denied); -} - -void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(m_system_settings.applet_launch_flag); -} - -void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - m_system_settings.applet_launch_flag = rp.Pop<u32>(); - SetSaveNeeded(); - - LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) { - const auto language_code = - available_language_codes[static_cast<s32>(::Settings::values.language_index.GetValue())]; - const auto key_code = - std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), - [=](const auto& element) { return element.first == language_code; }); - - KeyboardLayout selected_keyboard_layout = KeyboardLayout::EnglishUs; - if (key_code != language_to_layout.end()) { - selected_keyboard_layout = key_code->second; - } - - LOG_INFO(Service_SET, "called, selected_keyboard_layout={}", selected_keyboard_layout); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(selected_keyboard_layout)); -} - -void SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called."); - - Service::Time::Clock::SteadyClockTimePoint time_point{}; - auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(res); - rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); -} - -void SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called."); - - IPC::RequestParser rp{ctx}; - auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; - - auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called."); - - Service::Time::Clock::SteadyClockTimePoint time_point{}; - auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(res); - rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); -} - -void SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "called."); - - IPC::RequestParser rp{ctx}; - auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; - - auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(res); -} - -void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(ChineseTraditionalInputMethod::Unknown0); -} - -void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "(STUBBED) called"); - - const HomeMenuScheme default_color = { - .main = 0xFF323232, - .back = 0xFF323232, - .sub = 0xFFFFFFFF, - .bezel = 0xFFFFFFFF, - .extra = 0xFF000000, - }; - - IPC::ResponseBuilder rb{ctx, 2 + sizeof(HomeMenuScheme) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw(default_color); -} - -void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(0); -} - -void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) { - LOG_WARNING(Service_SET, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(false); -} - -SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"}, m_system{system} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &SET_SYS::SetLanguageCode, "SetLanguageCode"}, - {1, nullptr, "SetNetworkSettings"}, - {2, nullptr, "GetNetworkSettings"}, - {3, &SET_SYS::GetFirmwareVersion, "GetFirmwareVersion"}, - {4, &SET_SYS::GetFirmwareVersion2, "GetFirmwareVersion2"}, - {5, nullptr, "GetFirmwareVersionDigest"}, - {7, nullptr, "GetLockScreenFlag"}, - {8, nullptr, "SetLockScreenFlag"}, - {9, nullptr, "GetBacklightSettings"}, - {10, nullptr, "SetBacklightSettings"}, - {11, nullptr, "SetBluetoothDevicesSettings"}, - {12, nullptr, "GetBluetoothDevicesSettings"}, - {13, &SET_SYS::GetExternalSteadyClockSourceId, "GetExternalSteadyClockSourceId"}, - {14, &SET_SYS::SetExternalSteadyClockSourceId, "SetExternalSteadyClockSourceId"}, - {15, &SET_SYS::GetUserSystemClockContext, "GetUserSystemClockContext"}, - {16, &SET_SYS::SetUserSystemClockContext, "SetUserSystemClockContext"}, - {17, &SET_SYS::GetAccountSettings, "GetAccountSettings"}, - {18, &SET_SYS::SetAccountSettings, "SetAccountSettings"}, - {19, nullptr, "GetAudioVolume"}, - {20, nullptr, "SetAudioVolume"}, - {21, &SET_SYS::GetEulaVersions, "GetEulaVersions"}, - {22, &SET_SYS::SetEulaVersions, "SetEulaVersions"}, - {23, &SET_SYS::GetColorSetId, "GetColorSetId"}, - {24, &SET_SYS::SetColorSetId, "SetColorSetId"}, - {25, nullptr, "GetConsoleInformationUploadFlag"}, - {26, nullptr, "SetConsoleInformationUploadFlag"}, - {27, nullptr, "GetAutomaticApplicationDownloadFlag"}, - {28, nullptr, "SetAutomaticApplicationDownloadFlag"}, - {29, &SET_SYS::GetNotificationSettings, "GetNotificationSettings"}, - {30, &SET_SYS::SetNotificationSettings, "SetNotificationSettings"}, - {31, &SET_SYS::GetAccountNotificationSettings, "GetAccountNotificationSettings"}, - {32, &SET_SYS::SetAccountNotificationSettings, "SetAccountNotificationSettings"}, - {35, nullptr, "GetVibrationMasterVolume"}, - {36, nullptr, "SetVibrationMasterVolume"}, - {37, &SET_SYS::GetSettingsItemValueSize, "GetSettingsItemValueSize"}, - {38, &SET_SYS::GetSettingsItemValue, "GetSettingsItemValue"}, - {39, &SET_SYS::GetTvSettings, "GetTvSettings"}, - {40, &SET_SYS::SetTvSettings, "SetTvSettings"}, - {41, nullptr, "GetEdid"}, - {42, nullptr, "SetEdid"}, - {43, nullptr, "GetAudioOutputMode"}, - {44, nullptr, "SetAudioOutputMode"}, - {45, nullptr, "IsForceMuteOnHeadphoneRemoved"}, - {46, nullptr, "SetForceMuteOnHeadphoneRemoved"}, - {47, &SET_SYS::GetQuestFlag, "GetQuestFlag"}, - {48, nullptr, "SetQuestFlag"}, - {49, nullptr, "GetDataDeletionSettings"}, - {50, nullptr, "SetDataDeletionSettings"}, - {51, nullptr, "GetInitialSystemAppletProgramId"}, - {52, nullptr, "GetOverlayDispProgramId"}, - {53, &SET_SYS::GetDeviceTimeZoneLocationName, "GetDeviceTimeZoneLocationName"}, - {54, &SET_SYS::SetDeviceTimeZoneLocationName, "SetDeviceTimeZoneLocationName"}, - {55, nullptr, "GetWirelessCertificationFileSize"}, - {56, nullptr, "GetWirelessCertificationFile"}, - {57, &SET_SYS::SetRegionCode, "SetRegionCode"}, - {58, &SET_SYS::GetNetworkSystemClockContext, "GetNetworkSystemClockContext"}, - {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, - {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, - {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, - {62, &SET_SYS::GetDebugModeFlag, "GetDebugModeFlag"}, - {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, - {64, nullptr, "SetPrimaryAlbumStorage"}, - {65, nullptr, "GetUsb30EnableFlag"}, - {66, nullptr, "SetUsb30EnableFlag"}, - {67, nullptr, "GetBatteryLot"}, - {68, nullptr, "GetSerialNumber"}, - {69, nullptr, "GetNfcEnableFlag"}, - {70, nullptr, "SetNfcEnableFlag"}, - {71, &SET_SYS::GetSleepSettings, "GetSleepSettings"}, - {72, &SET_SYS::SetSleepSettings, "SetSleepSettings"}, - {73, nullptr, "GetWirelessLanEnableFlag"}, - {74, nullptr, "SetWirelessLanEnableFlag"}, - {75, &SET_SYS::GetInitialLaunchSettings, "GetInitialLaunchSettings"}, - {76, &SET_SYS::SetInitialLaunchSettings, "SetInitialLaunchSettings"}, - {77, &SET_SYS::GetDeviceNickName, "GetDeviceNickName"}, - {78, &SET_SYS::SetDeviceNickName, "SetDeviceNickName"}, - {79, &SET_SYS::GetProductModel, "GetProductModel"}, - {80, nullptr, "GetLdnChannel"}, - {81, nullptr, "SetLdnChannel"}, - {82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"}, - {83, nullptr, "GetTelemetryDirtyFlags"}, - {84, nullptr, "GetPtmBatteryLot"}, - {85, nullptr, "SetPtmBatteryLot"}, - {86, nullptr, "GetPtmFuelGaugeParameter"}, - {87, nullptr, "SetPtmFuelGaugeParameter"}, - {88, nullptr, "GetBluetoothEnableFlag"}, - {89, nullptr, "SetBluetoothEnableFlag"}, - {90, &SET_SYS::GetMiiAuthorId, "GetMiiAuthorId"}, - {91, nullptr, "SetShutdownRtcValue"}, - {92, nullptr, "GetShutdownRtcValue"}, - {93, nullptr, "AcquireFatalDirtyFlagEventHandle"}, - {94, nullptr, "GetFatalDirtyFlags"}, - {95, &SET_SYS::GetAutoUpdateEnableFlag, "GetAutoUpdateEnableFlag"}, - {96, nullptr, "SetAutoUpdateEnableFlag"}, - {97, nullptr, "GetNxControllerSettings"}, - {98, nullptr, "SetNxControllerSettings"}, - {99, &SET_SYS::GetBatteryPercentageFlag, "GetBatteryPercentageFlag"}, - {100, nullptr, "SetBatteryPercentageFlag"}, - {101, nullptr, "GetExternalRtcResetFlag"}, - {102, nullptr, "SetExternalRtcResetFlag"}, - {103, nullptr, "GetUsbFullKeyEnableFlag"}, - {104, nullptr, "SetUsbFullKeyEnableFlag"}, - {105, &SET_SYS::SetExternalSteadyClockInternalOffset, "SetExternalSteadyClockInternalOffset"}, - {106, &SET_SYS::GetExternalSteadyClockInternalOffset, "GetExternalSteadyClockInternalOffset"}, - {107, nullptr, "GetBacklightSettingsEx"}, - {108, nullptr, "SetBacklightSettingsEx"}, - {109, nullptr, "GetHeadphoneVolumeWarningCount"}, - {110, nullptr, "SetHeadphoneVolumeWarningCount"}, - {111, nullptr, "GetBluetoothAfhEnableFlag"}, - {112, nullptr, "SetBluetoothAfhEnableFlag"}, - {113, nullptr, "GetBluetoothBoostEnableFlag"}, - {114, nullptr, "SetBluetoothBoostEnableFlag"}, - {115, nullptr, "GetInRepairProcessEnableFlag"}, - {116, nullptr, "SetInRepairProcessEnableFlag"}, - {117, nullptr, "GetHeadphoneVolumeUpdateFlag"}, - {118, nullptr, "SetHeadphoneVolumeUpdateFlag"}, - {119, nullptr, "NeedsToUpdateHeadphoneVolume"}, - {120, nullptr, "GetPushNotificationActivityModeOnSleep"}, - {121, nullptr, "SetPushNotificationActivityModeOnSleep"}, - {122, nullptr, "GetServiceDiscoveryControlSettings"}, - {123, nullptr, "SetServiceDiscoveryControlSettings"}, - {124, &SET_SYS::GetErrorReportSharePermission, "GetErrorReportSharePermission"}, - {125, nullptr, "SetErrorReportSharePermission"}, - {126, &SET_SYS::GetAppletLaunchFlags, "GetAppletLaunchFlags"}, - {127, &SET_SYS::SetAppletLaunchFlags, "SetAppletLaunchFlags"}, - {128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"}, - {129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"}, - {130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"}, - {131, nullptr, "SetConsoleSixAxisSensorAngularVelocityBias"}, - {132, nullptr, "GetConsoleSixAxisSensorAccelerationGain"}, - {133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"}, - {134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"}, - {135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"}, - {136, &SET_SYS::GetKeyboardLayout, "GetKeyboardLayout"}, - {137, nullptr, "SetKeyboardLayout"}, - {138, nullptr, "GetWebInspectorFlag"}, - {139, nullptr, "GetAllowedSslHosts"}, - {140, nullptr, "GetHostFsMountPoint"}, - {141, nullptr, "GetRequiresRunRepairTimeReviser"}, - {142, nullptr, "SetRequiresRunRepairTimeReviser"}, - {143, nullptr, "SetBlePairingSettings"}, - {144, nullptr, "GetBlePairingSettings"}, - {145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"}, - {146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"}, - {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, - {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, - {149, nullptr, "GetRebootlessSystemUpdateVersion"}, - {150, &SET_SYS::GetDeviceTimeZoneLocationUpdatedTime, "GetDeviceTimeZoneLocationUpdatedTime"}, - {151, &SET_SYS::SetDeviceTimeZoneLocationUpdatedTime, "SetDeviceTimeZoneLocationUpdatedTime"}, - {152, &SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime, "GetUserSystemClockAutomaticCorrectionUpdatedTime"}, - {153, &SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime, "SetUserSystemClockAutomaticCorrectionUpdatedTime"}, - {154, nullptr, "GetAccountOnlineStorageSettings"}, - {155, nullptr, "SetAccountOnlineStorageSettings"}, - {156, nullptr, "GetPctlReadyFlag"}, - {157, nullptr, "SetPctlReadyFlag"}, - {158, nullptr, "GetAnalogStickUserCalibrationL"}, - {159, nullptr, "SetAnalogStickUserCalibrationL"}, - {160, nullptr, "GetAnalogStickUserCalibrationR"}, - {161, nullptr, "SetAnalogStickUserCalibrationR"}, - {162, nullptr, "GetPtmBatteryVersion"}, - {163, nullptr, "SetPtmBatteryVersion"}, - {164, nullptr, "GetUsb30HostEnableFlag"}, - {165, nullptr, "SetUsb30HostEnableFlag"}, - {166, nullptr, "GetUsb30DeviceEnableFlag"}, - {167, nullptr, "SetUsb30DeviceEnableFlag"}, - {168, nullptr, "GetThemeId"}, - {169, nullptr, "SetThemeId"}, - {170, &SET_SYS::GetChineseTraditionalInputMethod, "GetChineseTraditionalInputMethod"}, - {171, nullptr, "SetChineseTraditionalInputMethod"}, - {172, nullptr, "GetPtmCycleCountReliability"}, - {173, nullptr, "SetPtmCycleCountReliability"}, - {174, &SET_SYS::GetHomeMenuScheme, "GetHomeMenuScheme"}, - {175, nullptr, "GetThemeSettings"}, - {176, nullptr, "SetThemeSettings"}, - {177, nullptr, "GetThemeKey"}, - {178, nullptr, "SetThemeKey"}, - {179, nullptr, "GetZoomFlag"}, - {180, nullptr, "SetZoomFlag"}, - {181, nullptr, "GetT"}, - {182, nullptr, "SetT"}, - {183, nullptr, "GetPlatformRegion"}, - {184, nullptr, "SetPlatformRegion"}, - {185, &SET_SYS::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"}, - {186, nullptr, "GetMemoryUsageRateFlag"}, - {187, nullptr, "GetTouchScreenMode"}, - {188, nullptr, "SetTouchScreenMode"}, - {189, nullptr, "GetButtonConfigSettingsFull"}, - {190, nullptr, "SetButtonConfigSettingsFull"}, - {191, nullptr, "GetButtonConfigSettingsEmbedded"}, - {192, nullptr, "SetButtonConfigSettingsEmbedded"}, - {193, nullptr, "GetButtonConfigSettingsLeft"}, - {194, nullptr, "SetButtonConfigSettingsLeft"}, - {195, nullptr, "GetButtonConfigSettingsRight"}, - {196, nullptr, "SetButtonConfigSettingsRight"}, - {197, nullptr, "GetButtonConfigRegisteredSettingsEmbedded"}, - {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, - {199, nullptr, "GetButtonConfigRegisteredSettings"}, - {200, nullptr, "SetButtonConfigRegisteredSettings"}, - {201, &SET_SYS::GetFieldTestingFlag, "GetFieldTestingFlag"}, - {202, nullptr, "SetFieldTestingFlag"}, - {203, nullptr, "GetPanelCrcMode"}, - {204, nullptr, "SetPanelCrcMode"}, - {205, nullptr, "GetNxControllerSettingsEx"}, - {206, nullptr, "SetNxControllerSettingsEx"}, - {207, nullptr, "GetHearingProtectionSafeguardFlag"}, - {208, nullptr, "SetHearingProtectionSafeguardFlag"}, - {209, nullptr, "GetHearingProtectionSafeguardRemainingTime"}, - {210, nullptr, "SetHearingProtectionSafeguardRemainingTime"}, - }; - // clang-format on - - RegisterHandlers(functions); - - SetupSettings(); - m_save_thread = - std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); }); -} - -SET_SYS::~SET_SYS() { - SetSaveNeeded(); - m_save_thread.request_stop(); -} - -void SET_SYS::SetupSettings() { - auto system_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; - if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) { - ASSERT(false); - } - - auto private_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; - if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) { - ASSERT(false); - } - - auto device_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; - if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) { - ASSERT(false); - } - - auto appln_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; - if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) { - ASSERT(false); - } -} - -void SET_SYS::StoreSettings() { - auto system_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; - if (!StoreSettingsFile(system_dir, m_system_settings)) { - LOG_ERROR(HW_GPU, "Failed to store System settings"); - } - - auto private_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; - if (!StoreSettingsFile(private_dir, m_private_settings)) { - LOG_ERROR(HW_GPU, "Failed to store Private settings"); - } - - auto device_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; - if (!StoreSettingsFile(device_dir, m_device_settings)) { - LOG_ERROR(HW_GPU, "Failed to store Device settings"); - } - - auto appln_dir = - Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; - if (!StoreSettingsFile(appln_dir, m_appln_settings)) { - LOG_ERROR(HW_GPU, "Failed to store ApplLn settings"); - } -} - -void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { - Common::SetCurrentThreadName("SettingsStore"); - - while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { - std::scoped_lock l{m_save_needed_mutex}; - if (!std::exchange(m_save_needed, false)) { - continue; - } - StoreSettings(); - } -} - -void SET_SYS::SetSaveNeeded() { - std::scoped_lock l{m_save_needed_mutex}; - m_save_needed = true; -} - -Result SET_SYS::GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, - const std::string& name) { - auto settings{GetSettings()}; - R_UNLESS(settings.contains(category) && settings[category].contains(name), ResultUnknown); - - out_value = settings[category][name]; - R_SUCCEED(); -} - -Result SET_SYS::GetExternalSteadyClockSourceId(Common::UUID& out_id) { - out_id = m_private_settings.external_clock_source_id; - R_SUCCEED(); -} - -Result SET_SYS::SetExternalSteadyClockSourceId(Common::UUID id) { - m_private_settings.external_clock_source_id = id; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context) { - out_context = m_system_settings.user_system_clock_context; - R_SUCCEED(); -} - -Result SET_SYS::SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context) { - m_system_settings.user_system_clock_context = context; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name) { - out_name = m_system_settings.device_time_zone_location_name; - R_SUCCEED(); -} - -Result SET_SYS::SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name) { - m_system_settings.device_time_zone_location_name = name; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::GetNetworkSystemClockContext( - Service::Time::Clock::SystemClockContext& out_context) { - out_context = m_system_settings.network_system_clock_context; - R_SUCCEED(); -} - -Result SET_SYS::SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context) { - m_system_settings.network_system_clock_context = context; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) { - out_enabled = m_system_settings.user_system_clock_automatic_correction_enabled; - R_SUCCEED(); -} - -Result SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(bool enabled) { - m_system_settings.user_system_clock_automatic_correction_enabled = enabled; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::SetExternalSteadyClockInternalOffset(s64 offset) { - m_private_settings.external_steady_clock_internal_offset = offset; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::GetExternalSteadyClockInternalOffset(s64& out_offset) { - out_offset = m_private_settings.external_steady_clock_internal_offset; - R_SUCCEED(); -} - -Result SET_SYS::GetDeviceTimeZoneLocationUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& out_time_point) { - out_time_point = m_system_settings.device_time_zone_location_updated_time; - R_SUCCEED(); -} - -Result SET_SYS::SetDeviceTimeZoneLocationUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& time_point) { - m_system_settings.device_time_zone_location_updated_time = time_point; - SetSaveNeeded(); - R_SUCCEED(); -} - -Result SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& out_time_point) { - out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; - R_SUCCEED(); -} - -Result SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint out_time_point) { - m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; - SetSaveNeeded(); - R_SUCCEED(); -} - -} // namespace Service::Set diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h deleted file mode 100644 index 853f76fce..000000000 --- a/src/core/hle/service/set/set_sys.h +++ /dev/null @@ -1,153 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <filesystem> -#include <mutex> -#include <string> -#include <thread> - -#include "common/polyfill_thread.h" -#include "common/uuid.h" -#include "core/hle/result.h" -#include "core/hle/service/service.h" -#include "core/hle/service/set/appln_settings.h" -#include "core/hle/service/set/device_settings.h" -#include "core/hle/service/set/private_settings.h" -#include "core/hle/service/set/system_settings.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/time_zone_types.h" - -namespace Core { -class System; -} - -namespace Service::Set { -enum class GetFirmwareVersionType { - Version1, - Version2, -}; - -struct FirmwareVersionFormat { - u8 major; - u8 minor; - u8 micro; - INSERT_PADDING_BYTES(1); - u8 revision_major; - u8 revision_minor; - INSERT_PADDING_BYTES(2); - std::array<char, 0x20> platform; - std::array<u8, 0x40> version_hash; - std::array<char, 0x18> display_version; - std::array<char, 0x80> display_title; -}; -static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size"); - -Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, - GetFirmwareVersionType type); - -class SET_SYS final : public ServiceFramework<SET_SYS> { -public: - explicit SET_SYS(Core::System& system_); - ~SET_SYS() override; - - Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, - const std::string& name); - - Result GetExternalSteadyClockSourceId(Common::UUID& out_id); - Result SetExternalSteadyClockSourceId(Common::UUID id); - Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); - Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context); - Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name); - Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name); - Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); - Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context); - Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled); - Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); - Result SetExternalSteadyClockInternalOffset(s64 offset); - Result GetExternalSteadyClockInternalOffset(s64& out_offset); - Result GetDeviceTimeZoneLocationUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& out_time_point); - Result SetDeviceTimeZoneLocationUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& time_point); - Result GetUserSystemClockAutomaticCorrectionUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint& out_time_point); - Result SetUserSystemClockAutomaticCorrectionUpdatedTime( - Service::Time::Clock::SteadyClockTimePoint time_point); - -private: - void SetLanguageCode(HLERequestContext& ctx); - void GetFirmwareVersion(HLERequestContext& ctx); - void GetFirmwareVersion2(HLERequestContext& ctx); - void GetExternalSteadyClockSourceId(HLERequestContext& ctx); - void SetExternalSteadyClockSourceId(HLERequestContext& ctx); - void GetUserSystemClockContext(HLERequestContext& ctx); - void SetUserSystemClockContext(HLERequestContext& ctx); - void GetAccountSettings(HLERequestContext& ctx); - void SetAccountSettings(HLERequestContext& ctx); - void GetEulaVersions(HLERequestContext& ctx); - void SetEulaVersions(HLERequestContext& ctx); - void GetColorSetId(HLERequestContext& ctx); - void SetColorSetId(HLERequestContext& ctx); - void GetNotificationSettings(HLERequestContext& ctx); - void SetNotificationSettings(HLERequestContext& ctx); - void GetAccountNotificationSettings(HLERequestContext& ctx); - void SetAccountNotificationSettings(HLERequestContext& ctx); - void GetSettingsItemValueSize(HLERequestContext& ctx); - void GetSettingsItemValue(HLERequestContext& ctx); - void GetTvSettings(HLERequestContext& ctx); - void SetTvSettings(HLERequestContext& ctx); - void GetDebugModeFlag(HLERequestContext& ctx); - void GetQuestFlag(HLERequestContext& ctx); - void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); - void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); - void SetRegionCode(HLERequestContext& ctx); - void GetNetworkSystemClockContext(HLERequestContext& ctx); - void SetNetworkSystemClockContext(HLERequestContext& ctx); - void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); - void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); - void GetPrimaryAlbumStorage(HLERequestContext& ctx); - void GetSleepSettings(HLERequestContext& ctx); - void SetSleepSettings(HLERequestContext& ctx); - void GetInitialLaunchSettings(HLERequestContext& ctx); - void SetInitialLaunchSettings(HLERequestContext& ctx); - void GetDeviceNickName(HLERequestContext& ctx); - void SetDeviceNickName(HLERequestContext& ctx); - void GetProductModel(HLERequestContext& ctx); - void GetMiiAuthorId(HLERequestContext& ctx); - void GetAutoUpdateEnableFlag(HLERequestContext& ctx); - void GetBatteryPercentageFlag(HLERequestContext& ctx); - void SetExternalSteadyClockInternalOffset(HLERequestContext& ctx); - void GetExternalSteadyClockInternalOffset(HLERequestContext& ctx); - void GetErrorReportSharePermission(HLERequestContext& ctx); - void GetAppletLaunchFlags(HLERequestContext& ctx); - void SetAppletLaunchFlags(HLERequestContext& ctx); - void GetKeyboardLayout(HLERequestContext& ctx); - void GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); - void SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); - void GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); - void SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); - void GetChineseTraditionalInputMethod(HLERequestContext& ctx); - void GetHomeMenuScheme(HLERequestContext& ctx); - void GetHomeMenuSchemeModel(HLERequestContext& ctx); - void GetFieldTestingFlag(HLERequestContext& ctx); - - bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func); - bool StoreSettingsFile(std::filesystem::path& path, auto& settings); - void SetupSettings(); - void StoreSettings(); - void StoreSettingsThreadFunc(std::stop_token stop_token); - void SetSaveNeeded(); - - Core::System& m_system; - SystemSettings m_system_settings{}; - PrivateSettings m_private_settings{}; - DeviceSettings m_device_settings{}; - ApplnSettings m_appln_settings{}; - std::jthread m_save_thread; - std::mutex m_save_needed_mutex; - bool m_save_needed{false}; -}; - -} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/appln_settings.cpp b/src/core/hle/service/set/setting_formats/appln_settings.cpp new file mode 100644 index 000000000..f7c7d5b91 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/appln_settings.cpp @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/setting_formats/appln_settings.h" + +namespace Service::Set { + +ApplnSettings DefaultApplnSettings() { + ApplnSettings settings{}; + + settings.mii_author_id = Common::UUID::MakeDefault(); + + return settings; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/appln_settings.h b/src/core/hle/service/set/setting_formats/appln_settings.h new file mode 100644 index 000000000..ba9af998a --- /dev/null +++ b/src/core/hle/service/set/setting_formats/appln_settings.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <cstddef> + +#include "common/common_types.h" +#include "common/uuid.h" +#include "core/hle/service/set/settings_types.h" + +namespace Service::Set { +struct ApplnSettings { + INSERT_PADDING_BYTES(0x10); // Reserved + + // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0 + Common::UUID mii_author_id; + INSERT_PADDING_BYTES(0x30); // Reserved + + // nn::settings::system::ServiceDiscoveryControlSettings + u32 service_discovery_control_settings; + INSERT_PADDING_BYTES(0x20); // Reserved + + bool in_repair_process_enable_flag; + INSERT_PADDING_BYTES(0x3); +}; +static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10); +static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50); +static_assert(offsetof(ApplnSettings, in_repair_process_enable_flag) == 0x74); +static_assert(sizeof(ApplnSettings) == 0x78, "ApplnSettings has the wrong size!"); + +ApplnSettings DefaultApplnSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/device_settings.cpp b/src/core/hle/service/set/setting_formats/device_settings.cpp new file mode 100644 index 000000000..5f295404d --- /dev/null +++ b/src/core/hle/service/set/setting_formats/device_settings.cpp @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/setting_formats/device_settings.h" + +namespace Service::Set { + +DeviceSettings DefaultDeviceSettings() { + return {}; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/device_settings.h b/src/core/hle/service/set/setting_formats/device_settings.h new file mode 100644 index 000000000..2827756f6 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/device_settings.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <cstddef> + +#include "common/common_types.h" +#include "common/vector_math.h" +#include "core/hle/service/set/settings_types.h" + +namespace Service::Set { +struct DeviceSettings { + INSERT_PADDING_BYTES(0x10); // Reserved + + // nn::settings::BatteryLot + std::array<u8, 0x18> ptm_battery_lot; + // nn::settings::system::PtmFuelGaugeParameter + std::array<u8, 0x18> ptm_fuel_gauge_parameter; + u8 ptm_battery_version; + // nn::settings::system::PtmCycleCountReliability + u32 ptm_cycle_count_reliability; + INSERT_PADDING_BYTES(0x48); // Reserved + + // nn::settings::system::AnalogStickUserCalibration L + std::array<u8, 0x10> analog_user_stick_calibration_l; + // nn::settings::system::AnalogStickUserCalibration R + std::array<u8, 0x10> analog_user_stick_calibration_r; + INSERT_PADDING_BYTES(0x20); // Reserved + + // nn::settings::system::ConsoleSixAxisSensorAccelerationBias + Common::Vec3<f32> console_six_axis_sensor_acceleration_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias + Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias; + // nn::settings::system::ConsoleSixAxisSensorAccelerationGain + std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias + Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration + std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration; +}; +static_assert(offsetof(DeviceSettings, ptm_battery_lot) == 0x10); +static_assert(offsetof(DeviceSettings, ptm_cycle_count_reliability) == 0x44); +static_assert(offsetof(DeviceSettings, analog_user_stick_calibration_l) == 0x90); +static_assert(offsetof(DeviceSettings, console_six_axis_sensor_acceleration_bias) == 0xD0); +static_assert(offsetof(DeviceSettings, console_six_axis_sensor_angular_acceleration) == 0x13C); +static_assert(sizeof(DeviceSettings) == 0x160, "DeviceSettings has the wrong size!"); + +DeviceSettings DefaultDeviceSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/private_settings.cpp b/src/core/hle/service/set/setting_formats/private_settings.cpp new file mode 100644 index 000000000..81c362482 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/private_settings.cpp @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/setting_formats/private_settings.h" + +namespace Service::Set { + +PrivateSettings DefaultPrivateSettings() { + return {}; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/private_settings.h b/src/core/hle/service/set/setting_formats/private_settings.h new file mode 100644 index 000000000..6579e95e0 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/private_settings.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/common_types.h" +#include "common/uuid.h" +#include "core/hle/service/set/settings_types.h" + +namespace Service::Set { + +struct PrivateSettings { + INSERT_PADDING_BYTES(0x10); // Reserved + + InitialLaunchSettings initial_launch_settings; + INSERT_PADDING_BYTES(0x20); // Reserved + + Common::UUID external_clock_source_id; + s64 shutdown_rtc_value; + s64 external_steady_clock_internal_offset; + INSERT_PADDING_BYTES(0x60); // Reserved + + // nn::settings::system::PlatformRegion + s32 platform_region; + INSERT_PADDING_BYTES(0x4); // Reserved +}; +static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10); +static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50); +static_assert(offsetof(PrivateSettings, shutdown_rtc_value) == 0x60); +static_assert(offsetof(PrivateSettings, external_steady_clock_internal_offset) == 0x68); +static_assert(offsetof(PrivateSettings, platform_region) == 0xD0); +static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!"); + +PrivateSettings DefaultPrivateSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/system_settings.cpp b/src/core/hle/service/set/setting_formats/system_settings.cpp new file mode 100644 index 000000000..16ded43bf --- /dev/null +++ b/src/core/hle/service/set/setting_formats/system_settings.cpp @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/settings.h" +#include "core/hle/service/set/setting_formats/system_settings.h" + +namespace Service::Set { + +SystemSettings DefaultSystemSettings() { + SystemSettings settings{}; + + settings.version = 0x140000; + settings.flags = 7; + + settings.mii_author_id = Common::UUID::MakeDefault(); + + settings.color_set_id = ColorSet::BasicWhite; + + settings.notification_settings = { + .flags{0x300}, + .volume = NotificationVolume::High, + .start_time = {.hour = 9, .minute = 0}, + .stop_time = {.hour = 21, .minute = 0}, + }; + + settings.tv_settings = { + .flags = {0xC}, + .tv_resolution = TvResolution::Auto, + .hdmi_content_type = HdmiContentType::Game, + .rgb_range = RgbRange::Auto, + .cmu_mode = CmuMode::None, + .tv_underscan = {}, + .tv_gama = 1.0f, + .contrast_ratio = 0.5f, + }; + + settings.initial_launch_settings_packed = { + .flags = {0x10001}, + .timestamp = {}, + }; + + settings.sleep_settings = { + .flags = {0x3}, + .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min, + .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour, + }; + + settings.device_time_zone_location_name = {"UTC"}; + settings.user_system_clock_automatic_correction_enabled = true; + + settings.primary_album_storage = PrimaryAlbumStorage::SdCard; + settings.battery_percentage_flag = true; + settings.chinese_traditional_input_method = ChineseTraditionalInputMethod::Unknown0; + settings.vibration_master_volume = 1.0f; + + const auto language_code = + available_language_codes[static_cast<s32>(::Settings::values.language_index.GetValue())]; + const auto key_code = + std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), + [=](const auto& element) { return element.first == language_code; }); + + settings.keyboard_layout = KeyboardLayout::EnglishUs; + if (key_code != language_to_layout.end()) { + settings.keyboard_layout = key_code->second; + } + + return settings; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/setting_formats/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h new file mode 100644 index 000000000..ebc373da5 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/system_settings.h @@ -0,0 +1,391 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/uuid.h" +#include "common/vector_math.h" +#include "core/hle/service/set/setting_formats/private_settings.h" +#include "core/hle/service/set/settings_types.h" + +namespace Service::Set { + +struct SystemSettings { + // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000 + // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000 + // (9.0.0-10.0.4), 0x100100 (10.1.0+), 0x120000 (12.0.0-12.1.0), 0x130000 (13.0.0-13.2.1), + // 0x140000 (14.0.0+) + u32 version; + // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+). + // if (flags & 2), defaults are written for AnalogStickUserCalibration + u32 flags; + INSERT_PADDING_BYTES(0x8); // Reserved + + LanguageCode language_code; + INSERT_PADDING_BYTES(0x38); // Reserved + + // nn::settings::system::NetworkSettings + u32 network_setting_count; + bool wireless_lan_enable_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x8); // Reserved + + // nn::settings::system::NetworkSettings + std::array<std::array<u8, 0x400>, 32> network_settings_1B0; + + // nn::settings::system::BluetoothDevicesSettings + std::array<u8, 0x4> bluetooth_device_settings_count; + bool bluetooth_enable_flag; + INSERT_PADDING_BYTES(0x3); + bool bluetooth_afh_enable_flag; + INSERT_PADDING_BYTES(0x3); + bool bluetooth_boost_enable_flag; + INSERT_PADDING_BYTES(0x3); + std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10; + + s32 ldn_channel; + INSERT_PADDING_BYTES(0x3C); // Reserved + + // nn::util::Uuid MiiAuthorId + Common::UUID mii_author_id; + + INSERT_PADDING_BYTES(0x30); // Reserved + + // nn::settings::system::NxControllerSettings + u32 nx_controller_settings_count; + + INSERT_PADDING_BYTES(0xC); // Reserved + + // nn::settings::system::NxControllerSettings, + // nn::settings::system::NxControllerLegacySettings on 13.0.0+ + std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings; + INSERT_PADDING_BYTES(0x170); // Reserved + + bool external_rtc_reset_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x3C); // Reserved + + s32 push_notification_activity_mode_on_sleep; + INSERT_PADDING_BYTES(0x3C); // Reserved + + ErrorReportSharePermission error_report_share_permission; + INSERT_PADDING_BYTES(0x3C); // Reserved + + KeyboardLayout keyboard_layout; + INSERT_PADDING_BYTES(0x3C); // Reserved + + bool web_inspector_flag; + INSERT_PADDING_BYTES(0x3); + + // nn::settings::system::AllowedSslHost + u32 allowed_ssl_host_count; + + bool memory_usage_rate_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x34); // Reserved + + // nn::settings::system::HostFsMountPoint + std::array<u8, 0x100> host_fs_mount_point; + + // nn::settings::system::AllowedSslHost + std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts; + INSERT_PADDING_BYTES(0x6C0); // Reserved + + // nn::settings::system::BlePairingSettings + u32 ble_pairing_settings_count; + INSERT_PADDING_BYTES(0xC); // Reserved + std::array<std::array<u8, 0x80>, 10> ble_pairing_settings; + + // nn::settings::system::AccountOnlineStorageSettings + u32 account_online_storage_settings_count; + INSERT_PADDING_BYTES(0xC); // Reserved + std::array<std::array<u8, 0x40>, 8> account_online_storage_settings; + + bool pctl_ready_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x3C); // Reserved + + // nn::settings::system::ThemeId + std::array<u8, 0x80> theme_id_type0; + std::array<u8, 0x80> theme_id_type1; + INSERT_PADDING_BYTES(0x100); // Reserved + + ChineseTraditionalInputMethod chinese_traditional_input_method; + INSERT_PADDING_BYTES(0x3C); // Reserved + + bool zoom_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x3C); // Reserved + + // nn::settings::system::ButtonConfigRegisteredSettings + u32 button_config_registered_settings_count; + INSERT_PADDING_BYTES(0xC); // Reserved + + // nn::settings::system::ButtonConfigSettings + u32 button_config_settings_count; + INSERT_PADDING_BYTES(0x4); // Reserved + std::array<std::array<u8, 0x5A8>, 5> button_config_settings; + INSERT_PADDING_BYTES(0x13B0); // Reserved + u32 button_config_settings_embedded_count; + INSERT_PADDING_BYTES(0x4); // Reserved + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded; + INSERT_PADDING_BYTES(0x13B0); // Reserved + u32 button_config_settings_left_count; + INSERT_PADDING_BYTES(0x4); // Reserved + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left; + INSERT_PADDING_BYTES(0x13B0); // Reserved + u32 button_config_settings_right_count; + INSERT_PADDING_BYTES(0x4); // Reserved + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right; + INSERT_PADDING_BYTES(0x73B0); // Reserved + // nn::settings::system::ButtonConfigRegisteredSettings + std::array<u8, 0x5C8> button_config_registered_settings_embedded; + std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings; + INSERT_PADDING_BYTES(0x7FF8); // Reserved + + // nn::settings::system::ConsoleSixAxisSensorAccelerationBias + Common::Vec3<f32> console_six_axis_sensor_acceleration_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias + Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias; + // nn::settings::system::ConsoleSixAxisSensorAccelerationGain + std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias + Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration; + INSERT_PADDING_BYTES(0x70); // Reserved + + bool lock_screen_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x4); // Reserved + + ColorSet color_set_id; + + QuestFlag quest_flag; + + SystemRegionCode region_code; + + // Different to nn::settings::system::InitialLaunchSettings? + InitialLaunchSettingsPacked initial_launch_settings_packed; + + bool battery_percentage_flag; + INSERT_PADDING_BYTES(0x3); + + // BitFlagSet<32, nn::settings::system::AppletLaunchFlag> + u32 applet_launch_flag; + + // nn::settings::system::ThemeSettings + std::array<u8, 0x8> theme_settings; + // nn::fssystem::ArchiveMacKey + std::array<u8, 0x10> theme_key; + + bool field_testing_flag; + INSERT_PADDING_BYTES(0x3); + + s32 panel_crc_mode; + INSERT_PADDING_BYTES(0x28); // Reserved + + // nn::settings::system::BacklightSettings + std::array<u8, 0x2C> backlight_settings_mixed_up; + INSERT_PADDING_BYTES(0x64); // Reserved + + // nn::time::SystemClockContext + Service::PSC::Time::SystemClockContext user_system_clock_context; + Service::PSC::Time::SystemClockContext network_system_clock_context; + bool user_system_clock_automatic_correction_enabled; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x4); // Reserved + // nn::time::SteadyClockTimePoint + Service::PSC::Time::SteadyClockTimePoint + user_system_clock_automatic_correction_updated_time_point; + INSERT_PADDING_BYTES(0x10); // Reserved + + AccountSettings account_settings; + INSERT_PADDING_BYTES(0xFC); // Reserved + + // nn::settings::system::AudioVolume + std::array<u8, 0x8> audio_volume_type0; + std::array<u8, 0x8> audio_volume_type1; + AudioOutputMode audio_output_mode_hdmi; + AudioOutputMode audio_output_mode_speaker; + AudioOutputMode audio_output_mode_headphone; + bool force_mute_on_headphone_removed; + INSERT_PADDING_BYTES(0x3); + s32 headphone_volume_warning_count; + bool heaphone_volume_update_flag; + INSERT_PADDING_BYTES(0x3); + // nn::settings::system::AudioVolume + std::array<u8, 0x8> audio_volume_type2; + AudioOutputMode audio_output_mode_type3; + AudioOutputMode audio_output_mode_type4; + bool hearing_protection_safeguard_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x4); // Reserved + s64 hearing_protection_safeguard_remaining_time; + INSERT_PADDING_BYTES(0x38); // Reserved + + bool console_information_upload_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x3C); // Reserved + + bool automatic_application_download_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x4); // Reserved + + NotificationSettings notification_settings; + INSERT_PADDING_BYTES(0x60); // Reserved + + // nn::settings::system::AccountNotificationSettings + u32 account_notification_settings_count; + INSERT_PADDING_BYTES(0xC); // Reserved + std::array<AccountNotificationSettings, 8> account_notification_settings; + INSERT_PADDING_BYTES(0x140); // Reserved + + f32 vibration_master_volume; + + bool usb_full_key_enable_flag; + INSERT_PADDING_BYTES(0x3); + + // nn::settings::system::AnalogStickUserCalibration + std::array<u8, 0x10> analog_stick_user_calibration_left; + std::array<u8, 0x10> analog_stick_user_calibration_right; + + // nn::settings::system::TouchScreenMode + s32 touch_screen_mode; + INSERT_PADDING_BYTES(0x14); // Reserved + + TvSettings tv_settings; + + // nn::settings::system::Edid + std::array<u8, 0x100> edid; + INSERT_PADDING_BYTES(0x2E0); // Reserved + + // nn::settings::system::DataDeletionSettings + std::array<u8, 0x8> data_deletion_settings; + INSERT_PADDING_BYTES(0x38); // Reserved + + // nn::ncm::ProgramId + std::array<u8, 0x8> initial_system_applet_program_id; + std::array<u8, 0x8> overlay_disp_program_id; + INSERT_PADDING_BYTES(0x4); // Reserved + + bool requires_run_repair_time_reviser; + INSERT_PADDING_BYTES(0x6B); // Reserved + + // nn::time::LocationName + Service::PSC::Time::LocationName device_time_zone_location_name; + INSERT_PADDING_BYTES(0x4); // Reserved + // nn::time::SteadyClockTimePoint + Service::PSC::Time::SteadyClockTimePoint device_time_zone_location_updated_time; + + INSERT_PADDING_BYTES(0xC0); // Reserved + + // nn::settings::system::PrimaryAlbumStorage + PrimaryAlbumStorage primary_album_storage; + INSERT_PADDING_BYTES(0x3C); // Reserved + + bool usb_30_enable_flag; + INSERT_PADDING_BYTES(0x3); + bool usb_30_host_enable_flag; + INSERT_PADDING_BYTES(0x3); + bool usb_30_device_enable_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x34); // Reserved + + bool nfc_enable_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x3C); // Reserved + + // nn::settings::system::SleepSettings + SleepSettings sleep_settings; + INSERT_PADDING_BYTES(0x34); // Reserved + + // nn::settings::system::EulaVersion + u32 eula_version_count; + INSERT_PADDING_BYTES(0xC); // Reserved + std::array<EulaVersion, 32> eula_versions; + INSERT_PADDING_BYTES(0x200); // Reserved + + // nn::settings::system::DeviceNickName + std::array<u8, 0x80> device_nick_name; + INSERT_PADDING_BYTES(0x80); // Reserved + + bool auto_update_enable_flag; + INSERT_PADDING_BYTES(0x3); + INSERT_PADDING_BYTES(0x4C); // Reserved + + // nn::settings::system::BluetoothDevicesSettings + std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14; + INSERT_PADDING_BYTES(0x2000); // Reserved + + // nn::settings::system::NxControllerSettings + std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30; +}; + +static_assert(offsetof(SystemSettings, language_code) == 0x10); +static_assert(offsetof(SystemSettings, network_setting_count) == 0x50); +static_assert(offsetof(SystemSettings, network_settings_1B0) == 0x60); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_count) == 0x8060); +static_assert(offsetof(SystemSettings, bluetooth_enable_flag) == 0x8064); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_first_10) == 0x8070); +static_assert(offsetof(SystemSettings, ldn_channel) == 0x9470); +static_assert(offsetof(SystemSettings, mii_author_id) == 0x94B0); +static_assert(offsetof(SystemSettings, nx_controller_settings_count) == 0x94F0); +static_assert(offsetof(SystemSettings, nx_controller_legacy_settings) == 0x9500); +static_assert(offsetof(SystemSettings, external_rtc_reset_flag) == 0x98F0); +static_assert(offsetof(SystemSettings, push_notification_activity_mode_on_sleep) == 0x9930); +static_assert(offsetof(SystemSettings, allowed_ssl_host_count) == 0x99F4); +static_assert(offsetof(SystemSettings, host_fs_mount_point) == 0x9A30); +static_assert(offsetof(SystemSettings, allowed_ssl_hosts) == 0x9B30); +static_assert(offsetof(SystemSettings, ble_pairing_settings_count) == 0xA9F0); +static_assert(offsetof(SystemSettings, ble_pairing_settings) == 0xAA00); +static_assert(offsetof(SystemSettings, account_online_storage_settings_count) == 0xAF00); +static_assert(offsetof(SystemSettings, account_online_storage_settings) == 0xAF10); +static_assert(offsetof(SystemSettings, pctl_ready_flag) == 0xB110); +static_assert(offsetof(SystemSettings, theme_id_type0) == 0xB150); +static_assert(offsetof(SystemSettings, chinese_traditional_input_method) == 0xB350); +static_assert(offsetof(SystemSettings, button_config_registered_settings_count) == 0xB3D0); +static_assert(offsetof(SystemSettings, button_config_settings_count) == 0xB3E0); +static_assert(offsetof(SystemSettings, button_config_settings) == 0xB3E8); +static_assert(offsetof(SystemSettings, button_config_registered_settings_embedded) == 0x1D3E0); +static_assert(offsetof(SystemSettings, console_six_axis_sensor_acceleration_bias) == 0x29370); +static_assert(offsetof(SystemSettings, lock_screen_flag) == 0x29470); +static_assert(offsetof(SystemSettings, battery_percentage_flag) == 0x294A0); +static_assert(offsetof(SystemSettings, field_testing_flag) == 0x294C0); +static_assert(offsetof(SystemSettings, backlight_settings_mixed_up) == 0x294F0); +static_assert(offsetof(SystemSettings, user_system_clock_context) == 0x29580); +static_assert(offsetof(SystemSettings, network_system_clock_context) == 0x295A0); +static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_enabled) == 0x295C0); +static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_updated_time_point) == + 0x295C8); +static_assert(offsetof(SystemSettings, account_settings) == 0x295F0); +static_assert(offsetof(SystemSettings, audio_volume_type0) == 0x296F0); +static_assert(offsetof(SystemSettings, hearing_protection_safeguard_remaining_time) == 0x29730); +static_assert(offsetof(SystemSettings, automatic_application_download_flag) == 0x297B0); +static_assert(offsetof(SystemSettings, notification_settings) == 0x297B8); +static_assert(offsetof(SystemSettings, account_notification_settings) == 0x29840); +static_assert(offsetof(SystemSettings, vibration_master_volume) == 0x29A40); +static_assert(offsetof(SystemSettings, analog_stick_user_calibration_left) == 0x29A48); +static_assert(offsetof(SystemSettings, touch_screen_mode) == 0x29A68); +static_assert(offsetof(SystemSettings, edid) == 0x29AA0); +static_assert(offsetof(SystemSettings, data_deletion_settings) == 0x29E80); +static_assert(offsetof(SystemSettings, requires_run_repair_time_reviser) == 0x29ED4); +static_assert(offsetof(SystemSettings, device_time_zone_location_name) == 0x29F40); +static_assert(offsetof(SystemSettings, nfc_enable_flag) == 0x2A0C0); +static_assert(offsetof(SystemSettings, eula_version_count) == 0x2A140); +static_assert(offsetof(SystemSettings, device_nick_name) == 0x2A950); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_last_14) == 0x2AAA0); +static_assert(offsetof(SystemSettings, nx_controller_settings_data_from_offset_30) == 0x2E6A0); + +static_assert(sizeof(SystemSettings) == 0x336A0, "SystemSettings has the wrong size!"); + +SystemSettings DefaultSystemSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp index c48844f77..73d021ff4 100644 --- a/src/core/hle/service/set/settings.cpp +++ b/src/core/hle/service/set/settings.cpp @@ -2,21 +2,24 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/server_manager.h" -#include "core/hle/service/set/set.h" -#include "core/hle/service/set/set_cal.h" -#include "core/hle/service/set/set_fd.h" -#include "core/hle/service/set/set_sys.h" +#include "core/hle/service/set/factory_settings_server.h" +#include "core/hle/service/set/firmware_debug_settings_server.h" #include "core/hle/service/set/settings.h" +#include "core/hle/service/set/settings_server.h" +#include "core/hle/service/set/system_settings_server.h" namespace Service::Set { void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - server_manager->RegisterNamedService("set", std::make_shared<SET>(system)); - server_manager->RegisterNamedService("set:cal", std::make_shared<SET_CAL>(system)); - server_manager->RegisterNamedService("set:fd", std::make_shared<SET_FD>(system)); - server_manager->RegisterNamedService("set:sys", std::make_shared<SET_SYS>(system)); + server_manager->RegisterNamedService("set", std::make_shared<ISettingsServer>(system)); + server_manager->RegisterNamedService("set:cal", + std::make_shared<IFactorySettingsServer>(system)); + server_manager->RegisterNamedService("set:fd", + std::make_shared<IFirmwareDebugSettingsServer>(system)); + server_manager->RegisterNamedService("set:sys", + std::make_shared<ISystemSettingsServer>(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/set/settings_server.cpp b/src/core/hle/service/set/settings_server.cpp new file mode 100644 index 000000000..b2caa00ff --- /dev/null +++ b/src/core/hle/service/set/settings_server.cpp @@ -0,0 +1,166 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <algorithm> +#include <array> +#include <chrono> +#include "common/logging/log.h" +#include "common/settings.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/set/settings_server.h" + +namespace Service::Set { +namespace { +constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF; +constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40; + +constexpr Result ResultInvalidLanguage{ErrorModule::Settings, 625}; + +void PushResponseLanguageCode(HLERequestContext& ctx, std::size_t num_language_codes) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(num_language_codes)); +} + +void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entries) { + const std::size_t requested_amount = ctx.GetWriteBufferNumElements<LanguageCode>(); + const std::size_t max_amount = std::min(requested_amount, max_entries); + const std::size_t copy_amount = std::min(available_language_codes.size(), max_amount); + const std::size_t copy_size = copy_amount * sizeof(LanguageCode); + + ctx.WriteBuffer(available_language_codes.data(), copy_size); + PushResponseLanguageCode(ctx, copy_amount); +} + +void GetKeyCodeMapImpl(HLERequestContext& ctx) { + const auto language_code = + available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]; + const auto key_code = + std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), + [=](const auto& element) { return element.first == language_code; }); + KeyboardLayout layout = KeyboardLayout::EnglishUs; + if (key_code == language_to_layout.cend()) { + LOG_ERROR(Service_SET, + "Could not find keyboard layout for language index {}, defaulting to English us", + Settings::values.language_index.GetValue()); + } else { + layout = key_code->second; + } + + ctx.WriteBuffer(layout); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} +} // Anonymous namespace + +LanguageCode GetLanguageCodeFromIndex(std::size_t index) { + return available_language_codes.at(index); +} + +ISettingsServer::ISettingsServer(Core::System& system_) : ServiceFramework{system_, "set"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISettingsServer::GetLanguageCode, "GetLanguageCode"}, + {1, &ISettingsServer::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, + {2, &ISettingsServer::MakeLanguageCode, "MakeLanguageCode"}, + {3, &ISettingsServer::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, + {4, &ISettingsServer::GetRegionCode, "GetRegionCode"}, + {5, &ISettingsServer::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, + {6, &ISettingsServer::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, + {7, &ISettingsServer::GetKeyCodeMap, "GetKeyCodeMap"}, + {8, &ISettingsServer::GetQuestFlag, "GetQuestFlag"}, + {9, &ISettingsServer::GetKeyCodeMap2, "GetKeyCodeMap2"}, + {10, nullptr, "GetFirmwareVersionForDebug"}, + {11, &ISettingsServer::GetDeviceNickName, "GetDeviceNickName"}, + }; + // clang-format on + + RegisterHandlers(functions); +} + +ISettingsServer::~ISettingsServer() = default; + +void ISettingsServer::GetAvailableLanguageCodes(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES); +} + +void ISettingsServer::MakeLanguageCode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto index = rp.Pop<u32>(); + + if (index >= available_language_codes.size()) { + LOG_ERROR(Service_SET, "Invalid language code index! index={}", index); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Set::ResultInvalidLanguage); + return; + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushEnum(available_language_codes[index]); +} + +void ISettingsServer::GetAvailableLanguageCodes2(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES); +} + +void ISettingsServer::GetAvailableLanguageCodeCount(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES); +} + +void ISettingsServer::GetAvailableLanguageCodeCount2(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES); +} + +void ISettingsServer::GetQuestFlag(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<s32>(Settings::values.quest_flag.GetValue())); +} + +void ISettingsServer::GetLanguageCode(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue()); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.PushEnum( + available_language_codes[static_cast<s32>(Settings::values.language_index.GetValue())]); +} + +void ISettingsServer::GetRegionCode(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(Settings::values.region_index.GetValue())); +} + +void ISettingsServer::GetKeyCodeMap(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); + GetKeyCodeMapImpl(ctx); +} + +void ISettingsServer::GetKeyCodeMap2(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); + GetKeyCodeMapImpl(ctx); +} + +void ISettingsServer::GetDeviceNickName(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + ctx.WriteBuffer(Settings::values.device_name.GetValue()); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/settings_server.h b/src/core/hle/service/set/settings_server.h new file mode 100644 index 000000000..8304e8424 --- /dev/null +++ b/src/core/hle/service/set/settings_server.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/service/service.h" +#include "core/hle/service/set/settings_types.h" + +namespace Core { +class System; +} + +namespace Service::Set { + +LanguageCode GetLanguageCodeFromIndex(std::size_t idx); + +class ISettingsServer final : public ServiceFramework<ISettingsServer> { +public: + explicit ISettingsServer(Core::System& system_); + ~ISettingsServer() override; + +private: + void GetLanguageCode(HLERequestContext& ctx); + void GetAvailableLanguageCodes(HLERequestContext& ctx); + void MakeLanguageCode(HLERequestContext& ctx); + void GetAvailableLanguageCodes2(HLERequestContext& ctx); + void GetAvailableLanguageCodeCount(HLERequestContext& ctx); + void GetAvailableLanguageCodeCount2(HLERequestContext& ctx); + void GetQuestFlag(HLERequestContext& ctx); + void GetRegionCode(HLERequestContext& ctx); + void GetKeyCodeMap(HLERequestContext& ctx); + void GetKeyCodeMap2(HLERequestContext& ctx); + void GetDeviceNickName(HLERequestContext& ctx); +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h new file mode 100644 index 000000000..ceb85b82a --- /dev/null +++ b/src/core/hle/service/set/settings_types.h @@ -0,0 +1,475 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/uuid.h" +#include "core/hle/service/psc/time/common.h" + +namespace Service::Set { + +/// This is nn::settings::system::AudioOutputMode +enum class AudioOutputMode : u32 { + ch_1, + ch_2, + ch_5_1, + ch_7_1, +}; + +/// This is nn::settings::system::AudioOutputModeTarget +enum class AudioOutputModeTarget : u32 { + None, + Hdmi, + Speaker, + Headphone, + Type3, + Type4, +}; + +/// This is nn::settings::system::AudioVolumeTarget +enum class AudioVolumeTarget : u32 { + Speaker, + Headphone, +}; + +/// This is nn::settings::system::ClockSourceId +enum class ClockSourceId : u32 { + NetworkSystemClock, + SteadyClock, +}; + +/// This is nn::settings::system::CmuMode +enum class CmuMode : u32 { + None, + ColorInvert, + HighContrast, + GrayScale, +}; + +/// This is nn::settings::system::ChineseTraditionalInputMethod +enum class ChineseTraditionalInputMethod : u32 { + Unknown0 = 0, + Unknown1 = 1, + Unknown2 = 2, +}; + +/// Indicates the current theme set by the system settings +enum class ColorSet : u32 { + BasicWhite = 0, + BasicBlack = 1, +}; + +/// This is nn::settings::system::ConsoleSleepPlan +enum class ConsoleSleepPlan : u32 { + Sleep1Hour, + Sleep2Hour, + Sleep3Hour, + Sleep6Hour, + Sleep12Hour, + Never, +}; + +/// This is nn::settings::system::ErrorReportSharePermission +enum class ErrorReportSharePermission : u32 { + NotConfirmed, + Granted, + Denied, +}; + +/// This is nn::settings::system::EulaVersionClockType +enum class EulaVersionClockType : u32 { + NetworkSystemClock, + SteadyClock, +}; + +/// This is nn::settings::factory::RegionCode +enum class FactoryRegionCode : u32 { + Japan, + Usa, + Europe, + Australia, + China, + Korea, + Taiwan, +}; + +/// This is nn::settings::system::FriendPresenceOverlayPermission +enum class FriendPresenceOverlayPermission : u8 { + NotConfirmed, + NoDisplay, + FavoriteFriends, + Friends, +}; + +enum class GetFirmwareVersionType { + Version1, + Version2, +}; + +/// This is nn::settings::system::HandheldSleepPlan +enum class HandheldSleepPlan : u32 { + Sleep1Min, + Sleep3Min, + Sleep5Min, + Sleep10Min, + Sleep30Min, + Never, +}; + +/// This is nn::settings::system::HdmiContentType +enum class HdmiContentType : u32 { + None, + Graphics, + Cinema, + Photo, + Game, +}; + +enum class KeyboardLayout : u32 { + Japanese = 0, + EnglishUs = 1, + EnglishUsInternational = 2, + EnglishUk = 3, + French = 4, + FrenchCa = 5, + Spanish = 6, + SpanishLatin = 7, + German = 8, + Italian = 9, + Portuguese = 10, + Russian = 11, + Korean = 12, + ChineseSimplified = 13, + ChineseTraditional = 14, +}; + +/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. +enum class LanguageCode : u64 { + JA = 0x000000000000616A, + EN_US = 0x00000053552D6E65, + FR = 0x0000000000007266, + DE = 0x0000000000006564, + IT = 0x0000000000007469, + ES = 0x0000000000007365, + ZH_CN = 0x0000004E432D687A, + KO = 0x0000000000006F6B, + NL = 0x0000000000006C6E, + PT = 0x0000000000007470, + RU = 0x0000000000007572, + ZH_TW = 0x00000057542D687A, + EN_GB = 0x00000042472D6E65, + FR_CA = 0x00000041432D7266, + ES_419 = 0x00003931342D7365, + ZH_HANS = 0x00736E61482D687A, + ZH_HANT = 0x00746E61482D687A, + PT_BR = 0x00000052422D7470, +}; + +/// This is nn::settings::system::NotificationVolume +enum class NotificationVolume : u32 { + Mute, + Low, + High, +}; + +/// This is nn::settings::system::PrimaryAlbumStorage +enum class PrimaryAlbumStorage : u32 { + Nand, + SdCard, +}; + +/// Indicates the current console is a retail or kiosk unit +enum class QuestFlag : u8 { + Retail = 0, + Kiosk = 1, +}; + +/// This is nn::settings::system::RgbRange +enum class RgbRange : u32 { + Auto, + Full, + Limited, +}; + +/// This is nn::settings::system::RegionCode +enum class SystemRegionCode : u32 { + Japan, + Usa, + Europe, + Australia, + HongKongTaiwanKorea, + China, +}; + +/// This is nn::settings::system::TouchScreenMode +enum class TouchScreenMode : u32 { + Stylus, + Standard, +}; + +/// This is nn::settings::system::TvResolution +enum class TvResolution : u32 { + Auto, + Resolution1080p, + Resolution720p, + Resolution480p, +}; + +constexpr std::array<LanguageCode, 18> available_language_codes = {{ + LanguageCode::JA, + LanguageCode::EN_US, + LanguageCode::FR, + LanguageCode::DE, + LanguageCode::IT, + LanguageCode::ES, + LanguageCode::ZH_CN, + LanguageCode::KO, + LanguageCode::NL, + LanguageCode::PT, + LanguageCode::RU, + LanguageCode::ZH_TW, + LanguageCode::EN_GB, + LanguageCode::FR_CA, + LanguageCode::ES_419, + LanguageCode::ZH_HANS, + LanguageCode::ZH_HANT, + LanguageCode::PT_BR, +}}; + +static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{ + {LanguageCode::JA, KeyboardLayout::Japanese}, + {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, + {LanguageCode::FR, KeyboardLayout::French}, + {LanguageCode::DE, KeyboardLayout::German}, + {LanguageCode::IT, KeyboardLayout::Italian}, + {LanguageCode::ES, KeyboardLayout::Spanish}, + {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, + {LanguageCode::KO, KeyboardLayout::Korean}, + {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, + {LanguageCode::PT, KeyboardLayout::Portuguese}, + {LanguageCode::RU, KeyboardLayout::Russian}, + {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, + {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, + {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, + {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, + {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, + {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, + {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, +}}; + +/// This is nn::settings::system::AccountNotificationFlag +struct AccountNotificationFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> FriendOnlineFlag; + BitField<1, 1, u32> FriendRequestFlag; + BitField<8, 1, u32> CoralInvitationFlag; + }; +}; +static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size"); + +/// This is nn::settings::system::AccountSettings +struct AccountSettings { + u32 flags; +}; +static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size"); + +/// This is nn::settings::system::DataDeletionFlag +struct DataDeletionFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> AutomaticDeletionFlag; + }; +}; +static_assert(sizeof(DataDeletionFlag) == 4, "DataDeletionFlag is an invalid size"); + +/// This is nn::settings::system::InitialLaunchFlag +struct InitialLaunchFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> InitialLaunchCompletionFlag; + BitField<8, 1, u32> InitialLaunchUserAdditionFlag; + BitField<16, 1, u32> InitialLaunchTimestampFlag; + }; +}; +static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); + +/// This is nn::settings::system::SleepFlag +struct SleepFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> SleepsWhilePlayingMedia; + BitField<1, 1, u32> WakesAtPowerStateChange; + }; +}; +static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); + +/// This is nn::settings::system::NotificationFlag +struct NotificationFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> RingtoneFlag; + BitField<1, 1, u32> DownloadCompletionFlag; + BitField<8, 1, u32> EnablesNews; + BitField<9, 1, u32> IncomingLampFlag; + }; +}; +static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); + +struct PlatformConfig { + union { + u32 raw{}; + BitField<0, 1, u32> has_rail_interface; + BitField<1, 1, u32> has_sio_mcu; + }; +}; +static_assert(sizeof(PlatformConfig) == 0x4, "PlatformConfig is an invalid size"); + +/// This is nn::settings::system::TvFlag +struct TvFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> Allows4k; + BitField<1, 1, u32> Allows3d; + BitField<2, 1, u32> AllowsCec; + BitField<3, 1, u32> PreventsScreenBurnIn; + }; +}; +static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); + +/// This is nn::settings::system::UserSelectorFlag +struct UserSelectorFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> SkipIfSingleUser; + BitField<31, 1, u32> Unknown; + }; +}; +static_assert(sizeof(UserSelectorFlag) == 4, "UserSelectorFlag is an invalid size"); + +/// This is nn::settings::system::AccountNotificationSettings +struct AccountNotificationSettings { + Common::UUID uid; + AccountNotificationFlag flags; + FriendPresenceOverlayPermission friend_presence_permission; + FriendPresenceOverlayPermission friend_invitation_permission; + INSERT_PADDING_BYTES(0x2); +}; +static_assert(sizeof(AccountNotificationSettings) == 0x18, + "AccountNotificationSettings is an invalid size"); + +/// This is nn::settings::factory::BatteryLot +struct BatteryLot { + std::array<char, 0x18> lot_number; +}; +static_assert(sizeof(BatteryLot) == 0x18, "BatteryLot is an invalid size"); + +/// This is nn::settings::system::EulaVersion +struct EulaVersion { + u32 version; + SystemRegionCode region_code; + EulaVersionClockType clock_type; + INSERT_PADDING_BYTES(0x4); + s64 posix_time; + Service::PSC::Time::SteadyClockTimePoint timestamp; +}; +static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); + +struct FirmwareVersionFormat { + u8 major; + u8 minor; + u8 micro; + INSERT_PADDING_BYTES(1); + u8 revision_major; + u8 revision_minor; + INSERT_PADDING_BYTES(2); + std::array<char, 0x20> platform; + std::array<u8, 0x40> version_hash; + std::array<char, 0x18> display_version; + std::array<char, 0x80> display_title; +}; +static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size"); + +/// This is nn::settings::system::HomeMenuScheme +struct HomeMenuScheme { + u32 main; + u32 back; + u32 sub; + u32 bezel; + u32 extra; +}; +static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); + +/// This is nn::settings::system::InitialLaunchSettings +struct InitialLaunchSettings { + InitialLaunchFlag flags; + INSERT_PADDING_BYTES(0x4); + Service::PSC::Time::SteadyClockTimePoint timestamp; +}; +static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); + +#pragma pack(push, 4) +struct InitialLaunchSettingsPacked { + InitialLaunchFlag flags; + Service::PSC::Time::SteadyClockTimePoint timestamp; +}; +#pragma pack(pop) +static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, + "InitialLaunchSettingsPacked is incorrect size"); + +/// This is nn::settings::system::NotificationTime +struct NotificationTime { + u32 hour; + u32 minute; +}; +static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); + +/// This is nn::settings::system::NotificationSettings +struct NotificationSettings { + NotificationFlag flags; + NotificationVolume volume; + NotificationTime start_time; + NotificationTime stop_time; +}; +static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); + +/// This is nn::settings::factory::SerialNumber +struct SerialNumber { + std::array<char, 0x18> serial_number; +}; +static_assert(sizeof(SerialNumber) == 0x18, "SerialNumber is an invalid size"); + +/// This is nn::settings::system::SleepSettings +struct SleepSettings { + SleepFlag flags; + HandheldSleepPlan handheld_sleep_plan; + ConsoleSleepPlan console_sleep_plan; +}; +static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); + +/// This is nn::settings::system::TvSettings +struct TvSettings { + TvFlag flags; + TvResolution tv_resolution; + HdmiContentType hdmi_content_type; + RgbRange rgb_range; + CmuMode cmu_mode; + u32 tv_underscan; + f32 tv_gama; + f32 contrast_ratio; +}; +static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp deleted file mode 100644 index 2723417ad..000000000 --- a/src/core/hle/service/set/system_settings.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/set/system_settings.h" - -namespace Service::Set { - -SystemSettings DefaultSystemSettings() { - SystemSettings settings{}; - - settings.version = 0x140000; - settings.flags = 7; - - settings.color_set_id = ColorSet::BasicWhite; - - settings.notification_settings = { - .flags{0x300}, - .volume = NotificationVolume::High, - .start_time = {.hour = 9, .minute = 0}, - .stop_time = {.hour = 21, .minute = 0}, - }; - - settings.tv_settings = { - .flags = {0xC}, - .tv_resolution = TvResolution::Auto, - .hdmi_content_type = HdmiContentType::Game, - .rgb_range = RgbRange::Auto, - .cmu_mode = CmuMode::None, - .tv_underscan = {}, - .tv_gama = 1.0f, - .constrast_ratio = 0.5f, - }; - - settings.initial_launch_settings_packed = { - .flags = {0x10001}, - .timestamp = {}, - }; - - settings.sleep_settings = { - .flags = {0x3}, - .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min, - .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour, - }; - - settings.device_time_zone_location_name = {"UTC"}; - settings.user_system_clock_automatic_correction_enabled = false; - - return settings; -} - -} // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h deleted file mode 100644 index ded2906ad..000000000 --- a/src/core/hle/service/set/system_settings.h +++ /dev/null @@ -1,699 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> - -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/service/set/private_settings.h" -#include "core/hle/service/time/clock_types.h" - -namespace Service::Set { - -/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. -enum class LanguageCode : u64 { - JA = 0x000000000000616A, - EN_US = 0x00000053552D6E65, - FR = 0x0000000000007266, - DE = 0x0000000000006564, - IT = 0x0000000000007469, - ES = 0x0000000000007365, - ZH_CN = 0x0000004E432D687A, - KO = 0x0000000000006F6B, - NL = 0x0000000000006C6E, - PT = 0x0000000000007470, - RU = 0x0000000000007572, - ZH_TW = 0x00000057542D687A, - EN_GB = 0x00000042472D6E65, - FR_CA = 0x00000041432D7266, - ES_419 = 0x00003931342D7365, - ZH_HANS = 0x00736E61482D687A, - ZH_HANT = 0x00746E61482D687A, - PT_BR = 0x00000052422D7470, -}; - -/// This is nn::settings::system::ErrorReportSharePermission -enum class ErrorReportSharePermission : u32 { - NotConfirmed, - Granted, - Denied, -}; - -/// This is nn::settings::system::ChineseTraditionalInputMethod -enum class ChineseTraditionalInputMethod : u32 { - Unknown0 = 0, - Unknown1 = 1, - Unknown2 = 2, -}; - -/// This is nn::settings::system::HomeMenuScheme -struct HomeMenuScheme { - u32 main; - u32 back; - u32 sub; - u32 bezel; - u32 extra; -}; -static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); - -/// Indicates the current theme set by the system settings -enum class ColorSet : u32 { - BasicWhite = 0, - BasicBlack = 1, -}; - -/// Indicates the current console is a retail or kiosk unit -enum class QuestFlag : u8 { - Retail = 0, - Kiosk = 1, -}; - -/// This is nn::settings::system::RegionCode -enum class RegionCode : u32 { - Japan, - Usa, - Europe, - Australia, - HongKongTaiwanKorea, - China, -}; - -/// This is nn::settings::system::AccountSettings -struct AccountSettings { - u32 flags; -}; -static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size"); - -/// This is nn::settings::system::NotificationVolume -enum class NotificationVolume : u32 { - Mute, - Low, - High, -}; - -/// This is nn::settings::system::NotificationFlag -struct NotificationFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> RingtoneFlag; - BitField<1, 1, u32> DownloadCompletionFlag; - BitField<8, 1, u32> EnablesNews; - BitField<9, 1, u32> IncomingLampFlag; - }; -}; -static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); - -/// This is nn::settings::system::NotificationTime -struct NotificationTime { - u32 hour; - u32 minute; -}; -static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); - -/// This is nn::settings::system::NotificationSettings -struct NotificationSettings { - NotificationFlag flags; - NotificationVolume volume; - NotificationTime start_time; - NotificationTime stop_time; -}; -static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); - -/// This is nn::settings::system::AccountNotificationFlag -struct AccountNotificationFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> FriendOnlineFlag; - BitField<1, 1, u32> FriendRequestFlag; - BitField<8, 1, u32> CoralInvitationFlag; - }; -}; -static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size"); - -/// This is nn::settings::system::FriendPresenceOverlayPermission -enum class FriendPresenceOverlayPermission : u8 { - NotConfirmed, - NoDisplay, - FavoriteFriends, - Friends, -}; - -/// This is nn::settings::system::AccountNotificationSettings -struct AccountNotificationSettings { - Common::UUID uid; - AccountNotificationFlag flags; - FriendPresenceOverlayPermission friend_presence_permission; - FriendPresenceOverlayPermission friend_invitation_permission; - INSERT_PADDING_BYTES(0x2); -}; -static_assert(sizeof(AccountNotificationSettings) == 0x18, - "AccountNotificationSettings is an invalid size"); - -/// This is nn::settings::system::TvFlag -struct TvFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> Allows4k; - BitField<1, 1, u32> Allows3d; - BitField<2, 1, u32> AllowsCec; - BitField<3, 1, u32> PreventsScreenBurnIn; - }; -}; -static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); - -/// This is nn::settings::system::TvResolution -enum class TvResolution : u32 { - Auto, - Resolution1080p, - Resolution720p, - Resolution480p, -}; - -/// This is nn::settings::system::HdmiContentType -enum class HdmiContentType : u32 { - None, - Graphics, - Cinema, - Photo, - Game, -}; - -/// This is nn::settings::system::RgbRange -enum class RgbRange : u32 { - Auto, - Full, - Limited, -}; - -/// This is nn::settings::system::CmuMode -enum class CmuMode : u32 { - None, - ColorInvert, - HighContrast, - GrayScale, -}; - -/// This is nn::settings::system::TvSettings -struct TvSettings { - TvFlag flags; - TvResolution tv_resolution; - HdmiContentType hdmi_content_type; - RgbRange rgb_range; - CmuMode cmu_mode; - u32 tv_underscan; - f32 tv_gama; - f32 constrast_ratio; -}; -static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); - -/// This is nn::settings::system::PrimaryAlbumStorage -enum class PrimaryAlbumStorage : u32 { - Nand, - SdCard, -}; - -/// This is nn::settings::system::HandheldSleepPlan -enum class HandheldSleepPlan : u32 { - Sleep1Min, - Sleep3Min, - Sleep5Min, - Sleep10Min, - Sleep30Min, - Never, -}; - -/// This is nn::settings::system::ConsoleSleepPlan -enum class ConsoleSleepPlan : u32 { - Sleep1Hour, - Sleep2Hour, - Sleep3Hour, - Sleep6Hour, - Sleep12Hour, - Never, -}; - -/// This is nn::settings::system::SleepFlag -struct SleepFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> SleepsWhilePlayingMedia; - BitField<1, 1, u32> WakesAtPowerStateChange; - }; -}; -static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); - -/// This is nn::settings::system::SleepSettings -struct SleepSettings { - SleepFlag flags; - HandheldSleepPlan handheld_sleep_plan; - ConsoleSleepPlan console_sleep_plan; -}; -static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); - -/// This is nn::settings::system::EulaVersionClockType -enum class EulaVersionClockType : u32 { - NetworkSystemClock, - SteadyClock, -}; - -/// This is nn::settings::system::EulaVersion -struct EulaVersion { - u32 version; - RegionCode region_code; - EulaVersionClockType clock_type; - INSERT_PADDING_BYTES(0x4); - s64 posix_time; - Time::Clock::SteadyClockTimePoint timestamp; -}; -static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); - -struct SystemSettings { - // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000 - // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000 - // (9.0.0-10.0.4), 0x100100 (10.1.0+), 0x120000 (12.0.0-12.1.0), 0x130000 (13.0.0-13.2.1), - // 0x140000 (14.0.0+) - u32 version; - // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+). - // if (flags & 2), defaults are written for AnalogStickUserCalibration - u32 flags; - - std::array<u8, 0x8> reserved_00008; - - // nn::settings::LanguageCode - LanguageCode language_code; - - std::array<u8, 0x38> reserved_00018; - - // nn::settings::system::NetworkSettings - u32 network_setting_count; - bool wireless_lan_enable_flag; - std::array<u8, 0x3> pad_00055; - - std::array<u8, 0x8> reserved_00058; - - // nn::settings::system::NetworkSettings - std::array<std::array<u8, 0x400>, 32> network_settings_1B0; - - // nn::settings::system::BluetoothDevicesSettings - std::array<u8, 0x4> bluetooth_device_settings_count; - bool bluetooth_enable_flag; - std::array<u8, 0x3> pad_08065; - bool bluetooth_afh_enable_flag; - std::array<u8, 0x3> pad_08069; - bool bluetooth_boost_enable_flag; - std::array<u8, 0x3> pad_0806D; - std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10; - - s32 ldn_channel; - - std::array<u8, 0x3C> reserved_09474; - - // nn::util::Uuid MiiAuthorId - std::array<u8, 0x10> mii_author_id; - - std::array<u8, 0x30> reserved_094C0; - - // nn::settings::system::NxControllerSettings - u32 nx_controller_settings_count; - - std::array<u8, 0xC> reserved_094F4; - - // nn::settings::system::NxControllerSettings, - // nn::settings::system::NxControllerLegacySettings on 13.0.0+ - std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings; - - std::array<u8, 0x170> reserved_09780; - - bool external_rtc_reset_flag; - std::array<u8, 0x3> pad_098F1; - - std::array<u8, 0x3C> reserved_098F4; - - s32 push_notification_activity_mode_on_sleep; - - std::array<u8, 0x3C> reserved_09934; - - // nn::settings::system::ErrorReportSharePermission - ErrorReportSharePermission error_report_share_permssion; - - std::array<u8, 0x3C> reserved_09974; - - // nn::settings::KeyboardLayout - std::array<u8, 0x4> keyboard_layout; - - std::array<u8, 0x3C> reserved_099B4; - - bool web_inspector_flag; - std::array<u8, 0x3> pad_099F1; - - // nn::settings::system::AllowedSslHost - u32 allowed_ssl_host_count; - - bool memory_usage_rate_flag; - std::array<u8, 0x3> pad_099F9; - - std::array<u8, 0x34> reserved_099FC; - - // nn::settings::system::HostFsMountPoint - std::array<u8, 0x100> host_fs_mount_point; - - // nn::settings::system::AllowedSslHost - std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts; - - std::array<u8, 0x6C0> reserved_0A330; - - // nn::settings::system::BlePairingSettings - u32 ble_pairing_settings_count; - std::array<u8, 0xC> reserved_0A9F4; - std::array<std::array<u8, 0x80>, 10> ble_pairing_settings; - - // nn::settings::system::AccountOnlineStorageSettings - u32 account_online_storage_settings_count; - std::array<u8, 0xC> reserved_0AF04; - std::array<std::array<u8, 0x40>, 8> account_online_storage_settings; - - bool pctl_ready_flag; - std::array<u8, 0x3> pad_0B111; - - std::array<u8, 0x3C> reserved_0B114; - - // nn::settings::system::ThemeId - std::array<u8, 0x80> theme_id_type0; - std::array<u8, 0x80> theme_id_type1; - - std::array<u8, 0x100> reserved_0B250; - - // nn::settings::ChineseTraditionalInputMethod - ChineseTraditionalInputMethod chinese_traditional_input_method; - - std::array<u8, 0x3C> reserved_0B354; - - bool zoom_flag; - std::array<u8, 0x3> pad_0B391; - - std::array<u8, 0x3C> reserved_0B394; - - // nn::settings::system::ButtonConfigRegisteredSettings - u32 button_config_registered_settings_count; - std::array<u8, 0xC> reserved_0B3D4; - - // nn::settings::system::ButtonConfigSettings - u32 button_config_settings_count; - std::array<u8, 0x4> reserved_0B3E4; - std::array<std::array<u8, 0x5A8>, 5> button_config_settings; - std::array<u8, 0x13B0> reserved_0D030; - u32 button_config_settings_embedded_count; - std::array<u8, 0x4> reserved_0E3E4; - std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded; - std::array<u8, 0x13B0> reserved_10030; - u32 button_config_settings_left_count; - std::array<u8, 0x4> reserved_113E4; - std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left; - std::array<u8, 0x13B0> reserved_13030; - u32 button_config_settings_right_count; - std::array<u8, 0x4> reserved_143E4; - std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right; - std::array<u8, 0x73B0> reserved_16030; - // nn::settings::system::ButtonConfigRegisteredSettings - std::array<u8, 0x5C8> button_config_registered_settings_embedded; - std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings; - - std::array<u8, 0x7FF8> reserved_21378; - - // nn::settings::system::ConsoleSixAxisSensorAccelerationBias - std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias - std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; - // nn::settings::system::ConsoleSixAxisSensorAccelerationGain - std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain - std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; - // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias - std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; - // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration - std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration; - - std::array<u8, 0x70> reserved_29400; - - bool lock_screen_flag; - std::array<u8, 0x3> pad_29471; - - std::array<u8, 0x4> reserved_249274; - - ColorSet color_set_id; - - QuestFlag quest_flag; - - // nn::settings::system::RegionCode - RegionCode region_code; - - // Different to nn::settings::system::InitialLaunchSettings? - InitialLaunchSettingsPacked initial_launch_settings_packed; - - bool battery_percentage_flag; - std::array<u8, 0x3> pad_294A1; - - // BitFlagSet<32, nn::settings::system::AppletLaunchFlag> - u32 applet_launch_flag; - - // nn::settings::system::ThemeSettings - std::array<u8, 0x8> theme_settings; - // nn::fssystem::ArchiveMacKey - std::array<u8, 0x10> theme_key; - - bool field_testing_flag; - std::array<u8, 0x3> pad_294C1; - - s32 panel_crc_mode; - - std::array<u8, 0x28> reserved_294C8; - - // nn::settings::system::BacklightSettings - std::array<u8, 0x2C> backlight_settings_mixed_up; - - std::array<u8, 0x64> reserved_2951C; - - // nn::time::SystemClockContext - Service::Time::Clock::SystemClockContext user_system_clock_context; - Service::Time::Clock::SystemClockContext network_system_clock_context; - bool user_system_clock_automatic_correction_enabled; - std::array<u8, 0x3> pad_295C1; - std::array<u8, 0x4> reserved_295C4; - // nn::time::SteadyClockTimePoint - Service::Time::Clock::SteadyClockTimePoint - user_system_clock_automatic_correction_updated_time_point; - - std::array<u8, 0x10> reserved_295E0; - - // nn::settings::system::AccountSettings - AccountSettings account_settings; - - std::array<u8, 0xFC> reserved_295F4; - - // nn::settings::system::AudioVolume - std::array<u8, 0x8> audio_volume_type0; - std::array<u8, 0x8> audio_volume_type1; - // nn::settings::system::AudioOutputMode - s32 audio_output_mode_type0; - s32 audio_output_mode_type1; - s32 audio_output_mode_type2; - bool force_mute_on_headphone_removed; - std::array<u8, 0x3> pad_2970D; - s32 headphone_volume_warning_count; - bool heaphone_volume_update_flag; - std::array<u8, 0x3> pad_29715; - // nn::settings::system::AudioVolume - std::array<u8, 0x8> audio_volume_type2; - // nn::settings::system::AudioOutputMode - s32 audio_output_mode_type3; - s32 audio_output_mode_type4; - bool hearing_protection_safeguard_flag; - std::array<u8, 0x3> pad_29729; - std::array<u8, 0x4> reserved_2972C; - s64 hearing_protection_safeguard_remaining_time; - std::array<u8, 0x38> reserved_29738; - - bool console_information_upload_flag; - std::array<u8, 0x3> pad_29771; - - std::array<u8, 0x3C> reserved_29774; - - bool automatic_application_download_flag; - std::array<u8, 0x3> pad_297B1; - - std::array<u8, 0x4> reserved_297B4; - - // nn::settings::system::NotificationSettings - NotificationSettings notification_settings; - - std::array<u8, 0x60> reserved_297D0; - - // nn::settings::system::AccountNotificationSettings - u32 account_notification_settings_count; - std::array<u8, 0xC> reserved_29834; - std::array<AccountNotificationSettings, 8> account_notification_settings; - - std::array<u8, 0x140> reserved_29900; - - f32 vibration_master_volume; - - bool usb_full_key_enable_flag; - std::array<u8, 0x3> pad_29A45; - - // nn::settings::system::AnalogStickUserCalibration - std::array<u8, 0x10> analog_stick_user_calibration_left; - std::array<u8, 0x10> analog_stick_user_calibration_right; - - // nn::settings::system::TouchScreenMode - s32 touch_screen_mode; - - std::array<u8, 0x14> reserved_29A6C; - - // nn::settings::system::TvSettings - TvSettings tv_settings; - - // nn::settings::system::Edid - std::array<u8, 0x100> edid; - - std::array<u8, 0x2E0> reserved_29BA0; - - // nn::settings::system::DataDeletionSettings - std::array<u8, 0x8> data_deletion_settings; - - std::array<u8, 0x38> reserved_29E88; - - // nn::ncm::ProgramId - std::array<u8, 0x8> initial_system_applet_program_id; - std::array<u8, 0x8> overlay_disp_program_id; - - std::array<u8, 0x4> reserved_29ED0; - - bool requires_run_repair_time_reviser; - - std::array<u8, 0x6B> reserved_29ED5; - - // nn::time::LocationName - Service::Time::TimeZone::LocationName device_time_zone_location_name; - std::array<u8, 0x4> reserved_29F64; - // nn::time::SteadyClockTimePoint - Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; - - std::array<u8, 0xC0> reserved_29F80; - - // nn::settings::system::PrimaryAlbumStorage - PrimaryAlbumStorage primary_album_storage; - - std::array<u8, 0x3C> reserved_2A044; - - bool usb_30_enable_flag; - std::array<u8, 0x3> pad_2A081; - bool usb_30_host_enable_flag; - std::array<u8, 0x3> pad_2A085; - bool usb_30_device_enable_flag; - std::array<u8, 0x3> pad_2A089; - - std::array<u8, 0x34> reserved_2A08C; - - bool nfc_enable_flag; - std::array<u8, 0x3> pad_2A0C1; - - std::array<u8, 0x3C> reserved_2A0C4; - - // nn::settings::system::SleepSettings - SleepSettings sleep_settings; - - std::array<u8, 0x34> reserved_2A10C; - - // nn::settings::system::EulaVersion - u32 eula_version_count; - std::array<u8, 0xC> reserved_2A144; - std::array<EulaVersion, 32> eula_versions; - - std::array<u8, 0x200> reserved_2A750; - - // nn::settings::system::DeviceNickName - std::array<u8, 0x80> device_nick_name; - - std::array<u8, 0x80> reserved_2A9D0; - - bool auto_update_enable_flag; - std::array<u8, 0x3> pad_2AA51; - - std::array<u8, 0x4C> reserved_2AA54; - - // nn::settings::system::BluetoothDevicesSettings - std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14; - - std::array<u8, 0x2000> reserved_2C6A0; - - // nn::settings::system::NxControllerSettings - std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30; -}; - -static_assert(offsetof(SystemSettings, language_code) == 0x10); -static_assert(offsetof(SystemSettings, network_setting_count) == 0x50); -static_assert(offsetof(SystemSettings, network_settings_1B0) == 0x60); -static_assert(offsetof(SystemSettings, bluetooth_device_settings_count) == 0x8060); -static_assert(offsetof(SystemSettings, bluetooth_enable_flag) == 0x8064); -static_assert(offsetof(SystemSettings, bluetooth_device_settings_first_10) == 0x8070); -static_assert(offsetof(SystemSettings, ldn_channel) == 0x9470); -static_assert(offsetof(SystemSettings, mii_author_id) == 0x94B0); -static_assert(offsetof(SystemSettings, nx_controller_settings_count) == 0x94F0); -static_assert(offsetof(SystemSettings, nx_controller_legacy_settings) == 0x9500); -static_assert(offsetof(SystemSettings, external_rtc_reset_flag) == 0x98F0); -static_assert(offsetof(SystemSettings, push_notification_activity_mode_on_sleep) == 0x9930); -static_assert(offsetof(SystemSettings, allowed_ssl_host_count) == 0x99F4); -static_assert(offsetof(SystemSettings, host_fs_mount_point) == 0x9A30); -static_assert(offsetof(SystemSettings, allowed_ssl_hosts) == 0x9B30); -static_assert(offsetof(SystemSettings, ble_pairing_settings_count) == 0xA9F0); -static_assert(offsetof(SystemSettings, ble_pairing_settings) == 0xAA00); -static_assert(offsetof(SystemSettings, account_online_storage_settings_count) == 0xAF00); -static_assert(offsetof(SystemSettings, account_online_storage_settings) == 0xAF10); -static_assert(offsetof(SystemSettings, pctl_ready_flag) == 0xB110); -static_assert(offsetof(SystemSettings, theme_id_type0) == 0xB150); -static_assert(offsetof(SystemSettings, chinese_traditional_input_method) == 0xB350); -static_assert(offsetof(SystemSettings, button_config_registered_settings_count) == 0xB3D0); -static_assert(offsetof(SystemSettings, button_config_settings_count) == 0xB3E0); -static_assert(offsetof(SystemSettings, button_config_settings) == 0xB3E8); -static_assert(offsetof(SystemSettings, button_config_registered_settings_embedded) == 0x1D3E0); -static_assert(offsetof(SystemSettings, console_six_axis_sensor_acceleration_bias) == 0x29370); -static_assert(offsetof(SystemSettings, lock_screen_flag) == 0x29470); -static_assert(offsetof(SystemSettings, battery_percentage_flag) == 0x294A0); -static_assert(offsetof(SystemSettings, field_testing_flag) == 0x294C0); -static_assert(offsetof(SystemSettings, backlight_settings_mixed_up) == 0x294F0); -static_assert(offsetof(SystemSettings, user_system_clock_context) == 0x29580); -static_assert(offsetof(SystemSettings, network_system_clock_context) == 0x295A0); -static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_enabled) == 0x295C0); -static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_updated_time_point) == - 0x295C8); -static_assert(offsetof(SystemSettings, account_settings) == 0x295F0); -static_assert(offsetof(SystemSettings, audio_volume_type0) == 0x296F0); -static_assert(offsetof(SystemSettings, hearing_protection_safeguard_remaining_time) == 0x29730); -static_assert(offsetof(SystemSettings, automatic_application_download_flag) == 0x297B0); -static_assert(offsetof(SystemSettings, notification_settings) == 0x297B8); -static_assert(offsetof(SystemSettings, account_notification_settings) == 0x29840); -static_assert(offsetof(SystemSettings, vibration_master_volume) == 0x29A40); -static_assert(offsetof(SystemSettings, analog_stick_user_calibration_left) == 0x29A48); -static_assert(offsetof(SystemSettings, touch_screen_mode) == 0x29A68); -static_assert(offsetof(SystemSettings, edid) == 0x29AA0); -static_assert(offsetof(SystemSettings, data_deletion_settings) == 0x29E80); -static_assert(offsetof(SystemSettings, requires_run_repair_time_reviser) == 0x29ED4); -static_assert(offsetof(SystemSettings, device_time_zone_location_name) == 0x29F40); -static_assert(offsetof(SystemSettings, nfc_enable_flag) == 0x2A0C0); -static_assert(offsetof(SystemSettings, eula_version_count) == 0x2A140); -static_assert(offsetof(SystemSettings, device_nick_name) == 0x2A950); -static_assert(offsetof(SystemSettings, bluetooth_device_settings_last_14) == 0x2AAA0); -static_assert(offsetof(SystemSettings, nx_controller_settings_data_from_offset_30) == 0x2E6A0); - -static_assert(sizeof(SystemSettings) == 0x336A0, "SystemSettings has the wrong size!"); - -SystemSettings DefaultSystemSettings(); - -} // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp new file mode 100644 index 000000000..100cb2db4 --- /dev/null +++ b/src/core/hle/service/set/system_settings_server.cpp @@ -0,0 +1,1673 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <fstream> + +#include "common/assert.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "common/string_util.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/nca_metadata.h" +#include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" +#include "core/file_sys/system_archive/system_archive.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/set/settings_server.h" +#include "core/hle/service/set/system_settings_server.h" + +namespace Service::Set { + +namespace { +constexpr u32 SETTINGS_VERSION{2u}; +constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); +struct SettingsHeader { + u64 magic; + u32 version; + u32 reserved; +}; +} // Anonymous namespace + +Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, + GetFirmwareVersionType type) { + constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809; + auto& fsc = system.GetFileSystemController(); + + // Attempt to load version data from disk + const FileSys::RegisteredCache* bis_system{}; + std::unique_ptr<FileSys::NCA> nca{}; + FileSys::VirtualDir romfs{}; + + bis_system = fsc.GetSystemNANDContents(); + if (bis_system) { + nca = bis_system->GetEntry(FirmwareVersionSystemDataId, FileSys::ContentRecordType::Data); + } + if (nca) { + if (auto nca_romfs = nca->GetRomFS(); nca_romfs) { + romfs = FileSys::ExtractRomFS(nca_romfs); + } + } + if (!romfs) { + romfs = FileSys::ExtractRomFS( + FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId)); + } + + const auto early_exit_failure = [](std::string_view desc, Result code) { + LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", + desc); + return code; + }; + + const auto ver_file = romfs->GetFile("file"); + if (ver_file == nullptr) { + return early_exit_failure("The system version archive didn't contain the file 'file'.", + FileSys::ResultInvalidArgument); + } + + auto data = ver_file->ReadAllBytes(); + if (data.size() != sizeof(FirmwareVersionFormat)) { + return early_exit_failure("The system version file 'file' was not the correct size.", + FileSys::ResultOutOfRange); + } + + std::memcpy(&out_firmware, data.data(), sizeof(FirmwareVersionFormat)); + + // If the command is GetFirmwareVersion (as opposed to GetFirmwareVersion2), hardware will + // zero out the REVISION_MINOR field. + if (type == GetFirmwareVersionType::Version1) { + out_firmware.revision_minor = 0; + } + + return ResultSuccess; +} + +ISystemSettingsServer::ISystemSettingsServer(Core::System& system_) + : ServiceFramework{system_, "set:sys"}, m_system{system} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &ISystemSettingsServer::SetLanguageCode, "SetLanguageCode"}, + {1, nullptr, "SetNetworkSettings"}, + {2, nullptr, "GetNetworkSettings"}, + {3, &ISystemSettingsServer::GetFirmwareVersion, "GetFirmwareVersion"}, + {4, &ISystemSettingsServer::GetFirmwareVersion2, "GetFirmwareVersion2"}, + {5, nullptr, "GetFirmwareVersionDigest"}, + {7, &ISystemSettingsServer::GetLockScreenFlag, "GetLockScreenFlag"}, + {8, &ISystemSettingsServer::SetLockScreenFlag, "SetLockScreenFlag"}, + {9, nullptr, "GetBacklightSettings"}, + {10, nullptr, "SetBacklightSettings"}, + {11, nullptr, "SetBluetoothDevicesSettings"}, + {12, nullptr, "GetBluetoothDevicesSettings"}, + {13, &ISystemSettingsServer::GetExternalSteadyClockSourceId, "GetExternalSteadyClockSourceId"}, + {14, &ISystemSettingsServer::SetExternalSteadyClockSourceId, "SetExternalSteadyClockSourceId"}, + {15, &ISystemSettingsServer::GetUserSystemClockContext, "GetUserSystemClockContext"}, + {16, &ISystemSettingsServer::SetUserSystemClockContext, "SetUserSystemClockContext"}, + {17, &ISystemSettingsServer::GetAccountSettings, "GetAccountSettings"}, + {18, &ISystemSettingsServer::SetAccountSettings, "SetAccountSettings"}, + {19, nullptr, "GetAudioVolume"}, + {20, nullptr, "SetAudioVolume"}, + {21, &ISystemSettingsServer::GetEulaVersions, "GetEulaVersions"}, + {22, &ISystemSettingsServer::SetEulaVersions, "SetEulaVersions"}, + {23, &ISystemSettingsServer::GetColorSetId, "GetColorSetId"}, + {24, &ISystemSettingsServer::SetColorSetId, "SetColorSetId"}, + {25, nullptr, "GetConsoleInformationUploadFlag"}, + {26, nullptr, "SetConsoleInformationUploadFlag"}, + {27, nullptr, "GetAutomaticApplicationDownloadFlag"}, + {28, nullptr, "SetAutomaticApplicationDownloadFlag"}, + {29, &ISystemSettingsServer::GetNotificationSettings, "GetNotificationSettings"}, + {30, &ISystemSettingsServer::SetNotificationSettings, "SetNotificationSettings"}, + {31, &ISystemSettingsServer::GetAccountNotificationSettings, "GetAccountNotificationSettings"}, + {32, &ISystemSettingsServer::SetAccountNotificationSettings, "SetAccountNotificationSettings"}, + {35, &ISystemSettingsServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"}, + {36, &ISystemSettingsServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"}, + {37, &ISystemSettingsServer::GetSettingsItemValueSize, "GetSettingsItemValueSize"}, + {38, &ISystemSettingsServer::GetSettingsItemValue, "GetSettingsItemValue"}, + {39, &ISystemSettingsServer::GetTvSettings, "GetTvSettings"}, + {40, &ISystemSettingsServer::SetTvSettings, "SetTvSettings"}, + {41, nullptr, "GetEdid"}, + {42, nullptr, "SetEdid"}, + {43, &ISystemSettingsServer::GetAudioOutputMode, "GetAudioOutputMode"}, + {44, &ISystemSettingsServer::SetAudioOutputMode, "SetAudioOutputMode"}, + {45, &ISystemSettingsServer::GetSpeakerAutoMuteFlag , "GetSpeakerAutoMuteFlag"}, + {46, &ISystemSettingsServer::SetSpeakerAutoMuteFlag , "SetSpeakerAutoMuteFlag"}, + {47, &ISystemSettingsServer::GetQuestFlag, "GetQuestFlag"}, + {48, &ISystemSettingsServer::SetQuestFlag, "SetQuestFlag"}, + {49, nullptr, "GetDataDeletionSettings"}, + {50, nullptr, "SetDataDeletionSettings"}, + {51, nullptr, "GetInitialSystemAppletProgramId"}, + {52, nullptr, "GetOverlayDispProgramId"}, + {53, &ISystemSettingsServer::GetDeviceTimeZoneLocationName, "GetDeviceTimeZoneLocationName"}, + {54, &ISystemSettingsServer::SetDeviceTimeZoneLocationName, "SetDeviceTimeZoneLocationName"}, + {55, nullptr, "GetWirelessCertificationFileSize"}, + {56, nullptr, "GetWirelessCertificationFile"}, + {57, &ISystemSettingsServer::SetRegionCode, "SetRegionCode"}, + {58, &ISystemSettingsServer::GetNetworkSystemClockContext, "GetNetworkSystemClockContext"}, + {59, &ISystemSettingsServer::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, + {60, &ISystemSettingsServer::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, + {61, &ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, + {62, &ISystemSettingsServer::GetDebugModeFlag, "GetDebugModeFlag"}, + {63, &ISystemSettingsServer::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, + {64, &ISystemSettingsServer::SetPrimaryAlbumStorage, "SetPrimaryAlbumStorage"}, + {65, nullptr, "GetUsb30EnableFlag"}, + {66, nullptr, "SetUsb30EnableFlag"}, + {67, &ISystemSettingsServer::GetBatteryLot, "GetBatteryLot"}, + {68, &ISystemSettingsServer::GetSerialNumber, "GetSerialNumber"}, + {69, &ISystemSettingsServer::GetNfcEnableFlag, "GetNfcEnableFlag"}, + {70, &ISystemSettingsServer::SetNfcEnableFlag, "SetNfcEnableFlag"}, + {71, &ISystemSettingsServer::GetSleepSettings, "GetSleepSettings"}, + {72, &ISystemSettingsServer::SetSleepSettings, "SetSleepSettings"}, + {73, &ISystemSettingsServer::GetWirelessLanEnableFlag, "GetWirelessLanEnableFlag"}, + {74, &ISystemSettingsServer::SetWirelessLanEnableFlag, "SetWirelessLanEnableFlag"}, + {75, &ISystemSettingsServer::GetInitialLaunchSettings, "GetInitialLaunchSettings"}, + {76, &ISystemSettingsServer::SetInitialLaunchSettings, "SetInitialLaunchSettings"}, + {77, &ISystemSettingsServer::GetDeviceNickName, "GetDeviceNickName"}, + {78, &ISystemSettingsServer::SetDeviceNickName, "SetDeviceNickName"}, + {79, &ISystemSettingsServer::GetProductModel, "GetProductModel"}, + {80, nullptr, "GetLdnChannel"}, + {81, nullptr, "SetLdnChannel"}, + {82, nullptr, "AcquireTelemetryDirtyFlagEventHandle"}, + {83, nullptr, "GetTelemetryDirtyFlags"}, + {84, nullptr, "GetPtmBatteryLot"}, + {85, nullptr, "SetPtmBatteryLot"}, + {86, nullptr, "GetPtmFuelGaugeParameter"}, + {87, nullptr, "SetPtmFuelGaugeParameter"}, + {88, &ISystemSettingsServer::GetBluetoothEnableFlag, "GetBluetoothEnableFlag"}, + {89, &ISystemSettingsServer::SetBluetoothEnableFlag, "SetBluetoothEnableFlag"}, + {90, &ISystemSettingsServer::GetMiiAuthorId, "GetMiiAuthorId"}, + {91, nullptr, "SetShutdownRtcValue"}, + {92, nullptr, "GetShutdownRtcValue"}, + {93, nullptr, "AcquireFatalDirtyFlagEventHandle"}, + {94, nullptr, "GetFatalDirtyFlags"}, + {95, &ISystemSettingsServer::GetAutoUpdateEnableFlag, "GetAutoUpdateEnableFlag"}, + {96, &ISystemSettingsServer::SetAutoUpdateEnableFlag, "SetAutoUpdateEnableFlag"}, + {97, nullptr, "GetNxControllerSettings"}, + {98, nullptr, "SetNxControllerSettings"}, + {99, &ISystemSettingsServer::GetBatteryPercentageFlag, "GetBatteryPercentageFlag"}, + {100, &ISystemSettingsServer::SetBatteryPercentageFlag, "SetBatteryPercentageFlag"}, + {101, nullptr, "GetExternalRtcResetFlag"}, + {102, nullptr, "SetExternalRtcResetFlag"}, + {103, nullptr, "GetUsbFullKeyEnableFlag"}, + {104, nullptr, "SetUsbFullKeyEnableFlag"}, + {105, &ISystemSettingsServer::SetExternalSteadyClockInternalOffset, "SetExternalSteadyClockInternalOffset"}, + {106, &ISystemSettingsServer::GetExternalSteadyClockInternalOffset, "GetExternalSteadyClockInternalOffset"}, + {107, nullptr, "GetBacklightSettingsEx"}, + {108, nullptr, "SetBacklightSettingsEx"}, + {109, nullptr, "GetHeadphoneVolumeWarningCount"}, + {110, nullptr, "SetHeadphoneVolumeWarningCount"}, + {111, nullptr, "GetBluetoothAfhEnableFlag"}, + {112, nullptr, "SetBluetoothAfhEnableFlag"}, + {113, nullptr, "GetBluetoothBoostEnableFlag"}, + {114, nullptr, "SetBluetoothBoostEnableFlag"}, + {115, nullptr, "GetInRepairProcessEnableFlag"}, + {116, nullptr, "SetInRepairProcessEnableFlag"}, + {117, nullptr, "GetHeadphoneVolumeUpdateFlag"}, + {118, nullptr, "SetHeadphoneVolumeUpdateFlag"}, + {119, nullptr, "NeedsToUpdateHeadphoneVolume"}, + {120, &ISystemSettingsServer::GetPushNotificationActivityModeOnSleep, "GetPushNotificationActivityModeOnSleep"}, + {121, &ISystemSettingsServer::SetPushNotificationActivityModeOnSleep, "SetPushNotificationActivityModeOnSleep"}, + {122, nullptr, "GetServiceDiscoveryControlSettings"}, + {123, nullptr, "SetServiceDiscoveryControlSettings"}, + {124, &ISystemSettingsServer::GetErrorReportSharePermission, "GetErrorReportSharePermission"}, + {125, &ISystemSettingsServer::SetErrorReportSharePermission, "SetErrorReportSharePermission"}, + {126, &ISystemSettingsServer::GetAppletLaunchFlags, "GetAppletLaunchFlags"}, + {127, &ISystemSettingsServer::SetAppletLaunchFlags, "SetAppletLaunchFlags"}, + {128, nullptr, "GetConsoleSixAxisSensorAccelerationBias"}, + {129, nullptr, "SetConsoleSixAxisSensorAccelerationBias"}, + {130, nullptr, "GetConsoleSixAxisSensorAngularVelocityBias"}, + {131, nullptr, "SetConsoleSixAxisSensorAngularVelocityBias"}, + {132, nullptr, "GetConsoleSixAxisSensorAccelerationGain"}, + {133, nullptr, "SetConsoleSixAxisSensorAccelerationGain"}, + {134, nullptr, "GetConsoleSixAxisSensorAngularVelocityGain"}, + {135, nullptr, "SetConsoleSixAxisSensorAngularVelocityGain"}, + {136, &ISystemSettingsServer::GetKeyboardLayout, "GetKeyboardLayout"}, + {137, &ISystemSettingsServer::SetKeyboardLayout, "SetKeyboardLayout"}, + {138, nullptr, "GetWebInspectorFlag"}, + {139, nullptr, "GetAllowedSslHosts"}, + {140, nullptr, "GetHostFsMountPoint"}, + {141, nullptr, "GetRequiresRunRepairTimeReviser"}, + {142, nullptr, "SetRequiresRunRepairTimeReviser"}, + {143, nullptr, "SetBlePairingSettings"}, + {144, nullptr, "GetBlePairingSettings"}, + {145, nullptr, "GetConsoleSixAxisSensorAngularVelocityTimeBias"}, + {146, nullptr, "SetConsoleSixAxisSensorAngularVelocityTimeBias"}, + {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, + {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, + {149, nullptr, "GetRebootlessSystemUpdateVersion"}, + {150, &ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime, "GetDeviceTimeZoneLocationUpdatedTime"}, + {151, &ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime, "SetDeviceTimeZoneLocationUpdatedTime"}, + {152, &ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime, "GetUserSystemClockAutomaticCorrectionUpdatedTime"}, + {153, &ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime, "SetUserSystemClockAutomaticCorrectionUpdatedTime"}, + {154, nullptr, "GetAccountOnlineStorageSettings"}, + {155, nullptr, "SetAccountOnlineStorageSettings"}, + {156, nullptr, "GetPctlReadyFlag"}, + {157, nullptr, "SetPctlReadyFlag"}, + {158, nullptr, "GetAnalogStickUserCalibrationL"}, + {159, nullptr, "SetAnalogStickUserCalibrationL"}, + {160, nullptr, "GetAnalogStickUserCalibrationR"}, + {161, nullptr, "SetAnalogStickUserCalibrationR"}, + {162, nullptr, "GetPtmBatteryVersion"}, + {163, nullptr, "SetPtmBatteryVersion"}, + {164, nullptr, "GetUsb30HostEnableFlag"}, + {165, nullptr, "SetUsb30HostEnableFlag"}, + {166, nullptr, "GetUsb30DeviceEnableFlag"}, + {167, nullptr, "SetUsb30DeviceEnableFlag"}, + {168, nullptr, "GetThemeId"}, + {169, nullptr, "SetThemeId"}, + {170, &ISystemSettingsServer::GetChineseTraditionalInputMethod, "GetChineseTraditionalInputMethod"}, + {171, nullptr, "SetChineseTraditionalInputMethod"}, + {172, nullptr, "GetPtmCycleCountReliability"}, + {173, nullptr, "SetPtmCycleCountReliability"}, + {174, &ISystemSettingsServer::GetHomeMenuScheme, "GetHomeMenuScheme"}, + {175, nullptr, "GetThemeSettings"}, + {176, nullptr, "SetThemeSettings"}, + {177, nullptr, "GetThemeKey"}, + {178, nullptr, "SetThemeKey"}, + {179, nullptr, "GetZoomFlag"}, + {180, nullptr, "SetZoomFlag"}, + {181, nullptr, "GetT"}, + {182, nullptr, "SetT"}, + {183, nullptr, "GetPlatformRegion"}, + {184, nullptr, "SetPlatformRegion"}, + {185, &ISystemSettingsServer::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"}, + {186, nullptr, "GetMemoryUsageRateFlag"}, + {187, nullptr, "GetTouchScreenMode"}, + {188, nullptr, "SetTouchScreenMode"}, + {189, nullptr, "GetButtonConfigSettingsFull"}, + {190, nullptr, "SetButtonConfigSettingsFull"}, + {191, nullptr, "GetButtonConfigSettingsEmbedded"}, + {192, nullptr, "SetButtonConfigSettingsEmbedded"}, + {193, nullptr, "GetButtonConfigSettingsLeft"}, + {194, nullptr, "SetButtonConfigSettingsLeft"}, + {195, nullptr, "GetButtonConfigSettingsRight"}, + {196, nullptr, "SetButtonConfigSettingsRight"}, + {197, nullptr, "GetButtonConfigRegisteredSettingsEmbedded"}, + {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, + {199, nullptr, "GetButtonConfigRegisteredSettings"}, + {200, nullptr, "SetButtonConfigRegisteredSettings"}, + {201, &ISystemSettingsServer::GetFieldTestingFlag, "GetFieldTestingFlag"}, + {202, nullptr, "SetFieldTestingFlag"}, + {203, &ISystemSettingsServer::GetPanelCrcMode, "GetPanelCrcMode"}, + {204, &ISystemSettingsServer::SetPanelCrcMode, "SetPanelCrcMode"}, + {205, nullptr, "GetNxControllerSettingsEx"}, + {206, nullptr, "SetNxControllerSettingsEx"}, + {207, nullptr, "GetHearingProtectionSafeguardFlag"}, + {208, nullptr, "SetHearingProtectionSafeguardFlag"}, + {209, nullptr, "GetHearingProtectionSafeguardRemainingTime"}, + {210, nullptr, "SetHearingProtectionSafeguardRemainingTime"}, + }; + // clang-format on + + RegisterHandlers(functions); + + SetupSettings(); + m_save_thread = + std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); }); +} + +ISystemSettingsServer::~ISystemSettingsServer() { + SetSaveNeeded(); + m_save_thread.request_stop(); +} + +bool ISystemSettingsServer::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) { + using settings_type = decltype(default_func()); + + if (!Common::FS::CreateDirs(path)) { + return false; + } + + auto settings_file = path / "settings.dat"; + auto exists = std::filesystem::exists(settings_file); + auto file_size_ok = exists && std::filesystem::file_size(settings_file) == + sizeof(SettingsHeader) + sizeof(settings_type); + + auto ResetToDefault = [&]() { + auto default_settings{default_func()}; + + SettingsHeader hdr{ + .magic = SETTINGS_MAGIC, + .version = SETTINGS_VERSION, + .reserved = 0u, + }; + + std::ofstream out_settings_file(settings_file, std::ios::out | std::ios::binary); + out_settings_file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); + out_settings_file.write(reinterpret_cast<const char*>(&default_settings), + sizeof(settings_type)); + out_settings_file.flush(); + out_settings_file.close(); + }; + + constexpr auto IsHeaderValid = [](std::ifstream& file) -> bool { + if (!file.is_open()) { + return false; + } + SettingsHeader hdr{}; + file.read(reinterpret_cast<char*>(&hdr), sizeof(hdr)); + return hdr.magic == SETTINGS_MAGIC && hdr.version >= SETTINGS_VERSION; + }; + + if (!exists || !file_size_ok) { + ResetToDefault(); + } + + std::ifstream file(settings_file, std::ios::binary | std::ios::in); + if (!IsHeaderValid(file)) { + file.close(); + ResetToDefault(); + file = std::ifstream(settings_file, std::ios::binary | std::ios::in); + if (!IsHeaderValid(file)) { + return false; + } + } + + if constexpr (std::is_same_v<settings_type, PrivateSettings>) { + file.read(reinterpret_cast<char*>(&m_private_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { + file.read(reinterpret_cast<char*>(&m_device_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { + file.read(reinterpret_cast<char*>(&m_appln_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { + file.read(reinterpret_cast<char*>(&m_system_settings), sizeof(settings_type)); + } else { + UNREACHABLE(); + } + file.close(); + + return true; +} + +bool ISystemSettingsServer::StoreSettingsFile(std::filesystem::path& path, auto& settings) { + using settings_type = std::decay_t<decltype(settings)>; + + if (!Common::FS::IsDir(path)) { + return false; + } + + auto settings_base = path / "settings"; + std::filesystem::path settings_tmp_file = settings_base; + settings_tmp_file = settings_tmp_file.replace_extension("tmp"); + std::ofstream file(settings_tmp_file, std::ios::binary | std::ios::out); + if (!file.is_open()) { + return false; + } + + SettingsHeader hdr{ + .magic = SETTINGS_MAGIC, + .version = SETTINGS_VERSION, + .reserved = 0u, + }; + file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); + + if constexpr (std::is_same_v<settings_type, PrivateSettings>) { + file.write(reinterpret_cast<const char*>(&m_private_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { + file.write(reinterpret_cast<const char*>(&m_device_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { + file.write(reinterpret_cast<const char*>(&m_appln_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { + file.write(reinterpret_cast<const char*>(&m_system_settings), sizeof(settings_type)); + } else { + UNREACHABLE(); + } + file.close(); + + std::filesystem::rename(settings_tmp_file, settings_base.replace_extension("dat")); + + return true; +} + +void ISystemSettingsServer::SetLanguageCode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.language_code = rp.PopEnum<LanguageCode>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, language_code={}", m_system_settings.language_code); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetFirmwareVersion(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + FirmwareVersionFormat firmware_data{}; + const auto result = + GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version1); + + if (result.IsSuccess()) { + ctx.WriteBuffer(firmware_data); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void ISystemSettingsServer::GetFirmwareVersion2(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + FirmwareVersionFormat firmware_data{}; + const auto result = + GetFirmwareVersionImpl(firmware_data, system, GetFirmwareVersionType::Version2); + + if (result.IsSuccess()) { + ctx.WriteBuffer(firmware_data); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void ISystemSettingsServer::GetExternalSteadyClockSourceId(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Common::UUID id{}; + const auto res = GetExternalSteadyClockSourceId(id); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Common::UUID) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(id); +} + +void ISystemSettingsServer::SetExternalSteadyClockSourceId(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + const auto id{rp.PopRaw<Common::UUID>()}; + + const auto res = SetExternalSteadyClockSourceId(id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetUserSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::PSC::Time::SystemClockContext context{}; + const auto res = GetUserSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(context); +} + +void ISystemSettingsServer::SetUserSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + const auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; + + const auto res = SetUserSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetLockScreenFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.lock_screen_flag); +} + +void ISystemSettingsServer::SetLockScreenFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.lock_screen_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetAccountSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.account_settings); +} + +void ISystemSettingsServer::SetAccountSettings(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.account_settings = rp.PopRaw<AccountSettings>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, account_settings_flags={}", + m_system_settings.account_settings.flags); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetEulaVersions(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, elements={}", m_system_settings.eula_version_count); + + ctx.WriteBuffer(m_system_settings.eula_versions); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.eula_version_count); +} + +void ISystemSettingsServer::SetEulaVersions(HLERequestContext& ctx) { + const auto elements = ctx.GetReadBufferNumElements<EulaVersion>(); + const auto buffer_data = ctx.ReadBuffer(); + + LOG_INFO(Service_SET, "called, elements={}", elements); + ASSERT(elements <= m_system_settings.eula_versions.size()); + + m_system_settings.eula_version_count = static_cast<u32>(elements); + std::memcpy(&m_system_settings.eula_versions, buffer_data.data(), + sizeof(EulaVersion) * elements); + SetSaveNeeded(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetColorSetId(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called, color_set=", m_system_settings.color_set_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(m_system_settings.color_set_id); +} + +void ISystemSettingsServer::SetColorSetId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.color_set_id = rp.PopEnum<ColorSet>(); + SetSaveNeeded(); + + LOG_DEBUG(Service_SET, "called, color_set={}", m_system_settings.color_set_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetNotificationSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}", + m_system_settings.notification_settings.flags.raw, + m_system_settings.notification_settings.volume, + m_system_settings.notification_settings.start_time.hour, + m_system_settings.notification_settings.start_time.minute, + m_system_settings.notification_settings.stop_time.hour, + m_system_settings.notification_settings.stop_time.minute); + + IPC::ResponseBuilder rb{ctx, 8}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.notification_settings); +} + +void ISystemSettingsServer::SetNotificationSettings(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.notification_settings = rp.PopRaw<NotificationSettings>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}", + m_system_settings.notification_settings.flags.raw, + m_system_settings.notification_settings.volume, + m_system_settings.notification_settings.start_time.hour, + m_system_settings.notification_settings.start_time.minute, + m_system_settings.notification_settings.stop_time.hour, + m_system_settings.notification_settings.stop_time.minute); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetAccountNotificationSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, elements={}", + m_system_settings.account_notification_settings_count); + + ctx.WriteBuffer(m_system_settings.account_notification_settings); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.account_notification_settings_count); +} + +void ISystemSettingsServer::SetAccountNotificationSettings(HLERequestContext& ctx) { + const auto elements = ctx.GetReadBufferNumElements<AccountNotificationSettings>(); + const auto buffer_data = ctx.ReadBuffer(); + + LOG_INFO(Service_SET, "called, elements={}", elements); + + ASSERT(elements <= m_system_settings.account_notification_settings.size()); + + m_system_settings.account_notification_settings_count = static_cast<u32>(elements); + std::memcpy(&m_system_settings.account_notification_settings, buffer_data.data(), + elements * sizeof(AccountNotificationSettings)); + SetSaveNeeded(); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetVibrationMasterVolume(HLERequestContext& ctx) { + f32 vibration_master_volume = {}; + const auto result = GetVibrationMasterVolume(vibration_master_volume); + + LOG_INFO(Service_SET, "called, master_volume={}", vibration_master_volume); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.Push(vibration_master_volume); +} + +void ISystemSettingsServer::SetVibrationMasterVolume(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto vibration_master_volume = rp.PopRaw<f32>(); + + LOG_INFO(Service_SET, "called, elements={}", m_system_settings.vibration_master_volume); + + const auto result = SetVibrationMasterVolume(vibration_master_volume); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +// FIXME: implement support for the real system_settings.ini + +template <typename T> +static std::vector<u8> ToBytes(const T& value) { + static_assert(std::is_trivially_copyable_v<T>); + + const auto* begin = reinterpret_cast<const u8*>(&value); + const auto* end = begin + sizeof(T); + + return std::vector<u8>(begin, end); +} + +using Settings = + std::map<std::string, std::map<std::string, std::vector<u8>, std::less<>>, std::less<>>; + +static Settings GetSettings() { + Settings ret; + + // AM + ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); + ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); + + // Time + ret["time"]["notify_time_to_fs_interval_seconds"] = ToBytes(s32{600}); + ret["time"]["standard_network_clock_sufficient_accuracy_minutes"] = + ToBytes(s32{43200}); // 30 days + ret["time"]["standard_steady_clock_rtc_update_interval_minutes"] = ToBytes(s32{5}); + ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0}); + ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023}); + + // HID + ret["hid"]["has_rail_interface"] = ToBytes(bool{true}); + ret["hid"]["has_sio_mcu"] = ToBytes(bool{true}); + ret["hid_debug"]["enables_debugpad"] = ToBytes(bool{true}); + ret["hid_debug"]["manages_devices"] = ToBytes(bool{true}); + ret["hid_debug"]["manages_touch_ic_i2c"] = ToBytes(bool{true}); + ret["hid_debug"]["emulate_future_device"] = ToBytes(bool{false}); + ret["hid_debug"]["emulate_mcu_hardware_error"] = ToBytes(bool{false}); + ret["hid_debug"]["enables_rail"] = ToBytes(bool{true}); + ret["hid_debug"]["emulate_firmware_update_failure"] = ToBytes(bool{false}); + ret["hid_debug"]["failure_firmware_update"] = ToBytes(s32{0}); + ret["hid_debug"]["ble_disabled"] = ToBytes(bool{false}); + ret["hid_debug"]["dscale_disabled"] = ToBytes(bool{false}); + ret["hid_debug"]["force_handheld"] = ToBytes(bool{true}); + ret["hid_debug"]["disabled_features_per_id"] = std::vector<u8>(0xa8); + ret["hid_debug"]["touch_firmware_auto_update_disabled"] = ToBytes(bool{false}); + + // Mii + ret["mii"]["is_db_test_mode_enabled"] = ToBytes(bool{false}); + + // Settings + ret["settings_debug"]["is_debug_mode_enabled"] = ToBytes(bool{false}); + + // Error + ret["err"]["applet_auto_close"] = ToBytes(bool{false}); + + return ret; +} + +void ISystemSettingsServer::GetSettingsItemValueSize(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + // The category of the setting. This corresponds to the top-level keys of + // system_settings.ini. + const auto setting_category_buf{ctx.ReadBuffer(0)}; + const std::string setting_category{Common::StringFromBuffer(setting_category_buf)}; + + // The name of the setting. This corresponds to the second-level keys of + // system_settings.ini. + const auto setting_name_buf{ctx.ReadBuffer(1)}; + const std::string setting_name{Common::StringFromBuffer(setting_name_buf)}; + + auto settings{GetSettings()}; + u64 response_size{0}; + + if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) { + response_size = settings[setting_category][setting_name].size(); + } + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(response_size == 0 ? ResultUnknown : ResultSuccess); + rb.Push(response_size); +} + +void ISystemSettingsServer::GetSettingsItemValue(HLERequestContext& ctx) { + // The category of the setting. This corresponds to the top-level keys of + // system_settings.ini. + const auto setting_category_buf{ctx.ReadBuffer(0)}; + const std::string setting_category{Common::StringFromBuffer(setting_category_buf)}; + + // The name of the setting. This corresponds to the second-level keys of + // system_settings.ini. + const auto setting_name_buf{ctx.ReadBuffer(1)}; + const std::string setting_name{Common::StringFromBuffer(setting_name_buf)}; + + std::vector<u8> value; + auto response = GetSettingsItemValue(value, setting_category, setting_name); + + LOG_INFO(Service_SET, "called. category={}, name={} -- res=0x{:X}", setting_category, + setting_name, response.raw); + + ctx.WriteBuffer(value.data(), value.size()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(response); +} + +void ISystemSettingsServer::GetTvSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, + "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, " + "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", + m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, + m_system_settings.tv_settings.contrast_ratio, + m_system_settings.tv_settings.hdmi_content_type, + m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, + m_system_settings.tv_settings.tv_resolution, + m_system_settings.tv_settings.tv_underscan); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.tv_settings); +} + +void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.tv_settings = rp.PopRaw<TvSettings>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, + "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, " + "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", + m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, + m_system_settings.tv_settings.contrast_ratio, + m_system_settings.tv_settings.hdmi_content_type, + m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, + m_system_settings.tv_settings.tv_resolution, + m_system_settings.tv_settings.tv_underscan); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetAudioOutputMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto target{rp.PopEnum<AudioOutputModeTarget>()}; + + AudioOutputMode output_mode{}; + const auto result = GetAudioOutputMode(output_mode, target); + + LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(result); + rb.PushEnum(output_mode); +} + +void ISystemSettingsServer::SetAudioOutputMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto target{rp.PopEnum<AudioOutputModeTarget>()}; + const auto output_mode{rp.PopEnum<AudioOutputMode>()}; + + const auto result = SetAudioOutputMode(target, output_mode); + + LOG_INFO(Service_SET, "called, target={}, output_mode={}", target, output_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void ISystemSettingsServer::GetSpeakerAutoMuteFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, force_mute_on_headphone_removed={}", + m_system_settings.force_mute_on_headphone_removed); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.force_mute_on_headphone_removed); +} + +void ISystemSettingsServer::SetSpeakerAutoMuteFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.force_mute_on_headphone_removed = rp.PopRaw<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, force_mute_on_headphone_removed={}", + m_system_settings.force_mute_on_headphone_removed); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, quest_flag={}", m_system_settings.quest_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(m_system_settings.quest_flag); +} + +void ISystemSettingsServer::SetQuestFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.quest_flag = rp.PopEnum<QuestFlag>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, quest_flag={}", m_system_settings.quest_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::PSC::Time::LocationName name{}; + const auto res = GetDeviceTimeZoneLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::LocationName>(name); +} + +void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto name{rp.PopRaw<Service::PSC::Time::LocationName>()}; + + const auto res = SetDeviceTimeZoneLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.region_code = rp.PopEnum<SystemRegionCode>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetNetworkSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::PSC::Time::SystemClockContext context{}; + const auto res = GetNetworkSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::SystemClockContext) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(context); +} + +void ISystemSettingsServer::SetNetworkSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + const auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()}; + + const auto res = SetNetworkSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + bool enabled{}; + const auto res = IsUserSystemClockAutomaticCorrectionEnabled(enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.PushRaw(enabled); +} + +void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto enabled{rp.Pop<bool>()}; + + const auto res = SetUserSystemClockAutomaticCorrectionEnabled(enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetDebugModeFlag(HLERequestContext& ctx) { + bool is_debug_mode_enabled = false; + GetSettingsItemValue<bool>(is_debug_mode_enabled, "settings_debug", "is_debug_mode_enabled"); + + LOG_DEBUG(Service_SET, "called, is_debug_mode_enabled={}", is_debug_mode_enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(is_debug_mode_enabled); +} + +void ISystemSettingsServer::GetPrimaryAlbumStorage(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, primary_album_storage={}", + m_system_settings.primary_album_storage); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(m_system_settings.primary_album_storage); +} + +void ISystemSettingsServer::SetPrimaryAlbumStorage(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.primary_album_storage = rp.PopEnum<PrimaryAlbumStorage>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, primary_album_storage={}", + m_system_settings.primary_album_storage); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetBatteryLot(HLERequestContext& ctx) { + BatteryLot battery_lot = {"YUZUEMULATOR123456789"}; + + LOG_INFO(Service_SET, "called"); + + IPC::ResponseBuilder rb{ctx, 8}; + rb.Push(ResultSuccess); + rb.PushRaw(battery_lot); +} + +void ISystemSettingsServer::GetSerialNumber(HLERequestContext& ctx) { + SerialNumber console_serial = {"YUZ10012345678"}; + + LOG_INFO(Service_SET, "called"); + + IPC::ResponseBuilder rb{ctx, 8}; + rb.Push(ResultSuccess); + rb.PushRaw(console_serial); +} + +void ISystemSettingsServer::GetNfcEnableFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(m_system_settings.nfc_enable_flag); +} + +void ISystemSettingsServer::SetNfcEnableFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.nfc_enable_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetSleepSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}", + m_system_settings.sleep_settings.flags.raw, + m_system_settings.sleep_settings.handheld_sleep_plan, + m_system_settings.sleep_settings.console_sleep_plan); + + IPC::ResponseBuilder rb{ctx, 5}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.sleep_settings); +} + +void ISystemSettingsServer::SetSleepSettings(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.sleep_settings = rp.PopRaw<SleepSettings>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}", + m_system_settings.sleep_settings.flags.raw, + m_system_settings.sleep_settings.handheld_sleep_plan, + m_system_settings.sleep_settings.console_sleep_plan); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetWirelessLanEnableFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}", + m_system_settings.wireless_lan_enable_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.wireless_lan_enable_flag); +} + +void ISystemSettingsServer::SetWirelessLanEnableFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.wireless_lan_enable_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}", + m_system_settings.wireless_lan_enable_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, flags={}, timestamp={}", + m_system_settings.initial_launch_settings_packed.flags.raw, + m_system_settings.initial_launch_settings_packed.timestamp.time_point); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.initial_launch_settings_packed); +} + +void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + auto initial_launch_settings = rp.PopRaw<InitialLaunchSettings>(); + + m_system_settings.initial_launch_settings_packed.flags = initial_launch_settings.flags; + m_system_settings.initial_launch_settings_packed.timestamp = initial_launch_settings.timestamp; + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, flags={}, timestamp={}", + m_system_settings.initial_launch_settings_packed.flags.raw, + m_system_settings.initial_launch_settings_packed.timestamp.time_point); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetDeviceNickName(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called"); + + ctx.WriteBuffer(::Settings::values.device_name.GetValue()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::SetDeviceNickName(HLERequestContext& ctx) { + const std::string device_name = Common::StringFromBuffer(ctx.ReadBuffer()); + + LOG_INFO(Service_SET, "called, device_name={}", device_name); + + ::Settings::values.device_name = device_name; + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetProductModel(HLERequestContext& ctx) { + const u32 product_model = 1; + + LOG_WARNING(Service_SET, "(STUBBED) called, product_model={}", product_model); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(product_model); +} + +void ISystemSettingsServer::GetBluetoothEnableFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}", + m_system_settings.bluetooth_enable_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(m_system_settings.bluetooth_enable_flag); +} + +void ISystemSettingsServer::SetBluetoothEnableFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.bluetooth_enable_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}", + m_system_settings.bluetooth_enable_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetMiiAuthorId(HLERequestContext& ctx) { + if (m_system_settings.mii_author_id.IsInvalid()) { + m_system_settings.mii_author_id = Common::UUID::MakeDefault(); + SetSaveNeeded(); + } + + LOG_INFO(Service_SET, "called, author_id={}", + m_system_settings.mii_author_id.FormattedString()); + + IPC::ResponseBuilder rb{ctx, 6}; + rb.Push(ResultSuccess); + rb.PushRaw(m_system_settings.mii_author_id); +} + +void ISystemSettingsServer::GetAutoUpdateEnableFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, auto_update_flag={}", m_system_settings.auto_update_enable_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.auto_update_enable_flag); +} + +void ISystemSettingsServer::SetAutoUpdateEnableFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.auto_update_enable_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, auto_update_flag={}", m_system_settings.auto_update_enable_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetBatteryPercentageFlag(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called, battery_percentage_flag={}", + m_system_settings.battery_percentage_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.battery_percentage_flag); +} + +void ISystemSettingsServer::SetBatteryPercentageFlag(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.battery_percentage_flag = rp.Pop<bool>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, battery_percentage_flag={}", + m_system_settings.battery_percentage_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called."); + + IPC::RequestParser rp{ctx}; + auto offset{rp.Pop<s64>()}; + + const auto res = SetExternalSteadyClockInternalOffset(offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called."); + + s64 offset{}; + const auto res = GetExternalSteadyClockInternalOffset(offset); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(offset); +} + +void ISystemSettingsServer::GetPushNotificationActivityModeOnSleep(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, push_notification_activity_mode_on_sleep={}", + m_system_settings.push_notification_activity_mode_on_sleep); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.push_notification_activity_mode_on_sleep); +} + +void ISystemSettingsServer::SetPushNotificationActivityModeOnSleep(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.push_notification_activity_mode_on_sleep = rp.Pop<s32>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, push_notification_activity_mode_on_sleep={}", + m_system_settings.push_notification_activity_mode_on_sleep); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetErrorReportSharePermission(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, error_report_share_permission={}", + m_system_settings.error_report_share_permission); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(m_system_settings.error_report_share_permission); +} + +void ISystemSettingsServer::SetErrorReportSharePermission(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.error_report_share_permission = rp.PopEnum<ErrorReportSharePermission>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, error_report_share_permission={}", + m_system_settings.error_report_share_permission); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetAppletLaunchFlags(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.applet_launch_flag); +} + +void ISystemSettingsServer::SetAppletLaunchFlags(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.applet_launch_flag = rp.Pop<u32>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetKeyboardLayout(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, keyboard_layout={}", m_system_settings.keyboard_layout); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(m_system_settings.keyboard_layout)); +} + +void ISystemSettingsServer::SetKeyboardLayout(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.keyboard_layout = rp.PopRaw<KeyboardLayout>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, keyboard_layout={}", m_system_settings.keyboard_layout); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + const auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); +} + +void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()}; + + const auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( + HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::PSC::Time::SteadyClockTimePoint time_point{}; + const auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point); +} + +void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( + HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + const auto time_point{rp.PopRaw<Service::PSC::Time::SteadyClockTimePoint>()}; + + const auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void ISystemSettingsServer::GetChineseTraditionalInputMethod(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, chinese_traditional_input_method={}", + m_system_settings.chinese_traditional_input_method); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(m_system_settings.chinese_traditional_input_method); +} + +void ISystemSettingsServer::GetHomeMenuScheme(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "(STUBBED) called"); + + const HomeMenuScheme default_color = { + .main = 0xFF323232, + .back = 0xFF323232, + .sub = 0xFFFFFFFF, + .bezel = 0xFFFFFFFF, + .extra = 0xFF000000, + }; + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(HomeMenuScheme) / sizeof(u32)}; + rb.Push(ResultSuccess); + rb.PushRaw(default_color); +} + +void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); +} + +void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.field_testing_flag); +} + +void ISystemSettingsServer::GetPanelCrcMode(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called, panel_crc_mode={}", m_system_settings.panel_crc_mode); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(m_system_settings.panel_crc_mode); +} + +void ISystemSettingsServer::SetPanelCrcMode(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + m_system_settings.panel_crc_mode = rp.PopRaw<s32>(); + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, panel_crc_mode={}", m_system_settings.panel_crc_mode); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void ISystemSettingsServer::SetupSettings() { + auto system_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; + if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) { + ASSERT(false); + } + + auto private_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; + if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) { + ASSERT(false); + } + + auto device_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; + if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) { + ASSERT(false); + } + + auto appln_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; + if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) { + ASSERT(false); + } +} + +void ISystemSettingsServer::StoreSettings() { + auto system_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; + if (!StoreSettingsFile(system_dir, m_system_settings)) { + LOG_ERROR(Service_SET, "Failed to store System settings"); + } + + auto private_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; + if (!StoreSettingsFile(private_dir, m_private_settings)) { + LOG_ERROR(Service_SET, "Failed to store Private settings"); + } + + auto device_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; + if (!StoreSettingsFile(device_dir, m_device_settings)) { + LOG_ERROR(Service_SET, "Failed to store Device settings"); + } + + auto appln_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; + if (!StoreSettingsFile(appln_dir, m_appln_settings)) { + LOG_ERROR(Service_SET, "Failed to store ApplLn settings"); + } +} + +void ISystemSettingsServer::StoreSettingsThreadFunc(std::stop_token stop_token) { + Common::SetCurrentThreadName("SettingsStore"); + + while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { + std::scoped_lock l{m_save_needed_mutex}; + if (!std::exchange(m_save_needed, false)) { + continue; + } + StoreSettings(); + } +} + +void ISystemSettingsServer::SetSaveNeeded() { + std::scoped_lock l{m_save_needed_mutex}; + m_save_needed = true; +} + +Result ISystemSettingsServer::GetSettingsItemValue(std::vector<u8>& out_value, + const std::string& category, + const std::string& name) { + auto settings{GetSettings()}; + R_UNLESS(settings.contains(category) && settings[category].contains(name), ResultUnknown); + + out_value = settings[category][name]; + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetVibrationMasterVolume(f32& out_volume) const { + out_volume = m_system_settings.vibration_master_volume; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetVibrationMasterVolume(f32 volume) { + m_system_settings.vibration_master_volume = volume; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetAudioOutputMode(AudioOutputMode& out_output_mode, + AudioOutputModeTarget target) const { + switch (target) { + case AudioOutputModeTarget::Hdmi: + out_output_mode = m_system_settings.audio_output_mode_hdmi; + break; + case AudioOutputModeTarget::Speaker: + out_output_mode = m_system_settings.audio_output_mode_speaker; + break; + case AudioOutputModeTarget::Headphone: + out_output_mode = m_system_settings.audio_output_mode_headphone; + break; + case AudioOutputModeTarget::Type3: + out_output_mode = m_system_settings.audio_output_mode_type3; + break; + case AudioOutputModeTarget::Type4: + out_output_mode = m_system_settings.audio_output_mode_type4; + break; + default: + LOG_ERROR(Service_SET, "Invalid audio output mode target {}", target); + } + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetAudioOutputMode(AudioOutputModeTarget target, + AudioOutputMode output_mode) { + switch (target) { + case AudioOutputModeTarget::Hdmi: + m_system_settings.audio_output_mode_hdmi = output_mode; + break; + case AudioOutputModeTarget::Speaker: + m_system_settings.audio_output_mode_speaker = output_mode; + break; + case AudioOutputModeTarget::Headphone: + m_system_settings.audio_output_mode_headphone = output_mode; + break; + case AudioOutputModeTarget::Type3: + m_system_settings.audio_output_mode_type3 = output_mode; + break; + case AudioOutputModeTarget::Type4: + m_system_settings.audio_output_mode_type4 = output_mode; + break; + default: + LOG_ERROR(Service_SET, "Invalid audio output mode target {}", target); + } + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetSpeakerAutoMuteFlag(bool& is_auto_mute) const { + is_auto_mute = m_system_settings.force_mute_on_headphone_removed; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetSpeakerAutoMuteFlag(bool is_auto_mute) { + m_system_settings.force_mute_on_headphone_removed = is_auto_mute; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetExternalSteadyClockSourceId(Common::UUID& out_id) const { + out_id = m_private_settings.external_clock_source_id; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetExternalSteadyClockSourceId(const Common::UUID& id) { + m_private_settings.external_clock_source_id = id; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetUserSystemClockContext( + Service::PSC::Time::SystemClockContext& out_context) const { + out_context = m_system_settings.user_system_clock_context; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetUserSystemClockContext( + const Service::PSC::Time::SystemClockContext& context) { + m_system_settings.user_system_clock_context = context; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetDeviceTimeZoneLocationName( + Service::PSC::Time::LocationName& out_name) const { + out_name = m_system_settings.device_time_zone_location_name; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetDeviceTimeZoneLocationName( + const Service::PSC::Time::LocationName& name) { + m_system_settings.device_time_zone_location_name = name; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetNetworkSystemClockContext( + Service::PSC::Time::SystemClockContext& out_context) const { + out_context = m_system_settings.network_system_clock_context; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetNetworkSystemClockContext( + const Service::PSC::Time::SystemClockContext& context) { + m_system_settings.network_system_clock_context = context; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) const { + out_enabled = m_system_settings.user_system_clock_automatic_correction_enabled; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionEnabled(bool enabled) { + m_system_settings.user_system_clock_automatic_correction_enabled = enabled; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetExternalSteadyClockInternalOffset(s64 offset) { + m_private_settings.external_steady_clock_internal_offset = offset; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetExternalSteadyClockInternalOffset(s64& out_offset) const { + out_offset = m_private_settings.external_steady_clock_internal_offset; + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point) const { + out_time_point = m_system_settings.device_time_zone_location_updated_time; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime( + const Service::PSC::Time::SteadyClockTimePoint& time_point) { + m_system_settings.device_time_zone_location_updated_time = time_point; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point) const { + out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; + R_SUCCEED(); +} + +Result ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( + const Service::PSC::Time::SteadyClockTimePoint& out_time_point) { + m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; + SetSaveNeeded(); + R_SUCCEED(); +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h new file mode 100644 index 000000000..1982b9723 --- /dev/null +++ b/src/core/hle/service/set/system_settings_server.h @@ -0,0 +1,178 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <filesystem> +#include <mutex> +#include <string> +#include <thread> + +#include "common/polyfill_thread.h" +#include "common/uuid.h" +#include "core/hle/result.h" +#include "core/hle/service/psc/time/common.h" +#include "core/hle/service/service.h" +#include "core/hle/service/set/setting_formats/appln_settings.h" +#include "core/hle/service/set/setting_formats/device_settings.h" +#include "core/hle/service/set/setting_formats/private_settings.h" +#include "core/hle/service/set/setting_formats/system_settings.h" +#include "core/hle/service/set/settings_types.h" + +namespace Core { +class System; +} + +namespace Service::Set { + +Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, + GetFirmwareVersionType type); + +class ISystemSettingsServer final : public ServiceFramework<ISystemSettingsServer> { +public: + explicit ISystemSettingsServer(Core::System& system_); + ~ISystemSettingsServer() override; + + Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, + const std::string& name); + + template <typename T> + Result GetSettingsItemValue(T& value, const std::string& category, const std::string& name) { + std::vector<u8> data; + const auto result = GetSettingsItemValue(data, category, name); + if (result.IsError()) { + return result; + } + ASSERT(data.size() >= sizeof(T)); + std::memcpy(&value, data.data(), sizeof(T)); + return result; + } + + Result GetVibrationMasterVolume(f32& out_volume) const; + Result SetVibrationMasterVolume(f32 volume); + Result GetAudioOutputMode(AudioOutputMode& out_output_mode, AudioOutputModeTarget target) const; + Result SetAudioOutputMode(AudioOutputModeTarget target, AudioOutputMode output_mode); + Result GetSpeakerAutoMuteFlag(bool& is_auto_mute) const; + Result SetSpeakerAutoMuteFlag(bool auto_mute); + Result GetExternalSteadyClockSourceId(Common::UUID& out_id) const; + Result SetExternalSteadyClockSourceId(const Common::UUID& id); + Result GetUserSystemClockContext(Service::PSC::Time::SystemClockContext& out_context) const; + Result SetUserSystemClockContext(const Service::PSC::Time::SystemClockContext& context); + Result GetDeviceTimeZoneLocationName(Service::PSC::Time::LocationName& out_name) const; + Result SetDeviceTimeZoneLocationName(const Service::PSC::Time::LocationName& name); + Result GetNetworkSystemClockContext(Service::PSC::Time::SystemClockContext& out_context) const; + Result SetNetworkSystemClockContext(const Service::PSC::Time::SystemClockContext& context); + Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) const; + Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); + Result SetExternalSteadyClockInternalOffset(s64 offset); + Result GetExternalSteadyClockInternalOffset(s64& out_offset) const; + Result GetDeviceTimeZoneLocationUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point) const; + Result SetDeviceTimeZoneLocationUpdatedTime( + const Service::PSC::Time::SteadyClockTimePoint& time_point); + Result GetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::PSC::Time::SteadyClockTimePoint& out_time_point) const; + Result SetUserSystemClockAutomaticCorrectionUpdatedTime( + const Service::PSC::Time::SteadyClockTimePoint& time_point); + +private: + void SetLanguageCode(HLERequestContext& ctx); + void GetFirmwareVersion(HLERequestContext& ctx); + void GetFirmwareVersion2(HLERequestContext& ctx); + void GetLockScreenFlag(HLERequestContext& ctx); + void SetLockScreenFlag(HLERequestContext& ctx); + void GetExternalSteadyClockSourceId(HLERequestContext& ctx); + void SetExternalSteadyClockSourceId(HLERequestContext& ctx); + void GetUserSystemClockContext(HLERequestContext& ctx); + void SetUserSystemClockContext(HLERequestContext& ctx); + void GetAccountSettings(HLERequestContext& ctx); + void SetAccountSettings(HLERequestContext& ctx); + void GetEulaVersions(HLERequestContext& ctx); + void SetEulaVersions(HLERequestContext& ctx); + void GetColorSetId(HLERequestContext& ctx); + void SetColorSetId(HLERequestContext& ctx); + void GetNotificationSettings(HLERequestContext& ctx); + void SetNotificationSettings(HLERequestContext& ctx); + void GetAccountNotificationSettings(HLERequestContext& ctx); + void SetAccountNotificationSettings(HLERequestContext& ctx); + void GetVibrationMasterVolume(HLERequestContext& ctx); + void SetVibrationMasterVolume(HLERequestContext& ctx); + void GetSettingsItemValueSize(HLERequestContext& ctx); + void GetSettingsItemValue(HLERequestContext& ctx); + void GetTvSettings(HLERequestContext& ctx); + void SetTvSettings(HLERequestContext& ctx); + void GetAudioOutputMode(HLERequestContext& ctx); + void SetAudioOutputMode(HLERequestContext& ctx); + void GetSpeakerAutoMuteFlag(HLERequestContext& ctx); + void SetSpeakerAutoMuteFlag(HLERequestContext& ctx); + void GetDebugModeFlag(HLERequestContext& ctx); + void GetQuestFlag(HLERequestContext& ctx); + void SetQuestFlag(HLERequestContext& ctx); + void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); + void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); + void SetRegionCode(HLERequestContext& ctx); + void GetNetworkSystemClockContext(HLERequestContext& ctx); + void SetNetworkSystemClockContext(HLERequestContext& ctx); + void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void GetPrimaryAlbumStorage(HLERequestContext& ctx); + void SetPrimaryAlbumStorage(HLERequestContext& ctx); + void GetBatteryLot(HLERequestContext& ctx); + void GetSerialNumber(HLERequestContext& ctx); + void GetNfcEnableFlag(HLERequestContext& ctx); + void SetNfcEnableFlag(HLERequestContext& ctx); + void GetSleepSettings(HLERequestContext& ctx); + void SetSleepSettings(HLERequestContext& ctx); + void GetWirelessLanEnableFlag(HLERequestContext& ctx); + void SetWirelessLanEnableFlag(HLERequestContext& ctx); + void GetInitialLaunchSettings(HLERequestContext& ctx); + void SetInitialLaunchSettings(HLERequestContext& ctx); + void GetDeviceNickName(HLERequestContext& ctx); + void SetDeviceNickName(HLERequestContext& ctx); + void GetProductModel(HLERequestContext& ctx); + void GetBluetoothEnableFlag(HLERequestContext& ctx); + void SetBluetoothEnableFlag(HLERequestContext& ctx); + void GetMiiAuthorId(HLERequestContext& ctx); + void GetAutoUpdateEnableFlag(HLERequestContext& ctx); + void SetAutoUpdateEnableFlag(HLERequestContext& ctx); + void GetBatteryPercentageFlag(HLERequestContext& ctx); + void SetBatteryPercentageFlag(HLERequestContext& ctx); + void SetExternalSteadyClockInternalOffset(HLERequestContext& ctx); + void GetExternalSteadyClockInternalOffset(HLERequestContext& ctx); + void GetPushNotificationActivityModeOnSleep(HLERequestContext& ctx); + void SetPushNotificationActivityModeOnSleep(HLERequestContext& ctx); + void GetErrorReportSharePermission(HLERequestContext& ctx); + void SetErrorReportSharePermission(HLERequestContext& ctx); + void GetAppletLaunchFlags(HLERequestContext& ctx); + void SetAppletLaunchFlags(HLERequestContext& ctx); + void GetKeyboardLayout(HLERequestContext& ctx); + void SetKeyboardLayout(HLERequestContext& ctx); + void GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); + void SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); + void GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); + void SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); + void GetChineseTraditionalInputMethod(HLERequestContext& ctx); + void GetHomeMenuScheme(HLERequestContext& ctx); + void GetHomeMenuSchemeModel(HLERequestContext& ctx); + void GetFieldTestingFlag(HLERequestContext& ctx); + void GetPanelCrcMode(HLERequestContext& ctx); + void SetPanelCrcMode(HLERequestContext& ctx); + + bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func); + bool StoreSettingsFile(std::filesystem::path& path, auto& settings); + void SetupSettings(); + void StoreSettings(); + void StoreSettingsThreadFunc(std::stop_token stop_token); + void SetSaveNeeded(); + + Core::System& m_system; + SystemSettings m_system_settings{}; + PrivateSettings m_private_settings{}; + DeviceSettings m_device_settings{}; + ApplnSettings m_appln_settings{}; + std::mutex m_save_needed_mutex; + std::jthread m_save_thread; + bool m_save_needed{false}; +}; + +} // namespace Service::Set diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 4ae32a9c1..32c218638 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -3,6 +3,7 @@ #pragma once +#include <chrono> #include <memory> #include <mutex> #include <string> @@ -10,6 +11,7 @@ #include "common/concepts.h" #include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/svc.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -62,12 +64,21 @@ public: Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name); template <Common::DerivedFrom<SessionRequestHandler> T> - std::shared_ptr<T> GetService(const std::string& service_name) const { + std::shared_ptr<T> GetService(const std::string& service_name, bool block = false) const { auto service = registered_services.find(service_name); - if (service == registered_services.end()) { + if (service == registered_services.end() && !block) { LOG_DEBUG(Service, "Can't find service: {}", service_name); return nullptr; + } else if (block) { + using namespace std::literals::chrono_literals; + while (service == registered_services.end()) { + Kernel::Svc::SleepThread( + kernel.System(), + std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count()); + service = registered_services.find(service_name); + } } + return std::static_pointer_cast<T>(service->second()); } diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h deleted file mode 100644 index 7149fffeb..000000000 --- a/src/core/hle/service/time/clock_types.h +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <ratio> - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/uuid.h" -#include "core/hle/service/time/errors.h" -#include "core/hle/service/time/time_zone_types.h" - -// Defined by WinBase.h on Windows -#ifdef GetCurrentTime -#undef GetCurrentTime -#endif - -namespace Service::Time::Clock { - -enum class TimeType : u8 { - UserSystemClock, - NetworkSystemClock, - LocalSystemClock, -}; - -/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint -struct SteadyClockTimePoint { - s64 time_point; - Common::UUID clock_source_id; - - Result GetSpanBetween(SteadyClockTimePoint other, s64& span) const { - span = 0; - - if (clock_source_id != other.clock_source_id) { - return ERROR_TIME_MISMATCH; - } - - span = other.time_point - time_point; - - return ResultSuccess; - } - - static SteadyClockTimePoint GetRandom() { - return {0, Common::UUID::MakeRandom()}; - } -}; -static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); -static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>, - "SteadyClockTimePoint must be trivially copyable"); - -struct SteadyClockContext { - u64 internal_offset; - Common::UUID steady_time_point; -}; -static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); -static_assert(std::is_trivially_copyable_v<SteadyClockContext>, - "SteadyClockContext must be trivially copyable"); -using StandardSteadyClockTimePointType = SteadyClockContext; - -struct SystemClockContext { - s64 offset; - SteadyClockTimePoint steady_time_point; -}; -static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size"); -static_assert(std::is_trivially_copyable_v<SystemClockContext>, - "SystemClockContext must be trivially copyable"); - -struct ContinuousAdjustmentTimePoint { - s64 measurement_offset; - s64 diff_scale; - u32 shift_amount; - s64 lower; - s64 upper; - Common::UUID clock_source_id; -}; -static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38); -static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>, - "ContinuousAdjustmentTimePoint must be trivially copyable"); - -/// https://switchbrew.org/wiki/Glue_services#TimeSpanType -struct TimeSpanType { - s64 nanoseconds{}; - - s64 ToSeconds() const { - return nanoseconds / std::nano::den; - } - - static TimeSpanType FromSeconds(s64 seconds) { - return {seconds * std::nano::den}; - } - - template <u64 Frequency> - static TimeSpanType FromTicks(u64 ticks) { - using TicksToNSRatio = std::ratio<std::nano::den, Frequency>; - return {static_cast<s64>(ticks * TicksToNSRatio::num / TicksToNSRatio::den)}; - } -}; -static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); - -struct ClockSnapshot { - SystemClockContext user_context; - SystemClockContext network_context; - s64 user_time; - s64 network_time; - TimeZone::CalendarTime user_calendar_time; - TimeZone::CalendarTime network_calendar_time; - TimeZone::CalendarAdditionalInfo user_calendar_additional_time; - TimeZone::CalendarAdditionalInfo network_calendar_additional_time; - SteadyClockTimePoint steady_clock_time_point; - TimeZone::LocationName location_name; - u8 is_automatic_correction_enabled; - TimeType type; - INSERT_PADDING_BYTES_NOINIT(0x2); - - static Result GetCurrentTime(s64& current_time, - const SteadyClockTimePoint& steady_clock_time_point, - const SystemClockContext& context) { - if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) { - current_time = 0; - return ERROR_TIME_MISMATCH; - } - current_time = steady_clock_time_point.time_point + context.offset; - return ResultSuccess; - } -}; -static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size"); - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h deleted file mode 100644 index 0f928a5a5..000000000 --- a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/system_clock_context_update_callback.h" - -namespace Service::Time::Clock { - -class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { -public: - EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {} -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h deleted file mode 100644 index 0a5f5aafb..000000000 --- a/src/core/hle/service/time/ephemeral_network_system_clock_core.h +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/system_clock_core.h" - -namespace Service::Time::Clock { - -class EphemeralNetworkSystemClockCore final : public SystemClockCore { -public: - explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core_) - : SystemClockCore{steady_clock_core_} {} -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/errors.h b/src/core/hle/service/time/errors.h deleted file mode 100644 index 6655d30e1..000000000 --- a/src/core/hle/service/time/errors.h +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/result.h" - -namespace Service::Time { - -constexpr Result ERROR_PERMISSION_DENIED{ErrorModule::Time, 1}; -constexpr Result ERROR_TIME_MISMATCH{ErrorModule::Time, 102}; -constexpr Result ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103}; -constexpr Result ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200}; -constexpr Result ERROR_OVERFLOW{ErrorModule::Time, 201}; -constexpr Result ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801}; -constexpr Result ERROR_OUT_OF_RANGE{ErrorModule::Time, 902}; -constexpr Result ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903}; -constexpr Result ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989}; -constexpr Result ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h deleted file mode 100644 index 1639ef2b9..000000000 --- a/src/core/hle/service/time/local_system_clock_context_writer.h +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/system_clock_context_update_callback.h" -#include "core/hle/service/time/time_sharedmemory.h" - -namespace Service::Time::Clock { - -class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback { -public: - explicit LocalSystemClockContextWriter(SharedMemory& shared_memory_) - : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {} - -protected: - Result Update() override { - shared_memory.UpdateLocalSystemClockContext(context); - return ResultSuccess; - } - -private: - SharedMemory& shared_memory; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h deleted file mode 100644 index 655e4c06d..000000000 --- a/src/core/hle/service/time/network_system_clock_context_writer.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/errors.h" -#include "core/hle/service/time/system_clock_context_update_callback.h" -#include "core/hle/service/time/time_sharedmemory.h" - -namespace Service::Time::Clock { - -class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { -public: - explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory_) - : SystemClockContextUpdateCallback{}, shared_memory{shared_memory_} {} - -protected: - Result Update() override { - shared_memory.UpdateNetworkSystemClockContext(context); - return ResultSuccess; - } - -private: - SharedMemory& shared_memory; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h deleted file mode 100644 index ae2ff1bfd..000000000 --- a/src/core/hle/service/time/standard_local_system_clock_core.h +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/system_clock_core.h" - -namespace Service::Time::Clock { - -class StandardLocalSystemClockCore final : public SystemClockCore { -public: - explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core_) - : SystemClockCore{steady_clock_core_} {} -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h deleted file mode 100644 index c1ec5252b..000000000 --- a/src/core/hle/service/time/standard_network_system_clock_core.h +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/steady_clock_core.h" -#include "core/hle/service/time/system_clock_core.h" - -namespace Core { -class System; -} - -namespace Service::Time::Clock { - -class StandardNetworkSystemClockCore final : public SystemClockCore { -public: - explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core_) - : SystemClockCore{steady_clock_core_} {} - - void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) { - standard_network_clock_sufficient_accuracy = value; - } - - bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) const { - SystemClockContext clock_ctx{}; - if (GetClockContext(system, clock_ctx) != ResultSuccess) { - return {}; - } - - s64 span{}; - if (clock_ctx.steady_time_point.GetSpanBetween( - GetSteadyClockCore().GetCurrentTimePoint(system), span) != ResultSuccess) { - return {}; - } - - return TimeSpanType{span}.nanoseconds < - standard_network_clock_sufficient_accuracy.nanoseconds; - } - -private: - TimeSpanType standard_network_clock_sufficient_accuracy{}; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp deleted file mode 100644 index 5627b7003..000000000 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hardware_properties.h" -#include "core/hle/service/time/standard_steady_clock_core.h" - -namespace Service::Time::Clock { - -TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { - const TimeSpanType ticks_time_span{ - TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; - TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; - - if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { - raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds; - } - - cached_raw_time_point = raw_time_point; - return raw_time_point; -} - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_steady_clock_core.h b/src/core/hle/service/time/standard_steady_clock_core.h deleted file mode 100644 index 036463b87..000000000 --- a/src/core/hle/service/time/standard_steady_clock_core.h +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/steady_clock_core.h" - -namespace Core { -class System; -} - -namespace Service::Time::Clock { - -class StandardSteadyClockCore final : public SteadyClockCore { -public: - SteadyClockTimePoint GetTimePoint(Core::System& system) override { - return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()}; - } - - TimeSpanType GetInternalOffset() const override { - return internal_offset; - } - - void SetInternalOffset(TimeSpanType value) override { - internal_offset = value; - } - - TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; - - void SetSetupValue(TimeSpanType value) { - setup_value = value; - } - -private: - TimeSpanType setup_value{}; - TimeSpanType internal_offset{}; - TimeSpanType cached_raw_time_point{}; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp deleted file mode 100644 index b033757ed..000000000 --- a/src/core/hle/service/time/standard_user_system_clock_core.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/assert.h" -#include "core/core.h" -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/time/standard_local_system_clock_core.h" -#include "core/hle/service/time/standard_network_system_clock_core.h" -#include "core/hle/service/time/standard_user_system_clock_core.h" - -namespace Service::Time::Clock { - -StandardUserSystemClockCore::StandardUserSystemClockCore( - StandardLocalSystemClockCore& local_system_clock_core_, - StandardNetworkSystemClockCore& network_system_clock_core_, Core::System& system_) - : SystemClockCore(local_system_clock_core_.GetSteadyClockCore()), - local_system_clock_core{local_system_clock_core_}, - network_system_clock_core{network_system_clock_core_}, - auto_correction_time{SteadyClockTimePoint::GetRandom()}, service_context{ - system_, - "StandardUserSystemClockCore"} { - auto_correction_event = - service_context.CreateEvent("StandardUserSystemClockCore:AutoCorrectionEvent"); -} - -StandardUserSystemClockCore::~StandardUserSystemClockCore() { - service_context.CloseEvent(auto_correction_event); -} - -Result StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, - bool value) { - if (const Result result{ApplyAutomaticCorrection(system, value)}; result != ResultSuccess) { - return result; - } - - auto_correction_enabled = value; - - return ResultSuccess; -} - -Result StandardUserSystemClockCore::GetClockContext(Core::System& system, - SystemClockContext& ctx) const { - if (const Result result{ApplyAutomaticCorrection(system, false)}; result != ResultSuccess) { - return result; - } - - return local_system_clock_core.GetClockContext(system, ctx); -} - -Result StandardUserSystemClockCore::Flush(const SystemClockContext&) { - UNIMPLEMENTED(); - return ERROR_NOT_IMPLEMENTED; -} - -Result StandardUserSystemClockCore::SetClockContext(const SystemClockContext&) { - UNIMPLEMENTED(); - return ERROR_NOT_IMPLEMENTED; -} - -Result StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system, - bool value) const { - if (auto_correction_enabled == value) { - return ResultSuccess; - } - - if (!network_system_clock_core.IsClockSetup(system)) { - return ERROR_UNINITIALIZED_CLOCK; - } - - SystemClockContext ctx{}; - if (const Result result{network_system_clock_core.GetClockContext(system, ctx)}; - result != ResultSuccess) { - return result; - } - - local_system_clock_core.SetClockContext(ctx); - - return ResultSuccess; -} - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h deleted file mode 100644 index ee6e29487..000000000 --- a/src/core/hle/service/time/standard_user_system_clock_core.h +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/kernel_helpers.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/system_clock_core.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KEvent; -} - -namespace Service::Time::Clock { - -class StandardLocalSystemClockCore; -class StandardNetworkSystemClockCore; - -class StandardUserSystemClockCore final : public SystemClockCore { -public: - StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core_, - StandardNetworkSystemClockCore& network_system_clock_core_, - Core::System& system_); - - ~StandardUserSystemClockCore() override; - - Result SetAutomaticCorrectionEnabled(Core::System& system, bool value); - - Result GetClockContext(Core::System& system, SystemClockContext& ctx) const override; - - bool IsAutomaticCorrectionEnabled() const { - return auto_correction_enabled; - } - - void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) { - auto_correction_time = steady_clock_time_point; - } - -protected: - Result Flush(const SystemClockContext&) override; - - Result SetClockContext(const SystemClockContext&) override; - - Result ApplyAutomaticCorrection(Core::System& system, bool value) const; - - const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const { - return auto_correction_time; - } - -private: - StandardLocalSystemClockCore& local_system_clock_core; - StandardNetworkSystemClockCore& network_system_clock_core; - bool auto_correction_enabled{}; - SteadyClockTimePoint auto_correction_time; - KernelHelpers::ServiceContext service_context; - Kernel::KEvent* auto_correction_event; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h deleted file mode 100644 index 2867c351c..000000000 --- a/src/core/hle/service/time/steady_clock_core.h +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/uuid.h" -#include "core/hle/service/time/clock_types.h" - -namespace Core { -class System; -} - -namespace Service::Time::Clock { - -class SteadyClockCore { -public: - SteadyClockCore() = default; - virtual ~SteadyClockCore() = default; - - const Common::UUID& GetClockSourceId() const { - return clock_source_id; - } - - void SetClockSourceId(const Common::UUID& value) { - clock_source_id = value; - } - - virtual TimeSpanType GetInternalOffset() const = 0; - - virtual void SetInternalOffset(TimeSpanType internal_offset) = 0; - - virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0; - - virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0; - - SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) { - SteadyClockTimePoint result{GetTimePoint(system)}; - result.time_point += GetInternalOffset().ToSeconds(); - return result; - } - - bool IsInitialized() const { - return is_initialized; - } - - void MarkAsInitialized() { - is_initialized = true; - } - -private: - Common::UUID clock_source_id{Common::UUID::MakeRandom()}; - bool is_initialized{}; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp deleted file mode 100644 index cafc04ee7..000000000 --- a/src/core/hle/service/time/system_clock_context_update_callback.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/kernel/k_event.h" -#include "core/hle/service/time/errors.h" -#include "core/hle/service/time/system_clock_context_update_callback.h" - -namespace Service::Time::Clock { - -SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default; -SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default; - -bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const { - if (has_context) { - return context.offset != value.offset || - context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id; - } - - return true; -} - -void SystemClockContextUpdateCallback::RegisterOperationEvent( - std::shared_ptr<Kernel::KEvent>&& event) { - operation_event_list.emplace_back(std::move(event)); -} - -void SystemClockContextUpdateCallback::BroadcastOperationEvent() { - for (const auto& event : operation_event_list) { - event->Signal(); - } -} - -Result SystemClockContextUpdateCallback::Update(const SystemClockContext& value) { - Result result{ResultSuccess}; - - if (NeedUpdate(value)) { - context = value; - has_context = true; - - result = Update(); - - if (result == ResultSuccess) { - BroadcastOperationEvent(); - } - } - - return result; -} - -Result SystemClockContextUpdateCallback::Update() { - return ResultSuccess; -} - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h deleted file mode 100644 index bf657acd9..000000000 --- a/src/core/hle/service/time/system_clock_context_update_callback.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> -#include <vector> - -#include "core/hle/service/time/clock_types.h" - -namespace Kernel { -class KEvent; -} - -namespace Service::Time::Clock { - -// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). -// This code was released under public domain. - -class SystemClockContextUpdateCallback { -public: - SystemClockContextUpdateCallback(); - virtual ~SystemClockContextUpdateCallback(); - - bool NeedUpdate(const SystemClockContext& value) const; - - void RegisterOperationEvent(std::shared_ptr<Kernel::KEvent>&& event); - - void BroadcastOperationEvent(); - - Result Update(const SystemClockContext& value); - -protected: - virtual Result Update(); - - SystemClockContext context{}; - -private: - bool has_context{}; - std::vector<std::shared_ptr<Kernel::KEvent>> operation_event_list; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp deleted file mode 100644 index da078241f..000000000 --- a/src/core/hle/service/time/system_clock_core.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/time/steady_clock_core.h" -#include "core/hle/service/time/system_clock_context_update_callback.h" -#include "core/hle/service/time/system_clock_core.h" - -namespace Service::Time::Clock { - -SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core_) - : steady_clock_core{steady_clock_core_} { - context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); -} - -SystemClockCore::~SystemClockCore() = default; - -Result SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const { - posix_time = 0; - - const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; - - SystemClockContext clock_context{}; - if (const Result result{GetClockContext(system, clock_context)}; result != ResultSuccess) { - return result; - } - - if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) { - return ERROR_TIME_MISMATCH; - } - - posix_time = clock_context.offset + current_time_point.time_point; - - return ResultSuccess; -} - -Result SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) { - const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; - const SystemClockContext clock_context{posix_time - current_time_point.time_point, - current_time_point}; - - if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) { - return result; - } - return Flush(clock_context); -} - -Result SystemClockCore::Flush(const SystemClockContext& clock_context) { - if (!system_clock_context_update_callback) { - return ResultSuccess; - } - return system_clock_context_update_callback->Update(clock_context); -} - -Result SystemClockCore::SetSystemClockContext(const SystemClockContext& clock_context) { - if (const Result result{SetClockContext(clock_context)}; result != ResultSuccess) { - return result; - } - return Flush(clock_context); -} - -bool SystemClockCore::IsClockSetup(Core::System& system) const { - SystemClockContext value{}; - if (GetClockContext(system, value) == ResultSuccess) { - const SteadyClockTimePoint steady_clock_time_point{ - steady_clock_core.GetCurrentTimePoint(system)}; - return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id; - } - return {}; -} - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h deleted file mode 100644 index 8cb34126f..000000000 --- a/src/core/hle/service/time/system_clock_core.h +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <memory> - -#include "common/common_types.h" -#include "core/hle/service/time/clock_types.h" - -namespace Core { -class System; -} - -namespace Service::Time::Clock { - -class SteadyClockCore; -class SystemClockContextUpdateCallback; - -// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). -// This code was released under public domain. - -class SystemClockCore { -public: - explicit SystemClockCore(SteadyClockCore& steady_clock_core_); - virtual ~SystemClockCore(); - - SteadyClockCore& GetSteadyClockCore() const { - return steady_clock_core; - } - - Result GetCurrentTime(Core::System& system, s64& posix_time) const; - - Result SetCurrentTime(Core::System& system, s64 posix_time); - - virtual Result GetClockContext([[maybe_unused]] Core::System& system, - SystemClockContext& value) const { - value = context; - return ResultSuccess; - } - - virtual Result SetClockContext(const SystemClockContext& value) { - context = value; - return ResultSuccess; - } - - virtual Result Flush(const SystemClockContext& clock_context); - - void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) { - system_clock_context_update_callback = std::move(callback); - } - - Result SetSystemClockContext(const SystemClockContext& context); - - bool IsInitialized() const { - return is_initialized; - } - - void MarkAsInitialized() { - is_initialized = true; - } - - bool IsClockSetup(Core::System& system) const; - -private: - SteadyClockCore& steady_clock_core; - SystemClockContext context{}; - bool is_initialized{}; - std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp deleted file mode 100644 index 0d9fb3143..000000000 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hardware_properties.h" -#include "core/hle/service/time/tick_based_steady_clock_core.h" - -namespace Service::Time::Clock { - -SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { - const TimeSpanType ticks_time_span{ - TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())}; - - return {ticks_time_span.ToSeconds(), GetClockSourceId()}; -} - -TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { - return TimeSpanType::FromSeconds(GetTimePoint(system).time_point); -} - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.h b/src/core/hle/service/time/tick_based_steady_clock_core.h deleted file mode 100644 index 491185dc3..000000000 --- a/src/core/hle/service/time/tick_based_steady_clock_core.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/steady_clock_core.h" - -namespace Core { -class System; -} - -namespace Service::Time::Clock { - -class TickBasedSteadyClockCore final : public SteadyClockCore { -public: - TimeSpanType GetInternalOffset() const override { - return {}; - } - - void SetInternalOffset(TimeSpanType internal_offset) override {} - - SteadyClockTimePoint GetTimePoint(Core::System& system) override; - - TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; -}; - -} // namespace Service::Time::Clock diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp deleted file mode 100644 index 7197ca30f..000000000 --- a/src/core/hle/service/time/time.cpp +++ /dev/null @@ -1,412 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/logging/log.h" -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hardware_properties.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/server_manager.h" -#include "core/hle/service/time/time.h" -#include "core/hle/service/time/time_interface.h" -#include "core/hle/service/time/time_manager.h" -#include "core/hle/service/time/time_sharedmemory.h" -#include "core/hle/service/time/time_zone_service.h" - -namespace Service::Time { - -class ISystemClock final : public ServiceFramework<ISystemClock> { -public: - explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_) - : ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, - {1, nullptr, "SetCurrentTime"}, - {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, - {3, nullptr, "SetSystemClockContext"}, - {4, nullptr, "GetOperationEventReadableHandle"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - void GetCurrentTime(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - if (!clock_core.IsInitialized()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_UNINITIALIZED_CLOCK); - return; - } - - s64 posix_time{}; - if (const Result result{clock_core.GetCurrentTime(system, posix_time)}; result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<s64>(posix_time); - } - - void GetSystemClockContext(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - if (!clock_core.IsInitialized()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_UNINITIALIZED_CLOCK); - return; - } - - Clock::SystemClockContext system_clock_context{}; - if (const Result result{clock_core.GetClockContext(system, system_clock_context)}; - result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(system_clock_context); - } - - Clock::SystemClockCore& clock_core; -}; - -class ISteadyClock final : public ServiceFramework<ISteadyClock> { -public: - explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_) - : ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} { - static const FunctionInfo functions[] = { - {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, - {2, nullptr, "GetTestOffset"}, - {3, nullptr, "SetTestOffset"}, - {100, nullptr, "GetRtcValue"}, - {101, nullptr, "IsRtcResetDetected"}, - {102, nullptr, "GetSetupResultValue"}, - {200, nullptr, "GetInternalOffset"}, - {201, nullptr, "SetInternalOffset"}, - }; - RegisterHandlers(functions); - } - -private: - void GetCurrentTimePoint(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - if (!clock_core.IsInitialized()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_UNINITIALIZED_CLOCK); - return; - } - - const Clock::SteadyClockTimePoint time_point{clock_core.GetCurrentTimePoint(system)}; - IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(time_point); - } - - Clock::SteadyClockCore& clock_core; -}; - -Result Module::Interface::GetClockSnapshotFromSystemClockContextInternal( - Kernel::KThread* thread, Clock::SystemClockContext user_context, - Clock::SystemClockContext network_context, Clock::TimeType type, - Clock::ClockSnapshot& clock_snapshot) { - - auto& time_manager{system.GetTimeManager()}; - - clock_snapshot.steady_clock_time_point = - time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system); - clock_snapshot.is_automatic_correction_enabled = - time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); - clock_snapshot.type = type; - - if (const Result result{ - time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName( - clock_snapshot.location_name)}; - result != ResultSuccess) { - return result; - } - - clock_snapshot.user_context = user_context; - - if (const Result result{Clock::ClockSnapshot::GetCurrentTime( - clock_snapshot.user_time, clock_snapshot.steady_clock_time_point, - clock_snapshot.user_context)}; - result != ResultSuccess) { - return result; - } - - TimeZone::CalendarInfo userCalendarInfo{}; - if (const Result result{ - time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( - clock_snapshot.user_time, userCalendarInfo)}; - result != ResultSuccess) { - return result; - } - - clock_snapshot.user_calendar_time = userCalendarInfo.time; - clock_snapshot.user_calendar_additional_time = userCalendarInfo.additional_info; - - clock_snapshot.network_context = network_context; - - if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, - clock_snapshot.steady_clock_time_point, - clock_snapshot.network_context) != ResultSuccess) { - clock_snapshot.network_time = 0; - } - - TimeZone::CalendarInfo networkCalendarInfo{}; - if (const Result result{ - time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( - clock_snapshot.network_time, networkCalendarInfo)}; - result != ResultSuccess) { - return result; - } - - clock_snapshot.network_calendar_time = networkCalendarInfo.time; - clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additional_info; - - return ResultSuccess; -} - -void Module::Interface::GetStandardUserSystemClock(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(), - system); -} - -void Module::Interface::GetStandardNetworkSystemClock(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(), - system); -} - -void Module::Interface::GetStandardSteadyClock(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system); -} - -void Module::Interface::GetTimeZoneService(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ITimeZoneService>(system, - system.GetTimeManager().GetTimeZoneContentManager()); -} - -void Module::Interface::GetStandardLocalSystemClock(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(), - system); -} - -void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()}; - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); -} - -void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()}; - if (!steady_clock_core.IsInitialized()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_UNINITIALIZED_CLOCK); - return; - } - - IPC::RequestParser rp{ctx}; - const auto context{rp.PopRaw<Clock::SystemClockContext>()}; - const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; - - if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { - const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( - system.CoreTiming().GetClockTicks())}; - const s64 base_time_point{context.offset + current_time_point.time_point - - ticks.ToSeconds()}; - IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(base_time_point); - return; - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_TIME_MISMATCH); -} - -void Module::Interface::GetClockSnapshot(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto type{rp.PopEnum<Clock::TimeType>()}; - - LOG_DEBUG(Service_Time, "called, type={}", type); - - Clock::SystemClockContext user_context{}; - if (const Result result{ - system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system, - user_context)}; - result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - Clock::SystemClockContext network_context{}; - if (const Result result{ - system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( - system, network_context)}; - result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - Clock::ClockSnapshot clock_snapshot{}; - if (const Result result{GetClockSnapshotFromSystemClockContextInternal( - &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; - result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - ctx.WriteBuffer(clock_snapshot); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void Module::Interface::GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto type{rp.PopEnum<Clock::TimeType>()}; - - rp.Skip(1, false); - - const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()}; - const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()}; - - LOG_DEBUG(Service_Time, "called, type={}", type); - - Clock::ClockSnapshot clock_snapshot{}; - if (const Result result{GetClockSnapshotFromSystemClockContextInternal( - &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - ctx.WriteBuffer(clock_snapshot); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); -} - -void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - Clock::ClockSnapshot snapshot_a; - Clock::ClockSnapshot snapshot_b; - - const auto snapshot_a_data = ctx.ReadBuffer(0); - const auto snapshot_b_data = ctx.ReadBuffer(1); - - std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot)); - std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot)); - - auto time_span_type{Clock::TimeSpanType::FromSeconds(snapshot_b.user_context.offset - - snapshot_a.user_context.offset)}; - - if ((snapshot_b.user_context.steady_time_point.clock_source_id != - snapshot_a.user_context.steady_time_point.clock_source_id) || - (snapshot_b.is_automatic_correction_enabled && - snapshot_a.is_automatic_correction_enabled)) { - time_span_type.nanoseconds = 0; - } - - IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(time_span_type.nanoseconds); -} - -void Module::Interface::CalculateSpanBetween(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - Clock::ClockSnapshot snapshot_a; - Clock::ClockSnapshot snapshot_b; - - const auto snapshot_a_data = ctx.ReadBuffer(0); - const auto snapshot_b_data = ctx.ReadBuffer(1); - - std::memcpy(&snapshot_a, snapshot_a_data.data(), sizeof(Clock::ClockSnapshot)); - std::memcpy(&snapshot_b, snapshot_b_data.data(), sizeof(Clock::ClockSnapshot)); - - Clock::TimeSpanType time_span_type{}; - s64 span{}; - - if (const Result result{snapshot_a.steady_clock_time_point.GetSpanBetween( - snapshot_b.steady_clock_time_point, span)}; - result != ResultSuccess) { - if (snapshot_a.network_time && snapshot_b.network_time) { - time_span_type = - Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time); - } else { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_TIME_NOT_FOUND); - return; - } - } else { - time_span_type = Clock::TimeSpanType::FromSeconds(span); - } - - IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(time_span_type.nanoseconds); -} - -void Module::Interface::GetSharedMemoryNativeHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(&system.Kernel().GetTimeSharedMem()); -} - -Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, - const char* name) - : ServiceFramework{system_, name}, module{std::move(module_)} {} - -Module::Interface::~Interface() = default; - -void LoopProcess(Core::System& system) { - auto server_manager = std::make_unique<ServerManager>(system); - auto module{std::make_shared<Module>()}; - - server_manager->RegisterNamedService("time:a", - std::make_shared<Time>(module, system, "time:a")); - server_manager->RegisterNamedService("time:s", - std::make_shared<Time>(module, system, "time:s")); - server_manager->RegisterNamedService("time:u", - std::make_shared<Time>(module, system, "time:u")); - ServerManager::RunServer(std::move(server_manager)); -} - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h deleted file mode 100644 index b2d754ef3..000000000 --- a/src/core/hle/service/time/time.h +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" -#include "core/hle/service/time/clock_types.h" - -namespace Core { -class System; -} - -namespace Service::Time { - -class Module final { -public: - Module() = default; - - class Interface : public ServiceFramework<Interface> { - public: - explicit Interface(std::shared_ptr<Module> module_, Core::System& system_, - const char* name); - ~Interface() override; - - void GetStandardUserSystemClock(HLERequestContext& ctx); - void GetStandardNetworkSystemClock(HLERequestContext& ctx); - void GetStandardSteadyClock(HLERequestContext& ctx); - void GetTimeZoneService(HLERequestContext& ctx); - void GetStandardLocalSystemClock(HLERequestContext& ctx); - void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx); - void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx); - void GetClockSnapshot(HLERequestContext& ctx); - void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx); - void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx); - void CalculateSpanBetween(HLERequestContext& ctx); - void GetSharedMemoryNativeHandle(HLERequestContext& ctx); - - private: - Result GetClockSnapshotFromSystemClockContextInternal( - Kernel::KThread* thread, Clock::SystemClockContext user_context, - Clock::SystemClockContext network_context, Clock::TimeType type, - Clock::ClockSnapshot& cloc_snapshot); - - protected: - std::shared_ptr<Module> module; - }; -}; - -void LoopProcess(Core::System& system); - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_interface.cpp b/src/core/hle/service/time/time_interface.cpp deleted file mode 100644 index 0c53e98ee..000000000 --- a/src/core/hle/service/time/time_interface.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/hle/service/time/time_interface.h" - -namespace Service::Time { - -Time::Time(std::shared_ptr<Module> module_, Core::System& system_, const char* name_) - : Interface{std::move(module_), system_, name_} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, - {1, &Time::GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, - {2, &Time::GetStandardSteadyClock, "GetStandardSteadyClock"}, - {3, &Time::GetTimeZoneService, "GetTimeZoneService"}, - {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, - {5, nullptr, "GetEphemeralNetworkSystemClock"}, - {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, - {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"}, - {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, - {50, nullptr, "SetStandardSteadyClockInternalOffset"}, - {51, nullptr, "GetStandardSteadyClockRtcValue"}, - {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, - {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, - {102, nullptr, "GetStandardUserSystemClockInitialYear"}, - {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, - {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, - {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, - {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, - {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, - {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, - {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"}, - }; - // clang-format on - - RegisterHandlers(functions); -} - -Time::~Time() = default; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_interface.h b/src/core/hle/service/time/time_interface.h deleted file mode 100644 index ceeb0e5ef..000000000 --- a/src/core/hle/service/time/time_interface.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/time/time.h" - -namespace Core { -class System; -} - -namespace Service::Time { - -class Time final : public Module::Interface { -public: - explicit Time(std::shared_ptr<Module> time, Core::System& system_, const char* name_); - ~Time() override; -}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp deleted file mode 100644 index fa0fd0531..000000000 --- a/src/core/hle/service/time/time_manager.cpp +++ /dev/null @@ -1,293 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <chrono> -#include <ctime> - -#include "common/settings.h" -#include "common/time_zone.h" -#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" -#include "core/hle/service/time/ephemeral_network_system_clock_core.h" -#include "core/hle/service/time/local_system_clock_context_writer.h" -#include "core/hle/service/time/network_system_clock_context_writer.h" -#include "core/hle/service/time/tick_based_steady_clock_core.h" -#include "core/hle/service/time/time_manager.h" - -namespace Service::Time { -namespace { -constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL}; - -s64 GetSecondsSinceEpoch() { - const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch(); - return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + - Settings::values.custom_rtc_differential; -} -} // Anonymous namespace - -struct TimeManager::Impl final { - explicit Impl(Core::System& system) - : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core}, - standard_network_system_clock_core{standard_steady_clock_core}, - standard_user_system_clock_core{standard_local_system_clock_core, - standard_network_system_clock_core, system}, - ephemeral_network_system_clock_core{tick_based_steady_clock_core}, - local_system_clock_context_writer{ - std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)}, - network_system_clock_context_writer{ - std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)}, - ephemeral_network_system_clock_context_writer{ - std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, - time_zone_content_manager{system} { - - const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())}; - SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); - SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); - - Clock::SystemClockContext clock_context{}; - standard_local_system_clock_core.GetClockContext(system, clock_context); - - SetupStandardNetworkSystemClock(clock_context, standard_network_clock_accuracy); - SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); - SetupEphemeralNetworkSystemClock(); - } - - ~Impl() = default; - - Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { - return standard_steady_clock_core; - } - - const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { - return standard_steady_clock_core; - } - - Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { - return standard_local_system_clock_core; - } - - const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { - return standard_local_system_clock_core; - } - - Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { - return standard_network_system_clock_core; - } - - const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { - return standard_network_system_clock_core; - } - - Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { - return standard_user_system_clock_core; - } - - const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { - return standard_user_system_clock_core; - } - - TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { - return time_zone_content_manager; - } - - const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { - return time_zone_content_manager; - } - - SharedMemory& GetSharedMemory() { - return shared_memory; - } - - const SharedMemory& GetSharedMemory() const { - return shared_memory; - } - - void SetupTimeZoneManager(std::string location_name, - Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::vector<std::string> location_names, u128 time_zone_rule_version, - FileSys::VirtualFile& vfs_file) { - if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( - location_name, vfs_file) != ResultSuccess) { - ASSERT(false); - return; - } - - time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); - time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( - location_names.size()); - time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names); - time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion( - time_zone_rule_version); - time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); - } - - void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id, - Clock::TimeSpanType setup_value, - Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) { - standard_steady_clock_core.SetClockSourceId(clock_source_id); - standard_steady_clock_core.SetSetupValue(setup_value); - standard_steady_clock_core.SetInternalOffset(internal_offset); - standard_steady_clock_core.MarkAsInitialized(); - - const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system_)}; - shared_memory.SetupStandardSteadyClock(clock_source_id, current_time_point); - } - - void SetupStandardLocalSystemClock(Core::System& system_, - Clock::SystemClockContext clock_context, s64 posix_time) { - standard_local_system_clock_core.SetUpdateCallbackInstance( - local_system_clock_context_writer); - - const auto current_time_point{ - standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system_)}; - if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { - standard_local_system_clock_core.SetSystemClockContext(clock_context); - } else { - if (standard_local_system_clock_core.SetCurrentTime(system_, posix_time) != - ResultSuccess) { - ASSERT(false); - return; - } - } - - standard_local_system_clock_core.MarkAsInitialized(); - } - - void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, - Clock::TimeSpanType sufficient_accuracy) { - standard_network_system_clock_core.SetUpdateCallbackInstance( - network_system_clock_context_writer); - - if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != - ResultSuccess) { - ASSERT(false); - return; - } - - standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( - sufficient_accuracy); - standard_network_system_clock_core.MarkAsInitialized(); - } - - void SetupStandardUserSystemClock(Core::System& system_, bool is_automatic_correction_enabled, - Clock::SteadyClockTimePoint steady_clock_time_point) { - if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( - system_, is_automatic_correction_enabled) != ResultSuccess) { - ASSERT(false); - return; - } - - standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); - standard_user_system_clock_core.MarkAsInitialized(); - shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); - } - - void SetupEphemeralNetworkSystemClock() { - ephemeral_network_system_clock_core.SetUpdateCallbackInstance( - ephemeral_network_system_clock_context_writer); - ephemeral_network_system_clock_core.MarkAsInitialized(); - } - - void UpdateLocalSystemClockTime(Core::System& system_, s64 posix_time) { - const auto timespan{Clock::TimeSpanType::FromSeconds(posix_time)}; - if (GetStandardLocalSystemClockCore() - .SetCurrentTime(system_, timespan.ToSeconds()) - .IsError()) { - ASSERT(false); - return; - } - } - - SharedMemory shared_memory; - - Clock::StandardSteadyClockCore standard_steady_clock_core; - Clock::TickBasedSteadyClockCore tick_based_steady_clock_core; - Clock::StandardLocalSystemClockCore standard_local_system_clock_core; - Clock::StandardNetworkSystemClockCore standard_network_system_clock_core; - Clock::StandardUserSystemClockCore standard_user_system_clock_core; - Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core; - - std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer; - std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer; - std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter> - ephemeral_network_system_clock_context_writer; - - TimeZone::TimeZoneContentManager time_zone_content_manager; -}; - -TimeManager::TimeManager(Core::System& system_) : system{system_} {} - -TimeManager::~TimeManager() = default; - -void TimeManager::Initialize() { - impl = std::make_unique<Impl>(system); - - // Time zones can only be initialized after impl is valid - impl->time_zone_content_manager.Initialize(*this); -} - -Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() { - return impl->standard_steady_clock_core; -} - -const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const { - return impl->standard_steady_clock_core; -} - -Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() { - return impl->standard_local_system_clock_core; -} - -const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const { - return impl->standard_local_system_clock_core; -} - -Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() { - return impl->standard_network_system_clock_core; -} - -const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() - const { - return impl->standard_network_system_clock_core; -} - -Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() { - return impl->standard_user_system_clock_core; -} - -const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const { - return impl->standard_user_system_clock_core; -} - -TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() { - return impl->time_zone_content_manager; -} - -const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const { - return impl->time_zone_content_manager; -} - -SharedMemory& TimeManager::GetSharedMemory() { - return impl->shared_memory; -} - -const SharedMemory& TimeManager::GetSharedMemory() const { - return impl->shared_memory; -} - -void TimeManager::Shutdown() { - impl.reset(); -} - -void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) { - impl->UpdateLocalSystemClockTime(system, posix_time); -} - -void TimeManager::SetupTimeZoneManager(std::string location_name, - Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::vector<std::string> location_names, - u128 time_zone_rule_version, - FileSys::VirtualFile& vfs_file) { - impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names, - time_zone_rule_version, vfs_file); -} -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h deleted file mode 100644 index 84572dbfa..000000000 --- a/src/core/hle/service/time/time_manager.h +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "core/file_sys/vfs_types.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/standard_local_system_clock_core.h" -#include "core/hle/service/time/standard_network_system_clock_core.h" -#include "core/hle/service/time/standard_steady_clock_core.h" -#include "core/hle/service/time/standard_user_system_clock_core.h" -#include "core/hle/service/time/time_sharedmemory.h" -#include "core/hle/service/time/time_zone_content_manager.h" - -namespace Service::Time { - -namespace Clock { -class EphemeralNetworkSystemClockContextWriter; -class LocalSystemClockContextWriter; -class NetworkSystemClockContextWriter; -} // namespace Clock - -// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). -// This code was released under public domain. - -class TimeManager final { -public: - explicit TimeManager(Core::System& system_); - ~TimeManager(); - - void Initialize(); - - Clock::StandardSteadyClockCore& GetStandardSteadyClockCore(); - - const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const; - - Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore(); - - const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const; - - Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore(); - - const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const; - - Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore(); - - const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const; - - TimeZone::TimeZoneContentManager& GetTimeZoneContentManager(); - - const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const; - - void UpdateLocalSystemClockTime(s64 posix_time); - - SharedMemory& GetSharedMemory(); - - const SharedMemory& GetSharedMemory() const; - - void Shutdown(); - - void SetupTimeZoneManager(std::string location_name, - Clock::SteadyClockTimePoint time_zone_updated_time_point, - std::vector<std::string> location_names, u128 time_zone_rule_version, - FileSys::VirtualFile& vfs_file); - -private: - Core::System& system; - - struct Impl; - std::unique_ptr<Impl> impl; -}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp deleted file mode 100644 index a00676669..000000000 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "core/core.h" -#include "core/core_timing.h" -#include "core/hardware_properties.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/steady_clock_core.h" -#include "core/hle/service/time/time_sharedmemory.h" - -namespace Service::Time { - -static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; - -SharedMemory::SharedMemory(Core::System& system_) : system(system_) { - std::memset(system.Kernel().GetTimeSharedMem().GetPointer(), 0, SHARED_MEMORY_SIZE); -} - -SharedMemory::~SharedMemory() = default; - -void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id, - Clock::TimeSpanType current_time_point) { - const Clock::TimeSpanType ticks_time_span{ - Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>( - system.CoreTiming().GetClockTicks())}; - const Clock::SteadyClockContext context{ - static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), - clock_source_id}; - StoreToLockFreeAtomicType(&GetFormat()->standard_steady_clock_timepoint, context); -} - -void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { - // lower and upper are related to the measurement point for the steady time point, - // and compare equal on boot - const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL; - - // This adjusts for some sort of time skew - // Both 0 on boot - const s64 diff_scale = 0; - const u32 shift_amount = 0; - - const Clock::ContinuousAdjustmentTimePoint adjustment{ - .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(), - .diff_scale = diff_scale, - .shift_amount = shift_amount, - .lower = time_point_ns, - .upper = time_point_ns, - .clock_source_id = context.steady_time_point.clock_source_id, - }; - - StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment); - StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context); -} - -void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { - StoreToLockFreeAtomicType(&GetFormat()->standard_network_system_clock_context, context); -} - -void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { - StoreToLockFreeAtomicType( - &GetFormat()->is_standard_user_system_clock_automatic_correction_enabled, is_enabled); -} - -SharedMemory::Format* SharedMemory::GetFormat() { - return reinterpret_cast<SharedMemory::Format*>(system.Kernel().GetTimeSharedMem().GetPointer()); -} - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h deleted file mode 100644 index c89be9765..000000000 --- a/src/core/hle/service/time/time_sharedmemory.h +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/common_types.h" -#include "common/uuid.h" -#include "core/hle/kernel/k_shared_memory.h" -#include "core/hle/service/time/clock_types.h" - -namespace Service::Time { - -// Note: this type is not safe for concurrent writes. -template <typename T> -struct LockFreeAtomicType { - u32 counter_; - std::array<T, 2> value_; -}; - -template <typename T> -static inline void StoreToLockFreeAtomicType(LockFreeAtomicType<T>* p, const T& value) { - // Get the current counter. - auto counter = p->counter_; - - // Increment the counter. - ++counter; - - // Store the updated value. - p->value_[counter % 2] = value; - - // Fence memory. - std::atomic_thread_fence(std::memory_order_release); - - // Set the updated counter. - p->counter_ = counter; -} - -template <typename T> -static inline T LoadFromLockFreeAtomicType(const LockFreeAtomicType<T>* p) { - while (true) { - // Get the counter. - auto counter = p->counter_; - - // Get the value. - auto value = p->value_[counter % 2]; - - // Fence memory. - std::atomic_thread_fence(std::memory_order_acquire); - - // Check that the counter matches. - if (counter == p->counter_) { - return value; - } - } -} - -class SharedMemory final { -public: - explicit SharedMemory(Core::System& system_); - ~SharedMemory(); - - // Shared memory format - struct Format { - LockFreeAtomicType<Clock::StandardSteadyClockTimePointType> standard_steady_clock_timepoint; - LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context; - LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context; - LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled; - LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint; - }; - static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0); - static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38); - static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80); - static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) == - 0xc8); - static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0); - static_assert(sizeof(Format) == 0x148, "Format is an invalid size"); - - void SetupStandardSteadyClock(const Common::UUID& clock_source_id, - Clock::TimeSpanType current_time_point); - void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); - void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); - void SetAutomaticCorrectionEnabled(bool is_enabled); - Format* GetFormat(); - -private: - Core::System& system; -}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp deleted file mode 100644 index 1b96de37a..000000000 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <chrono> -#include <sstream> -#include <utility> - -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/time_zone.h" -#include "core/core.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/romfs.h" -#include "core/file_sys/system_archive/system_archive.h" -#include "core/file_sys/vfs.h" -#include "core/file_sys/vfs_types.h" -#include "core/hle/result.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/time/errors.h" -#include "core/hle/service/time/time_manager.h" -#include "core/hle/service/time/time_zone_content_manager.h" - -namespace Service::Time::TimeZone { - -constexpr u64 time_zone_binary_titleid{0x010000000000080E}; - -static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) { - const auto* nand{system.GetFileSystemController().GetSystemNANDContents()}; - const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)}; - - FileSys::VirtualFile romfs; - if (nca) { - romfs = nca->GetRomFS(); - } - - if (!romfs) { - romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid); - } - - if (!romfs) { - LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid); - return {}; - } - - return FileSys::ExtractRomFS(romfs); -} - -static std::vector<std::string> BuildLocationNameCache( - const FileSys::VirtualDir& time_zone_binary) { - if (!time_zone_binary) { - LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); - return {}; - } - - const FileSys::VirtualFile binary_list{time_zone_binary->GetFile("binaryList.txt")}; - if (!binary_list) { - LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid); - return {}; - } - - std::vector<char> raw_data(binary_list->GetSize() + 1); - binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize()); - - std::stringstream data_stream{raw_data.data()}; - std::string name; - std::vector<std::string> location_name_cache; - while (std::getline(data_stream, name)) { - name.pop_back(); // Remove carriage return - location_name_cache.emplace_back(std::move(name)); - } - return location_name_cache; -} - -TimeZoneContentManager::TimeZoneContentManager(Core::System& system_) - : system{system_}, time_zone_binary{GetTimeZoneBinary(system)}, - location_name_cache{BuildLocationNameCache(time_zone_binary)} {} - -void TimeZoneContentManager::Initialize(TimeManager& time_manager) { - const auto timezone_setting = - Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); - - if (FileSys::VirtualFile vfs_file; - GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) { - const auto time_point{ - time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; - time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {}, - vfs_file); - } else { - time_zone_manager.MarkAsInitialized(); - } -} - -Result TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules, - const std::string& location_name) const { - FileSys::VirtualFile vfs_file; - if (const Result result{GetTimeZoneInfoFile(location_name, vfs_file)}; - result != ResultSuccess) { - return result; - } - - return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file); -} - -bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const { - return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) != - location_name_cache.end(); -} - -Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name, - FileSys::VirtualFile& vfs_file) const { - if (!IsLocationNameValid(location_name)) { - return ERROR_TIME_NOT_FOUND; - } - - if (!time_zone_binary) { - LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); - return ERROR_TIME_NOT_FOUND; - } - - const FileSys::VirtualDir zoneinfo_dir{time_zone_binary->GetSubdirectory("zoneinfo")}; - if (!zoneinfo_dir) { - LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid); - return ERROR_TIME_NOT_FOUND; - } - - vfs_file = zoneinfo_dir->GetFileRelative(location_name); - if (!vfs_file) { - LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.", - time_zone_binary_titleid, location_name); - const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()}; - vfs_file = zoneinfo_dir->GetFile(system_time_zone); - } - - if (!vfs_file) { - LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", - time_zone_binary_titleid, location_name); - vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); - } - - if (!vfs_file) { - LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, - location_name); - return ERROR_TIME_NOT_FOUND; - } - - return ResultSuccess; -} - -} // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h deleted file mode 100644 index a6f9698bc..000000000 --- a/src/core/hle/service/time/time_zone_content_manager.h +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <string> -#include <vector> - -#include "core/file_sys/vfs_types.h" -#include "core/hle/service/time/time_zone_manager.h" - -namespace Core { -class System; -} - -namespace Service::Time { -class TimeManager; -} - -namespace Service::Time::TimeZone { - -class TimeZoneContentManager final { -public: - explicit TimeZoneContentManager(Core::System& system_); - - void Initialize(TimeManager& time_manager); - - TimeZoneManager& GetTimeZoneManager() { - return time_zone_manager; - } - - const TimeZoneManager& GetTimeZoneManager() const { - return time_zone_manager; - } - - Result LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const; - -private: - bool IsLocationNameValid(const std::string& location_name) const; - Result GetTimeZoneInfoFile(const std::string& location_name, - FileSys::VirtualFile& vfs_file) const; - - Core::System& system; - TimeZoneManager time_zone_manager; - const FileSys::VirtualDir time_zone_binary; - const std::vector<std::string> location_name_cache; -}; - -} // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp deleted file mode 100644 index 205371a26..000000000 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ /dev/null @@ -1,1182 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <climits> -#include <limits> - -#include "common/assert.h" -#include "common/logging/log.h" -#include "core/file_sys/content_archive.h" -#include "core/file_sys/nca_metadata.h" -#include "core/file_sys/registered_cache.h" -#include "core/hle/service/time/time_zone_manager.h" -#include "core/hle/service/time/time_zone_types.h" - -namespace Service::Time::TimeZone { - -static constexpr s32 epoch_year{1970}; -static constexpr s32 year_base{1900}; -static constexpr s32 epoch_week_day{4}; -static constexpr s32 seconds_per_minute{60}; -static constexpr s32 minutes_per_hour{60}; -static constexpr s32 hours_per_day{24}; -static constexpr s32 days_per_week{7}; -static constexpr s32 days_per_normal_year{365}; -static constexpr s32 days_per_leap_year{366}; -static constexpr s32 months_per_year{12}; -static constexpr s32 seconds_per_hour{seconds_per_minute * minutes_per_hour}; -static constexpr s32 seconds_per_day{seconds_per_hour * hours_per_day}; -static constexpr s32 years_per_repeat{400}; -static constexpr s64 average_seconds_per_year{31556952}; -static constexpr s64 seconds_per_repeat{years_per_repeat * average_seconds_per_year}; - -struct Rule { - enum class Type : u32 { JulianDay, DayOfYear, MonthNthDayOfWeek }; - Type rule_type{}; - s32 day{}; - s32 week{}; - s32 month{}; - s32 transition_time{}; -}; - -struct CalendarTimeInternal { - s64 year{}; - s8 month{}; - s8 day{}; - s8 hour{}; - s8 minute{}; - s8 second{}; - int Compare(const CalendarTimeInternal& other) const { - if (year != other.year) { - if (year < other.year) { - return -1; - } - return 1; - } - if (month != other.month) { - return month - other.month; - } - if (day != other.day) { - return day - other.day; - } - if (hour != other.hour) { - return hour - other.hour; - } - if (minute != other.minute) { - return minute - other.minute; - } - if (second != other.second) { - return second - other.second; - } - return {}; - } -}; - -template <typename TResult, typename TOperand> -static bool SafeAdd(TResult& result, TOperand op) { - result = result + op; - return true; -} - -template <typename TResult, typename TUnit, typename TBase> -static bool SafeNormalize(TResult& result, TUnit& unit, TBase base) { - TUnit delta{}; - if (unit >= 0) { - delta = unit / base; - } else { - delta = -1 - (-1 - unit) / base; - } - unit -= delta * base; - return SafeAdd(result, delta); -} - -template <typename T> -static constexpr bool IsLeapYear(T year) { - return ((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0); -} - -template <typename T> -static constexpr T GetYearLengthInDays(T year) { - return IsLeapYear(year) ? days_per_leap_year : days_per_normal_year; -} - -static constexpr s64 GetLeapDaysFromYearPositive(s64 year) { - return year / 4 - year / 100 + year / years_per_repeat; -} - -static constexpr s64 GetLeapDaysFromYear(s64 year) { - if (year < 0) { - return -1 - GetLeapDaysFromYearPositive(-1 - year); - } else { - return GetLeapDaysFromYearPositive(year); - } -} - -static constexpr s8 GetMonthLength(bool is_leap_year, int month) { - constexpr std::array<s8, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - constexpr std::array<s8, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; -} - -static constexpr bool IsDigit(char value) { - return value >= '0' && value <= '9'; -} - -static constexpr int GetQZName(const char* name, int offset, char delimiter) { - while (name[offset] != '\0' && name[offset] != delimiter) { - offset++; - } - return offset; -} - -static constexpr int GetTZName(const char* name, int offset) { - char c; - - while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') { - ++offset; - } - return offset; -} - -static constexpr bool GetInteger(const char* name, int& offset, int& value, int min, int max) { - value = 0; - char temp{name[offset]}; - if (!IsDigit(temp)) { - return {}; - } - do { - value = value * 10 + (temp - '0'); - if (value > max) { - return {}; - } - offset++; - temp = name[offset]; - } while (IsDigit(temp)); - - return value >= min; -} - -static constexpr bool GetSeconds(const char* name, int& offset, int& seconds) { - seconds = 0; - int value{}; - if (!GetInteger(name, offset, value, 0, hours_per_day * days_per_week - 1)) { - return {}; - } - seconds = value * seconds_per_hour; - - if (name[offset] == ':') { - offset++; - if (!GetInteger(name, offset, value, 0, minutes_per_hour - 1)) { - return {}; - } - seconds += value * seconds_per_minute; - if (name[offset] == ':') { - offset++; - if (!GetInteger(name, offset, value, 0, seconds_per_minute)) { - return {}; - } - seconds += value; - } - } - return true; -} - -static constexpr bool GetOffset(const char* name, int& offset, int& value) { - bool is_negative{}; - if (name[offset] == '-') { - is_negative = true; - offset++; - } else if (name[offset] == '+') { - offset++; - } - if (!GetSeconds(name, offset, value)) { - return {}; - } - if (is_negative) { - value = -value; - } - return true; -} - -static constexpr bool GetRule(const char* name, int& position, Rule& rule) { - bool is_valid{}; - if (name[position] == 'J') { - position++; - rule.rule_type = Rule::Type::JulianDay; - is_valid = GetInteger(name, position, rule.day, 1, days_per_normal_year); - } else if (name[position] == 'M') { - position++; - rule.rule_type = Rule::Type::MonthNthDayOfWeek; - is_valid = GetInteger(name, position, rule.month, 1, months_per_year); - if (!is_valid) { - return {}; - } - if (name[position++] != '.') { - return {}; - } - is_valid = GetInteger(name, position, rule.week, 1, 5); - if (!is_valid) { - return {}; - } - if (name[position++] != '.') { - return {}; - } - is_valid = GetInteger(name, position, rule.day, 0, days_per_week - 1); - } else if (isdigit(name[position])) { - rule.rule_type = Rule::Type::DayOfYear; - is_valid = GetInteger(name, position, rule.day, 0, days_per_leap_year - 1); - } else { - return {}; - } - if (!is_valid) { - return {}; - } - if (name[position] == '/') { - position++; - return GetOffset(name, position, rule.transition_time); - } else { - rule.transition_time = 2 * seconds_per_hour; - } - return true; -} - -static constexpr int TransitionTime(int year, Rule rule, int offset) { - int value{}; - switch (rule.rule_type) { - case Rule::Type::JulianDay: - value = (rule.day - 1) * seconds_per_day; - if (IsLeapYear(year) && rule.day >= 60) { - value += seconds_per_day; - } - break; - case Rule::Type::DayOfYear: - value = rule.day * seconds_per_day; - break; - case Rule::Type::MonthNthDayOfWeek: { - // Use Zeller's Congruence (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to - // calculate the day of the week for any Julian or Gregorian calendar date. - const int m1{(rule.month + 9) % 12 + 1}; - const int yy0{(rule.month <= 2) ? (year - 1) : year}; - const int yy1{yy0 / 100}; - const int yy2{yy0 % 100}; - int day_of_week{((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7}; - - if (day_of_week < 0) { - day_of_week += days_per_week; - } - int day{rule.day - day_of_week}; - if (day < 0) { - day += days_per_week; - } - for (int i{1}; i < rule.week; i++) { - if (day + days_per_week >= GetMonthLength(IsLeapYear(year), rule.month - 1)) { - break; - } - day += days_per_week; - } - - value = day * seconds_per_day; - for (int index{}; index < rule.month - 1; ++index) { - value += GetMonthLength(IsLeapYear(year), index) * seconds_per_day; - } - break; - } - default: - ASSERT(false); - break; - } - return value + rule.transition_time + offset; -} - -static bool ParsePosixName(const char* name, TimeZoneRule& rule) { - static constexpr char default_rule[]{",M4.1.0,M10.5.0"}; - const char* std_name{name}; - int std_len{}; - int offset{}; - int std_offset{}; - - if (name[offset] == '<') { - offset++; - std_name = name + offset; - const int std_name_offset{offset}; - offset = GetQZName(name, offset, '>'); - if (name[offset] != '>') { - return {}; - } - std_len = offset - std_name_offset; - offset++; - } else { - offset = GetTZName(name, offset); - std_len = offset; - } - if (std_len == 0) { - return {}; - } - if (!GetOffset(name, offset, std_offset)) { - return {}; - } - - int char_count{std_len + 1}; - int dest_len{}; - int dest_offset{}; - const char* dest_name{name + offset}; - if (rule.chars.size() < std::size_t(char_count)) { - return {}; - } - - if (name[offset] != '\0') { - if (name[offset] == '<') { - dest_name = name + (++offset); - const int dest_name_offset{offset}; - offset = GetQZName(name, offset, '>'); - if (name[offset] != '>') { - return {}; - } - dest_len = offset - dest_name_offset; - offset++; - } else { - dest_name = name + (offset); - offset = GetTZName(name, offset); - dest_len = offset; - } - if (dest_len == 0) { - return {}; - } - char_count += dest_len + 1; - if (rule.chars.size() < std::size_t(char_count)) { - return {}; - } - if (name[offset] != '\0' && name[offset] != ',' && name[offset] != ';') { - if (!GetOffset(name, offset, dest_offset)) { - return {}; - } - } else { - dest_offset = std_offset - seconds_per_hour; - } - if (name[offset] == '\0') { - name = default_rule; - offset = 0; - } - if (name[offset] == ',' || name[offset] == ';') { - offset++; - - Rule start{}; - if (!GetRule(name, offset, start)) { - return {}; - } - if (name[offset++] != ',') { - return {}; - } - - Rule end{}; - if (!GetRule(name, offset, end)) { - return {}; - } - if (name[offset] != '\0') { - return {}; - } - - rule.type_count = 2; - rule.ttis[0].gmt_offset = -dest_offset; - rule.ttis[0].is_dst = true; - rule.ttis[0].abbreviation_list_index = std_len + 1; - rule.ttis[1].gmt_offset = -std_offset; - rule.ttis[1].is_dst = false; - rule.ttis[1].abbreviation_list_index = 0; - rule.default_type = 0; - - s64 jan_first{}; - int time_count{}; - int jan_offset{}; - int year_beginning{epoch_year}; - do { - const int year_seconds{GetYearLengthInDays(year_beginning - 1) * seconds_per_day}; - year_beginning--; - if (!SafeAdd(jan_first, -year_seconds)) { - jan_offset = -year_seconds; - break; - } - } while (epoch_year - years_per_repeat / 2 < year_beginning); - - int year_limit{year_beginning + years_per_repeat + 1}; - int year{}; - for (year = year_beginning; year < year_limit; year++) { - int start_time{TransitionTime(year, start, std_offset)}; - int end_time{TransitionTime(year, end, dest_offset)}; - const int year_seconds{GetYearLengthInDays(year) * seconds_per_day}; - const bool is_reversed{end_time < start_time}; - if (is_reversed) { - int swap{start_time}; - start_time = end_time; - end_time = swap; - } - - if (is_reversed || - (start_time < end_time && - (end_time - start_time < (year_seconds + (std_offset - dest_offset))))) { - if (rule.ats.size() - 2 < std::size_t(time_count)) { - break; - } - - rule.ats[time_count] = jan_first; - if (SafeAdd(rule.ats[time_count], jan_offset + start_time)) { - rule.types[time_count++] = is_reversed ? 1 : 0; - } else if (jan_offset != 0) { - rule.default_type = is_reversed ? 1 : 0; - } - - rule.ats[time_count] = jan_first; - if (SafeAdd(rule.ats[time_count], jan_offset + end_time)) { - rule.types[time_count++] = is_reversed ? 0 : 1; - year_limit = year + years_per_repeat + 1; - } else if (jan_offset != 0) { - rule.default_type = is_reversed ? 0 : 1; - } - } - if (!SafeAdd(jan_first, jan_offset + year_seconds)) { - break; - } - jan_offset = 0; - } - rule.time_count = time_count; - if (time_count == 0) { - rule.type_count = 1; - } else if (years_per_repeat < year - year_beginning) { - rule.go_back = true; - rule.go_ahead = true; - } - } else { - if (name[offset] == '\0') { - return {}; - } - - s64 their_std_offset{}; - for (int index{}; index < rule.time_count; ++index) { - const s8 type{rule.types[index]}; - if (rule.ttis[type].is_standard_time_daylight) { - their_std_offset = -rule.ttis[type].gmt_offset; - } - } - - s64 their_offset{their_std_offset}; - for (int index{}; index < rule.time_count; ++index) { - const s8 type{rule.types[index]}; - rule.types[index] = rule.ttis[type].is_dst ? 1 : 0; - if (!rule.ttis[type].is_gmt) { - if (!rule.ttis[type].is_standard_time_daylight) { - rule.ats[index] += dest_offset - their_std_offset; - } else { - rule.ats[index] += std_offset - their_std_offset; - } - } - their_offset = -rule.ttis[type].gmt_offset; - if (!rule.ttis[type].is_dst) { - their_std_offset = their_offset; - } - } - - if (rule.time_count > 0) { - UNIMPLEMENTED(); - // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329 - // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing - } - - rule.ttis[0].gmt_offset = -std_offset; - rule.ttis[0].is_dst = false; - rule.ttis[0].abbreviation_list_index = 0; - rule.ttis[1].gmt_offset = -dest_offset; - rule.ttis[1].is_dst = true; - rule.ttis[1].abbreviation_list_index = std_len + 1; - rule.type_count = 2; - rule.default_type = 0; - } - } else { - // Default is standard time - rule.type_count = 1; - rule.time_count = 0; - rule.default_type = 0; - rule.ttis[0].gmt_offset = -std_offset; - rule.ttis[0].is_dst = false; - rule.ttis[0].abbreviation_list_index = 0; - } - - rule.char_count = char_count; - for (int index{}; index < std_len; ++index) { - rule.chars[index] = std_name[index]; - } - - rule.chars[std_len++] = '\0'; - if (dest_len != 0) { - for (int index{}; index < dest_len; ++index) { - rule.chars[std_len + index] = dest_name[index]; - } - rule.chars[std_len + dest_len] = '\0'; - } - - return true; -} - -static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFile& vfs_file) { - TzifHeader header{}; - if (vfs_file->ReadObject<TzifHeader>(&header) != sizeof(TzifHeader)) { - return {}; - } - - constexpr s32 time_zone_max_leaps{50}; - constexpr s32 time_zone_max_chars{50}; - constexpr s32 time_zone_max_times{1000}; - if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && - 0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) && - 0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) && - 0 <= header.char_count && header.char_count < time_zone_max_chars && - (header.ttis_std_count == header.type_count || header.ttis_std_count == 0) && - (header.ttis_gmt_count == header.type_count || header.ttis_gmt_count == 0))) { - return {}; - } - time_zone_rule.time_count = header.time_count; - time_zone_rule.type_count = header.type_count; - time_zone_rule.char_count = header.char_count; - - int time_count{}; - u64 read_offset = sizeof(TzifHeader); - for (int index{}; index < time_zone_rule.time_count; ++index) { - s64_be at{}; - vfs_file->ReadObject<s64_be>(&at, read_offset); - time_zone_rule.types[index] = 1; - if (time_count != 0 && at <= time_zone_rule.ats[time_count - 1]) { - if (at < time_zone_rule.ats[time_count - 1]) { - return {}; - } - time_zone_rule.types[index - 1] = 0; - time_count--; - } - time_zone_rule.ats[time_count++] = at; - read_offset += sizeof(s64_be); - } - time_count = 0; - for (int index{}; index < time_zone_rule.time_count; ++index) { - const u8 type{*vfs_file->ReadByte(read_offset)}; - read_offset += sizeof(u8); - if (time_zone_rule.type_count <= type) { - return {}; - } - if (time_zone_rule.types[index] != 0) { - time_zone_rule.types[time_count++] = type; - } - } - time_zone_rule.time_count = time_count; - for (int index{}; index < time_zone_rule.type_count; ++index) { - TimeTypeInfo& ttis{time_zone_rule.ttis[index]}; - u32_be gmt_offset{}; - vfs_file->ReadObject<u32_be>(&gmt_offset, read_offset); - read_offset += sizeof(u32_be); - ttis.gmt_offset = gmt_offset; - - const u8 dst{*vfs_file->ReadByte(read_offset)}; - read_offset += sizeof(u8); - if (dst >= 2) { - return {}; - } - ttis.is_dst = dst != 0; - - const s32 abbreviation_list_index{*vfs_file->ReadByte(read_offset)}; - read_offset += sizeof(u8); - if (abbreviation_list_index >= time_zone_rule.char_count) { - return {}; - } - ttis.abbreviation_list_index = abbreviation_list_index; - } - - vfs_file->ReadArray(time_zone_rule.chars.data(), time_zone_rule.char_count, read_offset); - time_zone_rule.chars[time_zone_rule.char_count] = '\0'; - read_offset += time_zone_rule.char_count; - for (int index{}; index < time_zone_rule.type_count; ++index) { - if (header.ttis_std_count == 0) { - time_zone_rule.ttis[index].is_standard_time_daylight = false; - } else { - const u8 dst{*vfs_file->ReadByte(read_offset)}; - read_offset += sizeof(u8); - if (dst >= 2) { - return {}; - } - time_zone_rule.ttis[index].is_standard_time_daylight = dst != 0; - } - } - - for (int index{}; index < time_zone_rule.type_count; ++index) { - if (header.ttis_std_count == 0) { - time_zone_rule.ttis[index].is_gmt = false; - } else { - const u8 dst{*vfs_file->ReadByte(read_offset)}; - read_offset += sizeof(u8); - if (dst >= 2) { - return {}; - } - time_zone_rule.ttis[index].is_gmt = dst != 0; - } - } - - const u64 position{(read_offset - sizeof(TzifHeader))}; - const s64 bytes_read = s64(vfs_file->GetSize() - sizeof(TzifHeader) - position); - if (bytes_read < 0) { - return {}; - } - constexpr s32 time_zone_name_max{255}; - if (bytes_read > (time_zone_name_max + 1)) { - return {}; - } - - std::array<char, time_zone_name_max + 1> temp_name{}; - vfs_file->ReadArray(temp_name.data(), bytes_read, read_offset); - if (bytes_read > 2 && temp_name[0] == '\n' && temp_name[bytes_read - 1] == '\n' && - std::size_t(time_zone_rule.type_count) + 2 <= time_zone_rule.ttis.size()) { - temp_name[bytes_read - 1] = '\0'; - - std::array<char, time_zone_name_max> name{}; - std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1)); - - // Fill in computed transition times with temp rule - TimeZoneRule temp_rule; - if (ParsePosixName(name.data(), temp_rule)) { - int have_abbreviation = 0; - int char_count = time_zone_rule.char_count; - - for (int i = 0; i < temp_rule.type_count; i++) { - char* temp_abbreviation = - temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index; - int j; - for (j = 0; j < char_count; j++) { - if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) { - temp_rule.ttis[i].abbreviation_list_index = j; - have_abbreviation++; - break; - } - } - if (j >= char_count) { - int temp_abbreviation_length = static_cast<int>(std::strlen(temp_abbreviation)); - if (j + temp_abbreviation_length < time_zone_max_chars) { - std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation); - char_count = j + temp_abbreviation_length + 1; - temp_rule.ttis[i].abbreviation_list_index = j; - have_abbreviation++; - } - } - } - - if (have_abbreviation == temp_rule.type_count) { - time_zone_rule.char_count = char_count; - - // Original comment: - /* Ignore any trailing, no-op transitions generated - by zic as they don't help here and can run afoul - of bugs in zic 2016j or earlier. */ - // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic - while (1 < time_zone_rule.time_count && - (time_zone_rule.types[time_zone_rule.time_count - 1] == - time_zone_rule.types[time_zone_rule.time_count - 2])) { - time_zone_rule.time_count--; - } - - for (int i = 0; - i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times; - i++) { - const s64 transition_time = temp_rule.ats[i]; - if (0 < time_zone_rule.time_count && - transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) { - continue; - } - - time_zone_rule.ats[time_zone_rule.time_count] = transition_time; - time_zone_rule.types[time_zone_rule.time_count] = - static_cast<s8>(time_zone_rule.type_count + temp_rule.types[i]); - time_zone_rule.time_count++; - } - for (int i = 0; i < temp_rule.type_count; i++) { - time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i]; - } - } - } - } - - const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool { - if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) { - return {}; - } - - const struct TimeTypeInfo* ap = &rule.ttis[a]; - const struct TimeTypeInfo* bp = &rule.ttis[b]; - - return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst && - (std::strcmp(&rule.chars[ap->abbreviation_list_index], - &rule.chars[bp->abbreviation_list_index]) == 0)); - }; - - if (time_zone_rule.type_count == 0) { - return {}; - } - if (time_zone_rule.time_count > 1) { - if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) { - s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat; - int repeatattype = time_zone_rule.types[0]; - for (int i = 1; i < time_zone_rule.time_count; ++i) { - if (time_zone_rule.ats[i] == repeatat && - typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { - time_zone_rule.go_back = true; - break; - } - } - } - if (std::numeric_limits<s64>::min() + seconds_per_repeat <= - time_zone_rule.ats[time_zone_rule.time_count - 1]) { - s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat; - int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1]; - for (int i = time_zone_rule.time_count; i >= 0; --i) { - if (time_zone_rule.ats[i] == repeatat && - typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) { - time_zone_rule.go_ahead = true; - break; - } - } - } - } - - s32 default_type{}; - - for (default_type = 0; default_type < time_zone_rule.time_count; default_type++) { - if (time_zone_rule.types[default_type] == 0) { - break; - } - } - - default_type = default_type < time_zone_rule.time_count ? -1 : 0; - if (default_type < 0 && time_zone_rule.time_count > 0 && - time_zone_rule.ttis[time_zone_rule.types[0]].is_dst) { - default_type = time_zone_rule.types[0]; - while (--default_type >= 0) { - if (!time_zone_rule.ttis[default_type].is_dst) { - break; - } - } - } - if (default_type < 0) { - default_type = 0; - while (time_zone_rule.ttis[default_type].is_dst) { - if (++default_type >= time_zone_rule.type_count) { - default_type = 0; - break; - } - } - } - time_zone_rule.default_type = default_type; - return true; -} - -static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal& calendar_time, - CalendarAdditionalInfo& calendar_additional_info) { - s64 year{epoch_year}; - s64 time_days{time / seconds_per_day}; - s64 remaining_seconds{time % seconds_per_day}; - while (time_days < 0 || time_days >= GetYearLengthInDays(year)) { - s64 delta = time_days / days_per_leap_year; - if (!delta) { - delta = time_days < 0 ? -1 : 1; - } - s64 new_year{year}; - if (!SafeAdd(new_year, delta)) { - return ERROR_OUT_OF_RANGE; - } - time_days -= (new_year - year) * days_per_normal_year; - time_days -= GetLeapDaysFromYear(new_year - 1) - GetLeapDaysFromYear(year - 1); - year = new_year; - } - - s64 day_of_year{time_days}; - remaining_seconds += gmt_offset; - while (remaining_seconds < 0) { - remaining_seconds += seconds_per_day; - day_of_year--; - } - - while (remaining_seconds >= seconds_per_day) { - remaining_seconds -= seconds_per_day; - day_of_year++; - } - - while (day_of_year < 0) { - if (!SafeAdd(year, -1)) { - return ERROR_OUT_OF_RANGE; - } - day_of_year += GetYearLengthInDays(year); - } - - while (day_of_year >= GetYearLengthInDays(year)) { - day_of_year -= GetYearLengthInDays(year); - if (!SafeAdd(year, 1)) { - return ERROR_OUT_OF_RANGE; - } - } - - calendar_time.year = year; - calendar_additional_info.day_of_year = static_cast<u32>(day_of_year); - s64 day_of_week{ - (epoch_week_day + - ((year - epoch_year) % days_per_week) * (days_per_normal_year % days_per_week) + - GetLeapDaysFromYear(year - 1) - GetLeapDaysFromYear(epoch_year - 1) + day_of_year) % - days_per_week}; - if (day_of_week < 0) { - day_of_week += days_per_week; - } - - calendar_additional_info.day_of_week = static_cast<u32>(day_of_week); - calendar_time.hour = static_cast<s8>((remaining_seconds / seconds_per_hour) % seconds_per_hour); - remaining_seconds %= seconds_per_hour; - calendar_time.minute = static_cast<s8>(remaining_seconds / seconds_per_minute); - calendar_time.second = static_cast<s8>(remaining_seconds % seconds_per_minute); - - for (calendar_time.month = 0; - day_of_year >= GetMonthLength(IsLeapYear(year), calendar_time.month); - ++calendar_time.month) { - day_of_year -= GetMonthLength(IsLeapYear(year), calendar_time.month); - } - - calendar_time.day = static_cast<s8>(day_of_year + 1); - calendar_additional_info.is_dst = false; - calendar_additional_info.gmt_offset = gmt_offset; - - return ResultSuccess; -} - -static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, - CalendarTimeInternal& calendar_time, - CalendarAdditionalInfo& calendar_additional_info) { - ASSERT(rules.go_ahead ? rules.time_count > 0 : true); - if ((rules.go_back && time < rules.ats[0]) || - (rules.go_ahead && time > rules.ats[rules.time_count - 1])) { - s64 seconds{}; - if (time < rules.ats[0]) { - seconds = rules.ats[0] - time; - } else { - seconds = time - rules.ats[rules.time_count - 1]; - } - seconds--; - - const s64 years{(seconds / seconds_per_repeat + 1) * years_per_repeat}; - seconds = years * average_seconds_per_year; - - s64 new_time{time}; - if (time < rules.ats[0]) { - new_time += seconds; - } else { - new_time -= seconds; - } - if (new_time < rules.ats[0] && new_time > rules.ats[rules.time_count - 1]) { - return ERROR_TIME_NOT_FOUND; - } - if (const Result result{ - ToCalendarTimeInternal(rules, new_time, calendar_time, calendar_additional_info)}; - result != ResultSuccess) { - return result; - } - if (time < rules.ats[0]) { - calendar_time.year -= years; - } else { - calendar_time.year += years; - } - - return ResultSuccess; - } - - s32 tti_index{}; - if (rules.time_count == 0 || time < rules.ats[0]) { - tti_index = rules.default_type; - } else { - s32 low{1}; - s32 high{rules.time_count}; - while (low < high) { - s32 mid{(low + high) >> 1}; - if (time < rules.ats[mid]) { - high = mid; - } else { - low = mid + 1; - } - } - tti_index = rules.types[low - 1]; - } - - if (const Result result{CreateCalendarTime(time, rules.ttis[tti_index].gmt_offset, - calendar_time, calendar_additional_info)}; - result != ResultSuccess) { - return result; - } - - calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; - const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; - u32 index; - for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' && - index < calendar_additional_info.timezone_name.size() - 1; - ++index) { - calendar_additional_info.timezone_name[index] = time_zone[index]; - } - calendar_additional_info.timezone_name[index] = '\0'; - return ResultSuccess; -} - -static Result ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) { - CalendarTimeInternal calendar_time{}; - const Result result{ - ToCalendarTimeInternal(rules, time, calendar_time, calendar.additional_info)}; - calendar.time.year = static_cast<s16>(calendar_time.year); - - // Internal impl. uses 0-indexed month - calendar.time.month = static_cast<s8>(calendar_time.month + 1); - - calendar.time.day = calendar_time.day; - calendar.time.hour = calendar_time.hour; - calendar.time.minute = calendar_time.minute; - calendar.time.second = calendar_time.second; - return result; -} - -TimeZoneManager::TimeZoneManager() = default; -TimeZoneManager::~TimeZoneManager() = default; - -Result TimeZoneManager::ToCalendarTime(const TimeZoneRule& rules, s64 time, - CalendarInfo& calendar) const { - return ToCalendarTimeImpl(rules, time, calendar); -} - -Result TimeZoneManager::SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, - FileSys::VirtualFile& vfs_file) { - TimeZoneRule rule{}; - if (ParseTimeZoneBinary(rule, vfs_file)) { - device_location_name = location_name; - time_zone_rule = rule; - return ResultSuccess; - } - return ERROR_TIME_ZONE_CONVERSION_FAILED; -} - -Result TimeZoneManager::SetUpdatedTime(const Clock::SteadyClockTimePoint& value) { - time_zone_update_time_point = value; - return ResultSuccess; -} - -Result TimeZoneManager::ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const { - if (is_initialized) { - return ToCalendarTime(time_zone_rule, time, calendar); - } else { - return ERROR_UNINITIALIZED_CLOCK; - } -} - -Result TimeZoneManager::ParseTimeZoneRuleBinary(TimeZoneRule& rules, - FileSys::VirtualFile& vfs_file) const { - if (!ParseTimeZoneBinary(rules, vfs_file)) { - return ERROR_TIME_ZONE_CONVERSION_FAILED; - } - return ResultSuccess; -} - -Result TimeZoneManager::ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time, - s64& posix_time) const { - posix_time = 0; - - CalendarTimeInternal internal_time{ - .year = calendar_time.year, - // Internal impl. uses 0-indexed month - .month = static_cast<s8>(calendar_time.month - 1), - .day = calendar_time.day, - .hour = calendar_time.hour, - .minute = calendar_time.minute, - .second = calendar_time.second, - }; - - s32 hour{internal_time.hour}; - s32 minute{internal_time.minute}; - if (!SafeNormalize(hour, minute, minutes_per_hour)) { - return ERROR_OVERFLOW; - } - internal_time.minute = static_cast<s8>(minute); - - s32 day{internal_time.day}; - if (!SafeNormalize(day, hour, hours_per_day)) { - return ERROR_OVERFLOW; - } - internal_time.day = static_cast<s8>(day); - internal_time.hour = static_cast<s8>(hour); - - s64 year{internal_time.year}; - s64 month{internal_time.month}; - if (!SafeNormalize(year, month, months_per_year)) { - return ERROR_OVERFLOW; - } - internal_time.month = static_cast<s8>(month); - - if (!SafeAdd(year, year_base)) { - return ERROR_OVERFLOW; - } - - while (day <= 0) { - if (!SafeAdd(year, -1)) { - return ERROR_OVERFLOW; - } - s64 temp_year{year}; - if (1 < internal_time.month) { - ++temp_year; - } - day += static_cast<s32>(GetYearLengthInDays(temp_year)); - } - - while (day > days_per_leap_year) { - s64 temp_year{year}; - if (1 < internal_time.month) { - temp_year++; - } - day -= static_cast<s32>(GetYearLengthInDays(temp_year)); - if (!SafeAdd(year, 1)) { - return ERROR_OVERFLOW; - } - } - - while (true) { - const s32 month_length{GetMonthLength(IsLeapYear(year), internal_time.month)}; - if (day <= month_length) { - break; - } - day -= month_length; - internal_time.month++; - if (internal_time.month >= months_per_year) { - internal_time.month = 0; - if (!SafeAdd(year, 1)) { - return ERROR_OVERFLOW; - } - } - } - internal_time.day = static_cast<s8>(day); - - if (!SafeAdd(year, -year_base)) { - return ERROR_OVERFLOW; - } - internal_time.year = year; - - s32 saved_seconds{}; - if (internal_time.second >= 0 && internal_time.second < seconds_per_minute) { - saved_seconds = 0; - } else if (year + year_base < epoch_year) { - s32 second{internal_time.second}; - if (!SafeAdd(second, 1 - seconds_per_minute)) { - return ERROR_OVERFLOW; - } - saved_seconds = second; - internal_time.second = 1 - seconds_per_minute; - } else { - saved_seconds = internal_time.second; - internal_time.second = 0; - } - - s64 low{LLONG_MIN}; - s64 high{LLONG_MAX}; - while (true) { - s64 pivot{low / 2 + high / 2}; - if (pivot < low) { - pivot = low; - } else if (pivot > high) { - pivot = high; - } - s32 direction{}; - CalendarTimeInternal candidate_calendar_time{}; - CalendarAdditionalInfo unused{}; - if (ToCalendarTimeInternal(rules, pivot, candidate_calendar_time, unused) != - ResultSuccess) { - if (pivot > 0) { - direction = 1; - } else { - direction = -1; - } - } else { - direction = candidate_calendar_time.Compare(internal_time); - } - if (!direction) { - const s64 time_result{pivot + saved_seconds}; - if ((time_result < pivot) != (saved_seconds < 0)) { - return ERROR_OVERFLOW; - } - posix_time = time_result; - break; - } else { - if (pivot == low) { - if (pivot == LLONG_MAX) { - return ERROR_TIME_NOT_FOUND; - } - pivot++; - low++; - } else if (pivot == high) { - if (pivot == LLONG_MIN) { - return ERROR_TIME_NOT_FOUND; - } - pivot--; - high--; - } - if (low > high) { - return ERROR_TIME_NOT_FOUND; - } - if (direction > 0) { - high = pivot; - } else { - low = pivot; - } - } - } - return ResultSuccess; -} - -Result TimeZoneManager::ToPosixTimeWithMyRule(const CalendarTime& calendar_time, - s64& posix_time) const { - if (is_initialized) { - return ToPosixTime(time_zone_rule, calendar_time, posix_time); - } - posix_time = 0; - return ERROR_UNINITIALIZED_CLOCK; -} - -Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const { - if (!is_initialized) { - return ERROR_UNINITIALIZED_CLOCK; - } - std::memcpy(value.data(), device_location_name.c_str(), device_location_name.size()); - return ResultSuccess; -} - -Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const { - if (!is_initialized) { - return ERROR_UNINITIALIZED_CLOCK; - } - count = static_cast<u32>(total_location_name_count); - - return ResultSuccess; -} - -Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const { - if (!is_initialized) { - return ERROR_UNINITIALIZED_CLOCK; - } - version = time_zone_rule_version; - - return ResultSuccess; -} - -Result TimeZoneManager::LoadLocationNameList(std::vector<LocationName>& values) const { - if (!is_initialized) { - return ERROR_UNINITIALIZED_CLOCK; - } - - for (const auto& name : total_location_names) { - LocationName entry{}; - std::memcpy(entry.data(), name.c_str(), name.size()); - values.push_back(entry); - } - - return ResultSuccess; -} - -} // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h deleted file mode 100644 index 8664f28d1..000000000 --- a/src/core/hle/service/time/time_zone_manager.h +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <string> - -#include "common/common_types.h" -#include "core/file_sys/vfs_types.h" -#include "core/hle/service/time/clock_types.h" -#include "core/hle/service/time/time_zone_types.h" - -namespace Service::Time::TimeZone { - -class TimeZoneManager final { -public: - TimeZoneManager(); - ~TimeZoneManager(); - - void SetTotalLocationNameCount(std::size_t value) { - total_location_name_count = value; - } - - void SetLocationNames(std::vector<std::string> location_names) { - total_location_names = location_names; - } - - void SetTimeZoneRuleVersion(const u128& value) { - time_zone_rule_version = value; - } - - void MarkAsInitialized() { - is_initialized = true; - } - - Result SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, - FileSys::VirtualFile& vfs_file); - Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value); - Result GetDeviceLocationName(TimeZone::LocationName& value) const; - Result GetTotalLocationNameCount(s32& count) const; - Result GetTimeZoneRuleVersion(u128& version) const; - Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const; - Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; - Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; - Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; - Result ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time, - s64& posix_time) const; - Result ToPosixTimeWithMyRule(const CalendarTime& calendar_time, s64& posix_time) const; - -private: - bool is_initialized{}; - TimeZoneRule time_zone_rule{}; - std::string device_location_name{"GMT"}; - u128 time_zone_rule_version{}; - std::size_t total_location_name_count{}; - std::vector<std::string> total_location_names{}; - Clock::SteadyClockTimePoint time_zone_update_time_point{ - Clock::SteadyClockTimePoint::GetRandom()}; -}; - -} // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp deleted file mode 100644 index 8171c82a5..000000000 --- a/src/core/hle/service/time/time_zone_service.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "common/logging/log.h" -#include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/time/time_zone_content_manager.h" -#include "core/hle/service/time/time_zone_service.h" -#include "core/hle/service/time/time_zone_types.h" - -namespace Service::Time { - -ITimeZoneService::ITimeZoneService(Core::System& system_, - TimeZone::TimeZoneContentManager& time_zone_manager_) - : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} { - static const FunctionInfo functions[] = { - {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, - {1, nullptr, "SetDeviceLocationName"}, - {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"}, - {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"}, - {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, - {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, - {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, - {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, - {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, - {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, - {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, - }; - RegisterHandlers(functions); -} - -void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - TimeZone::LocationName location_name{}; - if (const Result result{ - time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2}; - rb.Push(ResultSuccess); - rb.PushRaw(location_name); -} - -void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - s32 count{}; - if (const Result result{ - time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(count); -} - -void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - std::vector<TimeZone::LocationName> location_names{}; - if (const Result result{ - time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - ctx.WriteBuffer(location_names); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast<s32>(location_names.size())); -} -void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - u128 rule_version{}; - if (const Result result{ - time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 6}; - rb.Push(ResultSuccess); - rb.PushRaw(rule_version); -} - -void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()}; - - std::string location_name; - for (const auto& byte : raw_location_name) { - // Strip extra bytes - if (byte == '\0') { - break; - } - location_name.push_back(byte); - } - - LOG_DEBUG(Service_Time, "called, location_name={}", location_name); - - TimeZone::TimeZoneRule time_zone_rule{}; - const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)}; - - std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule)); - std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule)); - ctx.WriteBuffer(time_zone_rule_outbuffer); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); -} - -void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto posix_time{rp.Pop<s64>()}; - - LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); - - TimeZone::TimeZoneRule time_zone_rule{}; - const auto buffer{ctx.ReadBuffer()}; - std::memcpy(&time_zone_rule, buffer.data(), buffer.size()); - - TimeZone::CalendarInfo calendar_info{}; - if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime( - time_zone_rule, posix_time, calendar_info)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; - rb.Push(ResultSuccess); - rb.PushRaw(calendar_info); -} - -void ITimeZoneService::ToCalendarTimeWithMyRule(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto posix_time{rp.Pop<s64>()}; - - LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); - - TimeZone::CalendarInfo calendar_info{}; - if (const Result result{ - time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules( - posix_time, calendar_info)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; - rb.Push(ResultSuccess); - rb.PushRaw(calendar_info); -} - -void ITimeZoneService::ToPosixTime(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - IPC::RequestParser rp{ctx}; - const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()}; - TimeZone::TimeZoneRule time_zone_rule{}; - std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule)); - - s64 posix_time{}; - if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime( - time_zone_rule, calendar_time, posix_time)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - ctx.WriteBuffer(posix_time); - - // TODO(bunnei): Handle multiple times - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw<u32>(1); // Number of times we're returning -} - -void ITimeZoneService::ToPosixTimeWithMyRule(HLERequestContext& ctx) { - LOG_DEBUG(Service_Time, "called"); - - IPC::RequestParser rp{ctx}; - const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()}; - - s64 posix_time{}; - if (const Result result{time_zone_content_manager.GetTimeZoneManager().ToPosixTimeWithMyRule( - calendar_time, posix_time)}; - result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - return; - } - - ctx.WriteBuffer(posix_time); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw<u32>(1); // Number of times we're returning -} - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h deleted file mode 100644 index 952fcb0e2..000000000 --- a/src/core/hle/service/time/time_zone_service.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/service/service.h" - -namespace Core { -class System; -} - -namespace Service::Time { - -namespace TimeZone { -class TimeZoneContentManager; -} - -class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { -public: - explicit ITimeZoneService(Core::System& system_, - TimeZone::TimeZoneContentManager& time_zone_manager_); - -private: - void GetDeviceLocationName(HLERequestContext& ctx); - void GetTotalLocationNameCount(HLERequestContext& ctx); - void LoadLocationNameList(HLERequestContext& ctx); - void GetTimeZoneRuleVersion(HLERequestContext& ctx); - void LoadTimeZoneRule(HLERequestContext& ctx); - void ToCalendarTime(HLERequestContext& ctx); - void ToCalendarTimeWithMyRule(HLERequestContext& ctx); - void ToPosixTime(HLERequestContext& ctx); - void ToPosixTimeWithMyRule(HLERequestContext& ctx); - -private: - TimeZone::TimeZoneContentManager& time_zone_content_manager; -}; - -} // namespace Service::Time diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h deleted file mode 100644 index eb4fb52d1..000000000 --- a/src/core/hle/service/time/time_zone_types.h +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/swap.h" - -namespace Service::Time::TimeZone { - -using LocationName = std::array<char, 0x24>; - -/// https://switchbrew.org/wiki/Glue_services#ttinfo -struct TimeTypeInfo { - s32 gmt_offset{}; - u8 is_dst{}; - INSERT_PADDING_BYTES(3); - s32 abbreviation_list_index{}; - u8 is_standard_time_daylight{}; - u8 is_gmt{}; - INSERT_PADDING_BYTES(2); -}; -static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size"); - -/// https://switchbrew.org/wiki/Glue_services#TimeZoneRule -struct TimeZoneRule { - s32 time_count{}; - s32 type_count{}; - s32 char_count{}; - u8 go_back{}; - u8 go_ahead{}; - INSERT_PADDING_BYTES(2); - std::array<s64, 1000> ats{}; - std::array<s8, 1000> types{}; - std::array<TimeTypeInfo, 128> ttis{}; - std::array<char, 512> chars{}; - s32 default_type{}; - INSERT_PADDING_BYTES(0x12C4); -}; -static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size"); - -/// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo -struct CalendarAdditionalInfo { - u32 day_of_week; - u32 day_of_year; - std::array<char, 8> timezone_name; - u32 is_dst; - s32 gmt_offset; -}; -static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); - -/// https://switchbrew.org/wiki/Glue_services#CalendarTime -struct CalendarTime { - s16 year; - s8 month; - s8 day; - s8 hour; - s8 minute; - s8 second; - INSERT_PADDING_BYTES_NOINIT(1); -}; -static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); - -struct CalendarInfo { - CalendarTime time; - CalendarAdditionalInfo additional_info; -}; -static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size"); - -struct TzifHeader { - u32_be magic{}; - u8 version{}; - INSERT_PADDING_BYTES(15); - s32_be ttis_gmt_count{}; - s32_be ttis_std_count{}; - s32_be leap_count{}; - s32_be time_count{}; - s32_be type_count{}; - s32_be char_count{}; -}; -static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size"); - -} // namespace Service::Time::TimeZone diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 71ce9be50..725311c53 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -71,18 +71,7 @@ size_t Display::GetNumLayers() const { return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); } -Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) { - if (got_vsync_event) { - return ResultPermissionDenied; - } - - got_vsync_event = true; - - *out_vsync_event = GetVSyncEventUnchecked(); - return ResultSuccess; -} - -Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() { +Kernel::KReadableEvent* Display::GetVSyncEvent() { return &vsync_event->GetReadableEvent(); } @@ -102,6 +91,10 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id, layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer, std::move(buffer_item_consumer))); + if (is_abandoned) { + this->FindLayer(layer_id)->GetConsumer().Abandon(); + } + hos_binder_driver_server.RegisterProducer(std::move(producer)); } @@ -114,6 +107,13 @@ void Display::DestroyLayer(u64 layer_id) { [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); } +void Display::Abandon() { + for (auto& layer : layers) { + layer->GetConsumer().Abandon(); + } + is_abandoned = true; +} + Layer* Display::FindLayer(u64 layer_id) { const auto itr = std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 1d9360b96..8eb8a5155 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -74,16 +74,8 @@ public: std::size_t GetNumLayers() const; - /** - * Gets the internal vsync event. - * - * @returns The internal Vsync event if it has not yet been retrieved, - * VI::ResultPermissionDenied otherwise. - */ - [[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event); - /// Gets the internal vsync event. - Kernel::KReadableEvent* GetVSyncEventUnchecked(); + Kernel::KReadableEvent* GetVSyncEvent(); /// Signals the internal vsync event. void SignalVSyncEvent(); @@ -104,9 +96,10 @@ public: /// Resets the display for a new connection. void Reset() { layers.clear(); - got_vsync_event = false; } + void Abandon(); + /// Attempts to find a layer with the given ID. /// /// @param layer_id The layer ID. @@ -133,7 +126,7 @@ private: std::vector<std::unique_ptr<Layer>> layers; Kernel::KEvent* vsync_event{}; - bool got_vsync_event{false}; + bool is_abandoned{}; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index 295005e23..f95e2dc71 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -4,6 +4,7 @@ #pragma once #include <memory> +#include <utility> #include "common/common_types.h" @@ -75,12 +76,12 @@ public: return open; } - void Close() { - open = false; + bool Close() { + return std::exchange(open, false); } - void Open() { - open = true; + bool Open() { + return !std::exchange(open, true); } private: diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 9ab8788e3..1f3d82c57 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -15,6 +15,7 @@ #include "common/logging/log.h" #include "common/math_util.h" #include "common/settings.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core_timing.h" #include "core/hle/kernel/k_readable_event.h" @@ -343,8 +344,8 @@ private: class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { public: - explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_) - : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} { + explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} { // clang-format off static const FunctionInfo functions[] = { {200, nullptr, "AllocateProcessHeapBlock"}, @@ -440,7 +441,7 @@ private: IPC::RequestParser rp{ctx}; const u64 display = rp.Pop<u64>(); - const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; + const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(rc); @@ -457,7 +458,7 @@ private: "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", unknown, display, aruid); - const auto layer_id = nv_flinger.CreateLayer(display); + const auto layer_id = nvnflinger.CreateLayer(display); if (!layer_id) { LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); IPC::ResponseBuilder rb{ctx, 2}; @@ -494,14 +495,14 @@ private: rb.Push(ResultSuccess); } - Nvnflinger::Nvnflinger& nv_flinger; + Nvnflinger::Nvnflinger& nvnflinger; }; class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { public: - IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_, + IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) - : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_}, + : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_}, hos_binder_driver_server{hos_binder_driver_server_} { static const FunctionInfo functions[] = { @@ -564,7 +565,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger); + rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger); } void GetManagerDisplayService(HLERequestContext& ctx) { @@ -572,7 +573,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger); + rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger); } void GetIndirectDisplayTransactionService(HLERequestContext& ctx) { @@ -607,7 +608,7 @@ private: ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); - const auto display_id = nv_flinger.OpenDisplay(name); + const auto display_id = nvnflinger.OpenDisplay(name); if (!display_id) { LOG_ERROR(Service_VI, "Display not found! display_name={}", name); IPC::ResponseBuilder rb{ctx, 2}; @@ -624,7 +625,7 @@ private: IPC::RequestParser rp{ctx}; const u64 display_id = rp.Pop<u64>(); - const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; + const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(rc); @@ -694,16 +695,14 @@ private: void OpenLayer(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); - const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); - - const std::string display_name(name_buf.begin(), end); + const std::string display_name(Common::StringFromBuffer(name_buf)); const u64 layer_id = rp.Pop<u64>(); const u64 aruid = rp.Pop<u64>(); LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); - const auto display_id = nv_flinger.OpenDisplay(display_name); + const auto display_id = nvnflinger.OpenDisplay(display_name); if (!display_id) { LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -711,7 +710,7 @@ private: return; } - const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); + const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -719,7 +718,12 @@ private: return; } - nv_flinger.OpenLayer(layer_id); + if (!nvnflinger.OpenLayer(layer_id)) { + LOG_WARNING(Service_VI, "Tried to open layer which was already open"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultOperationFailed); + return; + } android::OutputParcel parcel; parcel.WriteInterface(NativeWindow{*buffer_queue_id}); @@ -737,7 +741,12 @@ private: LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); - nv_flinger.CloseLayer(layer_id); + if (!nvnflinger.CloseLayer(layer_id)) { + LOG_WARNING(Service_VI, "Tried to close layer which was not open"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultOperationFailed); + return; + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -753,7 +762,7 @@ private: // TODO(Subv): What's the difference between a Stray and a Managed layer? - const auto layer_id = nv_flinger.CreateLayer(display_id); + const auto layer_id = nvnflinger.CreateLayer(display_id); if (!layer_id) { LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -761,7 +770,7 @@ private: return; } - const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); + const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -785,7 +794,7 @@ private: const u64 layer_id = rp.Pop<u64>(); LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); - nv_flinger.DestroyLayer(layer_id); + nvnflinger.DestroyLayer(layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -798,7 +807,7 @@ private: LOG_DEBUG(Service_VI, "called. display_id={}", display_id); Kernel::KReadableEvent* vsync_event{}; - const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id); + const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id); if (result != ResultSuccess) { if (result == ResultNotFound) { LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); @@ -808,6 +817,12 @@ private: rb.Push(result); return; } + if (vsync_event_fetched) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(VI::ResultPermissionDenied); + return; + } + vsync_event_fetched = true; IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); @@ -899,8 +914,9 @@ private: } } - Nvnflinger::Nvnflinger& nv_flinger; + Nvnflinger::Nvnflinger& nvnflinger; Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; + bool vsync_event_fetched{false}; }; static bool IsValidServiceAccess(Permission permission, Policy policy) { @@ -916,7 +932,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { } void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, - Nvnflinger::Nvnflinger& nv_flinger, + Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission) { IPC::RequestParser rp{ctx}; @@ -931,19 +947,19 @@ void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server); + rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server); } -void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, +void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { auto server_manager = std::make_unique<ServerManager>(system); server_manager->RegisterNamedService( - "vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)); + "vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server)); server_manager->RegisterNamedService( - "vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)); + "vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server)); server_manager->RegisterNamedService( - "vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)); + "vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index a35b62f97..ee4bcbcfa 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -48,7 +48,7 @@ void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, Permission permission); } // namespace detail -void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, +void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); } // namespace Service::VI |