diff options
Diffstat (limited to 'src/core/hle')
23 files changed, 550 insertions, 89 deletions
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index bf7f875b6..8839ce482 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -194,6 +194,16 @@ template<ResultCode func(Handle, u32)> void Wrap() { FuncReturn(func(PARAM(0), PARAM(1)).raw); } +template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() { + Handle param_1 = 0; + Handle param_2 = 0; + u32 retval = func(¶m_1, ¶m_2, reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3)).raw; + // The first out parameter is moved into R2 and the second is moved into R1. + Core::g_app_core->SetReg(1, param_2); + Core::g_app_core->SetReg(2, param_1); + FuncReturn(retval); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// // Function wrappers that return type u32 diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp new file mode 100644 index 000000000..444ce8d45 --- /dev/null +++ b/src/core/hle/kernel/client_port.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" + +namespace Kernel { + +ClientPort::ClientPort() {} +ClientPort::~ClientPort() {} + +} // namespace diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h new file mode 100644 index 000000000..480b6ddae --- /dev/null +++ b/src/core/hle/kernel/client_port.h @@ -0,0 +1,36 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ServerPort; + +class ClientPort : public Object { +public: + friend class ServerPort; + std::string GetTypeName() const override { return "ClientPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ClientPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. + u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have + u32 active_sessions; ///< Number of currently open sessions to this port + std::string name; ///< Name of client port (optional) + +protected: + ClientPort(); + ~ClientPort() override; +}; + +} // namespace diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4d4276f7a..27ba3f912 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -35,7 +35,7 @@ enum KernelHandle : Handle { enum class HandleType : u32 { Unknown = 0, - Port = 1, + Session = 2, Event = 3, Mutex = 4, @@ -48,6 +48,8 @@ enum class HandleType : u32 { Timer = 11, ResourceLimit = 12, CodeSet = 13, + ClientPort = 14, + ServerPort = 15, }; enum { @@ -72,6 +74,7 @@ public: bool IsWaitable() const { switch (GetHandleType()) { case HandleType::Session: + case HandleType::ServerPort: case HandleType::Event: case HandleType::Mutex: case HandleType::Thread: @@ -80,13 +83,13 @@ public: return true; case HandleType::Unknown: - case HandleType::Port: case HandleType::SharedMemory: case HandleType::Redirection: case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: case HandleType::CodeSet: + case HandleType::ClientPort: return false; } } diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp new file mode 100644 index 000000000..fcc684a20 --- /dev/null +++ b/src/core/hle/kernel/server_port.cpp @@ -0,0 +1,41 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> + +#include "common/assert.h" + +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/server_port.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +ServerPort::ServerPort() {} +ServerPort::~ServerPort() {} + +bool ServerPort::ShouldWait() { + // If there are no pending sessions, we wait until a new one is added. + return pending_sessions.size() == 0; +} + +void ServerPort::Acquire() { + ASSERT_MSG(!ShouldWait(), "object unavailable!"); +} + +std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(u32 max_sessions, std::string name) { + SharedPtr<ServerPort> server_port(new ServerPort); + SharedPtr<ClientPort> client_port(new ClientPort); + + server_port->name = name + "_Server"; + client_port->name = name + "_Client"; + client_port->server_port = server_port; + client_port->max_sessions = max_sessions; + client_port->active_sessions = 0; + + return std::make_tuple(std::move(server_port), std::move(client_port)); +} + +} // namespace diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h new file mode 100644 index 000000000..e9c972ce6 --- /dev/null +++ b/src/core/hle/kernel/server_port.h @@ -0,0 +1,46 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> +#include <tuple> + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +namespace Kernel { + +class ClientPort; + +class ServerPort final : public WaitObject { +public: + /** + * Creates a pair of ServerPort and an associated ClientPort. + * @param max_sessions Maximum number of sessions to the port + * @param name Optional name of the ports + * @return The created port tuple + */ + static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort"); + + std::string GetTypeName() const override { return "ServerPort"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::ServerPort; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + std::string name; ///< Name of port (optional) + + std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port + + bool ShouldWait() override; + void Acquire() override; + +private: + ServerPort(); + ~ServerPort() override; +}; + +} // namespace diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 6ddaf970e..26b086f87 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h @@ -32,6 +32,10 @@ constexpr u32 CallingPidDesc() { return 0x20; } +constexpr u32 TransferHandleDesc() { + return 0x20; +} + constexpr u32 StaticBufferDesc(u32 size, unsigned int buffer_id) { return 0x2 | (size << 14) | ((buffer_id & 0xF) << 10); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index db2728a7b..9dea995f4 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -182,6 +182,48 @@ static void PriorityBoostStarvedThreads() { } /** + * Gets the registers for timeout parameter of the next WaitSynchronization call. + * @param thread a pointer to the thread that is ready to call WaitSynchronization + * @returns a tuple of two register pointers to low and high part of the timeout parameter + */ +static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) { + bool thumb_mode = (thread->context.cpsr & TBIT) != 0; + u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE); + u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF; + + if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { + // svc #0x24 (WaitSynchronization1) + return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]); + } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { + // svc #0x25 (WaitSynchronizationN) + return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]); + } + + UNREACHABLE(); +} + +/** + * Updates the WaitSynchronization timeout paramter according to the difference + * between ticks of the last WaitSynchronization call and the incoming one. + * @param timeout_low a pointer to the register for the low part of the timeout parameter + * @param timeout_high a pointer to the register for the high part of the timeout parameter + * @param last_tick tick of the last WaitSynchronization call + */ +static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) { + s64 timeout = ((s64)*timeout_high << 32) | *timeout_low; + + if (timeout != -1) { + timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds + + if (timeout < 0) + timeout = 0; + + *timeout_low = timeout & 0xFFFFFFFF; + *timeout_high = timeout >> 32; + } +} + +/** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to */ @@ -219,6 +261,13 @@ static void SwitchContext(Thread* new_thread) { // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM new_thread->context.pc -= thumb_mode ? 2 : 4; + + // Get the register for timeout parameter + u32* timeout_low, *timeout_high; + std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); + + // Update the timeout parameter + UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks); } // Clean up the thread's wait_objects, they'll be restored if needed during diff --git a/src/core/hle/result.h b/src/core/hle/result.h index bfb3327ce..57dedcb22 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -26,6 +26,7 @@ enum class ErrorDescription : u32 { FS_NotAFile = 250, FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage + GPU_FirstInitialization = 519, FS_InvalidPath = 702, InvalidSection = 1000, TooLarge = 1001, diff --git a/src/core/hle/service/dlp/dlp.cpp b/src/core/hle/service/dlp/dlp.cpp new file mode 100644 index 000000000..7c8db794b --- /dev/null +++ b/src/core/hle/service/dlp/dlp.cpp @@ -0,0 +1,24 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/dlp/dlp.h" +#include "core/hle/service/dlp/dlp_clnt.h" +#include "core/hle/service/dlp/dlp_fkcl.h" +#include "core/hle/service/dlp/dlp_srvr.h" + +namespace Service { +namespace DLP { + +void Init() { + AddService(new DLP_CLNT_Interface); + AddService(new DLP_FKCL_Interface); + AddService(new DLP_SRVR_Interface); +} + +void Shutdown() { +} + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h new file mode 100644 index 000000000..ec2fe46e8 --- /dev/null +++ b/src/core/hle/service/dlp/dlp.h @@ -0,0 +1,15 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +namespace Service { +namespace DLP { + +/// Initializes the DLP services. +void Init(); + +/// Shuts down the DLP services. +void Shutdown(); + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp new file mode 100644 index 000000000..0b31d47df --- /dev/null +++ b/src/core/hle/service/dlp/dlp_clnt.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/dlp/dlp_clnt.h" + +namespace Service { +namespace DLP { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C3, nullptr, "Initialize"}, + {0x00110000, nullptr, "GetWirelessRebootPassphrase"}, +}; + +DLP_CLNT_Interface::DLP_CLNT_Interface() { + Register(FunctionTable); +} + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h new file mode 100644 index 000000000..067f11e37 --- /dev/null +++ b/src/core/hle/service/dlp/dlp_clnt.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace DLP { + +class DLP_CLNT_Interface final : public Interface { +public: + DLP_CLNT_Interface(); + + std::string GetPortName() const override { + return "dlp:CLNT"; + } +}; + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp new file mode 100644 index 000000000..a845260e5 --- /dev/null +++ b/src/core/hle/service/dlp/dlp_fkcl.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/dlp/dlp_fkcl.h" + +namespace Service { +namespace DLP { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010083, nullptr, "Initialize"}, + {0x000F0000, nullptr, "GetWirelessRebootPassphrase"}, +}; + +DLP_FKCL_Interface::DLP_FKCL_Interface() { + Register(FunctionTable); +} + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h new file mode 100644 index 000000000..e4837a167 --- /dev/null +++ b/src/core/hle/service/dlp/dlp_fkcl.h @@ -0,0 +1,22 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace DLP { + +class DLP_FKCL_Interface final : public Interface { +public: + DLP_FKCL_Interface(); + + std::string GetPortName() const override { + return "dlp:FKCL"; + } +}; + +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp index 1f30188da..da9b30f56 100644 --- a/src/core/hle/service/dlp_srvr.cpp +++ b/src/core/hle/service/dlp/dlp_srvr.cpp @@ -2,16 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/common_types.h" #include "common/logging/log.h" -#include "core/hle/hle.h" -#include "core/hle/service/dlp_srvr.h" +#include "core/hle/result.h" +#include "core/hle/service/dlp/dlp_srvr.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace DLP_SRVR +namespace Service { +namespace DLP { -namespace DLP_SRVR { - -static void unk_0x000E0040(Service::Interface* self) { +static void unk_0x000E0040(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; @@ -23,14 +22,13 @@ static void unk_0x000E0040(Service::Interface* self) { const Interface::FunctionInfo FunctionTable[] = { {0x00010183, nullptr, "Initialize"}, {0x00020000, nullptr, "Finalize"}, + {0x000800C0, nullptr, "SendWirelessRebootPassphrase"}, {0x000E0040, unk_0x000E0040, "unk_0x000E0040"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +DLP_SRVR_Interface::DLP_SRVR_Interface() { Register(FunctionTable); } -} // namespace +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h index d65d00814..19fe17840 100644 --- a/src/core/hle/service/dlp_srvr.h +++ b/src/core/hle/service/dlp/dlp_srvr.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace DLP_SRVR +namespace Service { +namespace DLP { -namespace DLP_SRVR { - -class Interface : public Service::Interface { +class DLP_SRVR_Interface final : public Interface { public: - Interface(); + DLP_SRVR_Interface(); std::string GetPortName() const override { return "dlp:SRVR"; } }; -} // namespace +} // namespace DLP +} // namespace Service diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index f3c7b7df3..ec565f46d 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -44,7 +44,7 @@ Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory; u32 g_thread_id = 0; static bool gpu_right_acquired = false; - +static bool first_initialization = true; /// Gets a pointer to a thread command buffer in GSP shared memory static inline u8* GetCommandBuffer(u32 thread_id) { return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); @@ -347,24 +347,25 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { u32 flags = cmd_buff[1]; g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]); + // TODO(mailwl): return right error code instead assert ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!"); g_interrupt_event->name = "GSP_GPU::interrupt_event"; - using Kernel::MemoryPermission; - g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, - MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, - 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); - - Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); - - // This specific code is required for a successful initialization, rather than 0 - cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX, - ErrorSummary::Success, ErrorLevel::Success).raw; + if (first_initialization) { + // This specific code is required for a successful initialization, rather than 0 + first_initialization = false; + cmd_buff[1] = ResultCode(ErrorDescription::GPU_FirstInitialization, ErrorModule::GX, + ErrorSummary::Success, ErrorLevel::Success).raw; + } else { + cmd_buff[1] = RESULT_SUCCESS.raw; + } cmd_buff[2] = g_thread_id++; // Thread ID - cmd_buff[4] = shmem_handle; // GSP shared memory + cmd_buff[4] = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); // GSP shared memory g_interrupt_event->Signal(); // TODO(bunnei): Is this correct? + + LOG_WARNING(Service_GSP, "called, flags=0x%08X", flags); } /** @@ -375,12 +376,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) { static void UnregisterInterruptRelayQueue(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - g_shared_memory = nullptr; + g_thread_id = 0; g_interrupt_event = nullptr; cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_GSP, "called"); + LOG_WARNING(Service_GSP, "(STUBBED) called"); } /** @@ -718,10 +719,15 @@ Interface::Interface() { Register(FunctionTable); g_interrupt_event = nullptr; - g_shared_memory = nullptr; + + using Kernel::MemoryPermission; + g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, + MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, + 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); g_thread_id = 0; gpu_right_acquired = false; + first_initialization = true; } Interface::~Interface() { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index d216cecb4..cdec11388 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cmath> + #include "common/logging/log.h" #include "common/emu_window.h" @@ -19,8 +21,6 @@ namespace Service { namespace HID { -static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position - // Handle to shared memory region designated to HID_User service static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem; @@ -39,38 +39,48 @@ static u32 next_gyroscope_index; static int enable_accelerometer_count = 0; // positive means enabled static int enable_gyroscope_count = 0; // positive means enabled -const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {{ - Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y, - Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR, - Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE, - Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT, - Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT, - Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT -}}; - - -// TODO(peachum): -// Add a method for setting analog input from joystick device for the circle Pad. -// -// This method should: -// * Be called after both PadButton<Press, Release>(). -// * Be called before PadUpdateComplete() -// * Set current PadEntry.circle_pad_<axis> using analog data -// * Set PadData.raw_circle_pad_data -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 -// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 -// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 -// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 +static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { + constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions + constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction + PadState state; + state.hex = 0; + + if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) { + float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x); + + if (circle_pad_x != 0 && t < TAN60) { + if (circle_pad_x > 0) + state.circle_right.Assign(1); + else + state.circle_left.Assign(1); + } + + if (circle_pad_x == 0 || t > TAN30) { + if (circle_pad_y > 0) + state.circle_up.Assign(1); + else + state.circle_down.Assign(1); + } + } + + return state; +} void Update() { SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer()); - const PadState state = VideoCore::g_emu_window->GetPadState(); if (mem == nullptr) { LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); return; } + PadState state = VideoCore::g_emu_window->GetPadState(); + + // Get current circle pad position and update circle pad direction + s16 circle_pad_x, circle_pad_y; + std::tie(circle_pad_x, circle_pad_y) = VideoCore::g_emu_window->GetCirclePadState(); + state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; + mem->pad.current_state.hex = state.hex; mem->pad.index = next_pad_index; next_pad_index = (next_pad_index + 1) % mem->pad.entries.size(); @@ -88,13 +98,9 @@ void Update() { // Update entry properties pad_entry.current_state.hex = state.hex; pad_entry.delta_additions.hex = changed.hex & state.hex; - pad_entry.delta_removals.hex = changed.hex & old_state.hex;; - - // Set circle Pad - pad_entry.circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS : - state.circle_right ? MAX_CIRCLEPAD_POS : 0x0; - pad_entry.circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS : - state.circle_up ? MAX_CIRCLEPAD_POS : 0x0; + pad_entry.delta_removals.hex = changed.hex & old_state.hex; + pad_entry.circle_pad_x = circle_pad_x; + pad_entry.circle_pad_y = circle_pad_y; // If we just updated index 0, provide a new timestamp if (mem->pad.index == 0) { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 170d19ea8..669b1f723 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -215,9 +215,6 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; const PadState PAD_CIRCLE_UP = {{1u << 30}}; const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; - -extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping; - /** * HID::GetIPCHandles service function * Inputs: diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index d7e7d4fe3..395880843 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -10,7 +10,6 @@ #include "core/hle/service/act_a.h" #include "core/hle/service/act_u.h" #include "core/hle/service/csnd_snd.h" -#include "core/hle/service/dlp_srvr.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" #include "core/hle/service/gsp_gpu.h" @@ -31,6 +30,7 @@ #include "core/hle/service/boss/boss.h" #include "core/hle/service/cam/cam.h" #include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/dlp/dlp.h" #include "core/hle/service/frd/frd.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/cfg/cfg.h" @@ -111,6 +111,7 @@ void Init() { Service::CAM::Init(); Service::CECD::Init(); Service::CFG::Init(); + Service::DLP::Init(); Service::FRD::Init(); Service::HID::Init(); Service::IR::Init(); @@ -123,7 +124,6 @@ void Init() { AddService(new ACT_A::Interface); AddService(new ACT_U::Interface); AddService(new CSND_SND::Interface); - AddService(new DLP_SRVR::Interface); AddService(new DSP_DSP::Interface); AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); @@ -150,6 +150,7 @@ void Shutdown() { Service::IR::Shutdown(); Service::HID::Shutdown(); Service::FRD::Shutdown(); + Service::DLP::Shutdown(); Service::CFG::Shutdown(); Service::CECD::Shutdown(); Service::CAM::Shutdown(); diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index aae955bf8..8bd36d5ea 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2016 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -15,23 +15,64 @@ namespace SRV { static Kernel::SharedPtr<Kernel::Event> event_handle; -static void Initialize(Service::Interface* self) { +/** + * SRV::RegisterClient service function + * Inputs: + * 0: 0x00010002 + * 1: ProcessId Header (must be 0x20) + * Outputs: + * 0: 0x00010040 + * 1: ResultCode + */ +static void RegisterClient(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = 0; // No error + if (cmd_buff[1] != IPC::CallingPidDesc()) { + cmd_buff[0] = IPC::MakeHeader(0x0, 0x1, 0); //0x40 + cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, + ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; + return; + } + cmd_buff[0] = IPC::MakeHeader(0x1, 0x1, 0); //0x10040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called"); } -static void GetProcSemaphore(Service::Interface* self) { +/** + * SRV::EnableNotification service function + * Inputs: + * 0: 0x00020000 + * Outputs: + * 0: 0x00020042 + * 1: ResultCode + * 2: Translation descriptor: 0x20 + * 3: Handle to semaphore signaled on process notification + */ +static void EnableNotification(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); // TODO(bunnei): Change to a semaphore once these have been implemented event_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "SRV:Event"); event_handle->Clear(); - cmd_buff[1] = 0; // No error + cmd_buff[0] = IPC::MakeHeader(0x2, 0x1, 0x2); // 0x20042 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = IPC::TransferHandleDesc(); cmd_buff[3] = Kernel::g_handle_table.Create(event_handle).MoveFrom(); + LOG_WARNING(Service_SRV, "(STUBBED) called"); } +/** + * SRV::GetServiceHandle service function + * Inputs: + * 0: 0x00050100 + * 1-2: 8-byte UTF-8 service name + * 3: Name length + * 4: Flags (bit0: if not set, return port-handle if session-handle unavailable) + * Outputs: + * 1: ResultCode + * 3: Service handle + */ static void GetServiceHandle(Service::Interface* self) { ResultCode res = RESULT_SUCCESS; u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -49,16 +90,80 @@ static void GetServiceHandle(Service::Interface* self) { cmd_buff[1] = res.raw; } +/** + * SRV::Subscribe service function + * Inputs: + * 0: 0x00090040 + * 1: Notification ID + * Outputs: + * 0: 0x00090040 + * 1: ResultCode + */ +static void Subscribe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0x9, 0x1, 0); // 0x90040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::Unsubscribe service function + * Inputs: + * 0: 0x000A0040 + * 1: Notification ID + * Outputs: + * 0: 0x000A0040 + * 1: ResultCode + */ +static void Unsubscribe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + + cmd_buff[0] = IPC::MakeHeader(0xA, 0x1, 0); // 0xA0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X", notification_id); +} + +/** + * SRV::PublishToSubscriber service function + * Inputs: + * 0: 0x000C0080 + * 1: Notification ID + * 2: Flags (bit0: only fire if not fired, bit1: report errors) + * Outputs: + * 0: 0x000C0040 + * 1: ResultCode + */ +static void PublishToSubscriber(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 notification_id = cmd_buff[1]; + u8 flags = cmd_buff[2] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0xC, 0x1, 0); // 0xC0040 + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + LOG_WARNING(Service_SRV, "(STUBBED) called, notification_id=0x%X, flags=%u", notification_id, flags); +} + const Interface::FunctionInfo FunctionTable[] = { - {0x00010002, Initialize, "Initialize"}, - {0x00020000, GetProcSemaphore, "GetProcSemaphore"}, - {0x00030100, nullptr, "RegisterService"}, - {0x000400C0, nullptr, "UnregisterService"}, - {0x00050100, GetServiceHandle, "GetServiceHandle"}, - {0x000600C2, nullptr, "RegisterHandle"}, - {0x00090040, nullptr, "Subscribe"}, - {0x000B0000, nullptr, "ReceiveNotification"}, - {0x000C0080, nullptr, "PublishToSubscriber"}, + {0x00010002, RegisterClient, "RegisterClient"}, + {0x00020000, EnableNotification, "EnableNotification"}, + {0x00030100, nullptr, "RegisterService"}, + {0x000400C0, nullptr, "UnregisterService"}, + {0x00050100, GetServiceHandle, "GetServiceHandle"}, + {0x000600C2, nullptr, "RegisterPort"}, + {0x000700C0, nullptr, "UnregisterPort"}, + {0x00080100, nullptr, "GetPort"}, + {0x00090040, Subscribe, "Subscribe"}, + {0x000A0040, Unsubscribe, "Unsubscribe"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, PublishToSubscriber, "PublishToSubscriber"}, + {0x000D0040, nullptr, "PublishAndGetSubscriber"}, + {0x000E00C0, nullptr, "IsServiceRegistered"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -66,10 +171,11 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable); + event_handle = nullptr; } Interface::~Interface() { event_handle = nullptr; } -} // namespace +} // namespace SRV diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 0ce72de87..5d71d5619 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -14,12 +14,14 @@ #include "core/arm/arm_interface.h" #include "core/hle/kernel/address_arbiter.h" +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/semaphore.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/timer.h" @@ -834,6 +836,23 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 return RESULT_SUCCESS; } +static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name, u32 max_sessions) { + // TODO(Subv): Implement named ports. + ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented"); + + using Kernel::ServerPort; + using Kernel::ClientPort; + using Kernel::SharedPtr; + + auto ports = ServerPort::CreatePortPair(max_sessions); + CASCADE_RESULT(*client_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ClientPort>>(ports)))); + // Note: The 3DS kernel also leaks the client port handle if the server port handle fails to be created. + CASCADE_RESULT(*server_port, Kernel::g_handle_table.Create(std::move(std::get<SharedPtr<ServerPort>>(ports)))); + + LOG_TRACE(Kernel_SVC, "called max_sessions=%u", max_sessions); + return RESULT_SUCCESS; +} + static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { using Kernel::MemoryRegion; @@ -1011,7 +1030,7 @@ static const FunctionDef SVC_Table[] = { {0x44, nullptr, "Unknown"}, {0x45, nullptr, "Unknown"}, {0x46, nullptr, "Unknown"}, - {0x47, nullptr, "CreatePort"}, + {0x47, HLE::Wrap<CreatePort>, "CreatePort"}, {0x48, nullptr, "CreateSessionToPort"}, {0x49, nullptr, "CreateSession"}, {0x4A, nullptr, "AcceptSession"}, |