diff options
Diffstat (limited to 'src/core/hle/service')
-rw-r--r-- | src/core/hle/service/apt/apt.cpp | 517 | ||||
-rw-r--r-- | src/core/hle/service/apt/apt.h | 10 | ||||
-rw-r--r-- | src/core/hle/service/apt/bcfnt/bcfnt.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/boss/boss_p.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/cfg/cfg.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/dlp/dlp_clnt.cpp | 21 | ||||
-rw-r--r-- | src/core/hle/service/dlp/dlp_fkcl.cpp | 18 | ||||
-rw-r--r-- | src/core/hle/service/dlp/dlp_srvr.cpp | 9 | ||||
-rw-r--r-- | src/core/hle/service/dsp_dsp.cpp | 7 | ||||
-rw-r--r-- | src/core/hle/service/frd/frd.cpp | 43 | ||||
-rw-r--r-- | src/core/hle/service/frd/frd.h | 13 | ||||
-rw-r--r-- | src/core/hle/service/frd/frd_u.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/gsp_gpu.cpp | 11 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.cpp | 44 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/ir/ir_rst.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/service/y2r_u.cpp | 4 |
17 files changed, 598 insertions, 116 deletions
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 25e7b777d..58d94768c 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -2,15 +2,18 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <boost/optional.hpp> #include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/file_sys/file_backend.h" #include "core/hle/applets/applet.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/romfs.h" #include "core/hle/service/apt/apt.h" #include "core/hle/service/apt/apt_a.h" #include "core/hle/service/apt/apt_s.h" @@ -27,11 +30,10 @@ namespace APT { /// Handle to shared memory region designated to for shared system font static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem; +static bool shared_font_loaded = false; static bool shared_font_relocated = false; static Kernel::SharedPtr<Kernel::Mutex> lock; -static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event -static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event static u32 cpu_percent; ///< CPU time available to the running application @@ -40,38 +42,170 @@ static u8 unknown_ns_state_field; static ScreencapPostPermission screen_capture_post_permission; -/// Parameter data to be returned in the next call to Glance/ReceiveParameter -static MessageParameter next_parameter; +/// Parameter data to be returned in the next call to Glance/ReceiveParameter. +/// TODO(Subv): Use std::optional once we migrate to C++17. +static boost::optional<MessageParameter> next_parameter; + +enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 }; + +static constexpr size_t NumAppletSlot = 4; + +enum class AppletSlot : u8 { + Application, + SystemApplet, + HomeMenu, + LibraryApplet, + + // An invalid tag + Error, +}; + +union AppletAttributes { + u32 raw; + + BitField<0, 3, u32> applet_pos; + + AppletAttributes() : raw(0) {} + AppletAttributes(u32 attributes) : raw(attributes) {} +}; + +struct AppletSlotData { + AppletId applet_id; + AppletSlot slot; + bool registered; + AppletAttributes attributes; + Kernel::SharedPtr<Kernel::Event> notification_event; + Kernel::SharedPtr<Kernel::Event> parameter_event; +}; + +// Holds data about the concurrently running applets in the system. +static std::array<AppletSlotData, NumAppletSlot> applet_slots = {}; + +// This overload returns nullptr if no applet with the specified id has been started. +static AppletSlotData* GetAppletSlotData(AppletId id) { + auto GetSlot = [](AppletSlot slot) -> AppletSlotData* { + return &applet_slots[static_cast<size_t>(slot)]; + }; + + if (id == AppletId::Application) { + auto* slot = GetSlot(AppletSlot::Application); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + if (id == AppletId::AnySystemApplet) { + auto* system_slot = GetSlot(AppletSlot::SystemApplet); + if (system_slot->applet_id != AppletId::None) + return system_slot; + + // The Home Menu is also a system applet, but it lives in its own slot to be able to run + // concurrently with other system applets. + auto* home_slot = GetSlot(AppletSlot::HomeMenu); + if (home_slot->applet_id != AppletId::None) + return home_slot; + + return nullptr; + } + + if (id == AppletId::AnyLibraryApplet || id == AppletId::AnySysLibraryApplet) { + auto* slot = GetSlot(AppletSlot::LibraryApplet); + if (slot->applet_id == AppletId::None) + return nullptr; + + u32 applet_pos = slot->attributes.applet_pos; + + if (id == AppletId::AnyLibraryApplet && applet_pos == static_cast<u32>(AppletPos::Library)) + return slot; + + if (id == AppletId::AnySysLibraryApplet && + applet_pos == static_cast<u32>(AppletPos::SysLibrary)) + return slot; + + return nullptr; + } + + if (id == AppletId::HomeMenu || id == AppletId::AlternateMenu) { + auto* slot = GetSlot(AppletSlot::HomeMenu); + if (slot->applet_id != AppletId::None) + return slot; + + return nullptr; + } + + for (auto& slot : applet_slots) { + if (slot.applet_id == id) + return &slot; + } + + return nullptr; +} + +static AppletSlotData* GetAppletSlotData(AppletAttributes attributes) { + // Mapping from AppletPos to AppletSlot + static constexpr std::array<AppletSlot, 6> applet_position_slots = { + AppletSlot::Application, AppletSlot::LibraryApplet, AppletSlot::SystemApplet, + AppletSlot::LibraryApplet, AppletSlot::Error, AppletSlot::LibraryApplet}; + + u32 applet_pos = attributes.applet_pos; + if (applet_pos >= applet_position_slots.size()) + return nullptr; + + AppletSlot slot = applet_position_slots[applet_pos]; + + if (slot == AppletSlot::Error) + return nullptr; + + return &applet_slots[static_cast<size_t>(slot)]; +} void SendParameter(const MessageParameter& parameter) { next_parameter = parameter; - // Signal the event to let the application know that a new parameter is ready to be read - parameter_event->Signal(); + // Signal the event to let the receiver know that a new parameter is ready to be read + auto* const slot_data = GetAppletSlotData(static_cast<AppletId>(parameter.destination_id)); + ASSERT(slot_data); + + slot_data->parameter_event->Signal(); } void Initialize(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2, 2, 0); // 0x20080 u32 app_id = rp.Pop<u32>(); - u32 flags = rp.Pop<u32>(); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); - rb.Push(RESULT_SUCCESS); - rb.PushCopyHandles(Kernel::g_handle_table.Create(notification_event).Unwrap(), - Kernel::g_handle_table.Create(parameter_event).Unwrap()); + u32 attributes = rp.Pop<u32>(); - // TODO(bunnei): Check if these events are cleared every time Initialize is called. - notification_event->Clear(); - parameter_event->Clear(); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, attributes=0x%08X", app_id, attributes); - ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); - lock->Release(); + auto* const slot_data = GetAppletSlotData(attributes); - LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); + // Note: The real NS service does not check if the attributes value is valid before accessing + // the data in the array + ASSERT_MSG(slot_data, "Invalid application attributes"); + + if (slot_data->registered) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::AlreadyExists, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + slot_data->applet_id = static_cast<AppletId>(app_id); + slot_data->attributes.raw = attributes; + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); + rb.Push(RESULT_SUCCESS); + rb.PushCopyHandles(Kernel::g_handle_table.Create(slot_data->notification_event).Unwrap(), + Kernel::g_handle_table.Create(slot_data->parameter_event).Unwrap()); } void GetSharedFont(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x44, 0, 0); // 0x00440000 IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - if (!shared_font_mem) { + + // Log in telemetry if the game uses the shared font + Core::Telemetry().AddField(Telemetry::FieldType::Session, "RequiresSharedFont", true); + + if (!shared_font_loaded) { LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); rb.Push<u32>(-1); // TODO: Find the right error code rb.Skip(1 + 2, true); @@ -82,7 +216,7 @@ void GetSharedFont(Service::Interface* self) { // The shared font has to be relocated to the new address before being passed to the // application. VAddr target_address = - Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address); + Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address).value(); if (!shared_font_relocated) { BCFNT::RelocateSharedFont(shared_font_mem, target_address); shared_font_relocated = true; @@ -112,7 +246,12 @@ void GetLockHandle(Service::Interface* self) { // this will cause the app to wait until parameter_event is signaled. u32 applet_attributes = rp.Pop<u32>(); IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); - rb.Push(RESULT_SUCCESS); // No error + rb.Push(RESULT_SUCCESS); // No error + + // TODO(Subv): The output attributes should have an AppletPos of either Library or System | + // Library (depending on the type of the last launched applet) if the input attributes' + // AppletPos has the Library bit set. + rb.Push(applet_attributes); // Applet Attributes, this value is passed to Enable. rb.Push<u32>(0); // Least significant bit = power button state Kernel::Handle handle_copy = Kernel::g_handle_table.Create(lock).Unwrap(); @@ -125,10 +264,22 @@ void GetLockHandle(Service::Interface* self) { void Enable(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x3, 1, 0); // 0x30040 u32 attributes = rp.Pop<u32>(); + + LOG_DEBUG(Service_APT, "called attributes=0x%08X", attributes); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); // No error - parameter_event->Signal(); // Let the application know that it has been started - LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes); + + auto* const slot_data = GetAppletSlotData(attributes); + + if (!slot_data) { + rb.Push(ResultCode(ErrCodes::InvalidAppletSlot, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + slot_data->registered = true; + + rb.Push(RESULT_SUCCESS); } void GetAppletManInfo(Service::Interface* self) { @@ -146,22 +297,27 @@ void GetAppletManInfo(Service::Interface* self) { void IsRegistered(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x9, 1, 0); // 0x90040 - u32 app_id = rp.Pop<u32>(); + AppletId app_id = static_cast<AppletId>(rp.Pop<u32>()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); // No error - // TODO(Subv): An application is considered "registered" if it has already called APT::Enable - // handle this properly once we implement multiprocess support. - bool is_registered = false; // Set to not registered by default + auto* const slot_data = GetAppletSlotData(app_id); + + // Check if an LLE applet was registered first, then fallback to HLE applets + bool is_registered = slot_data && slot_data->registered; - if (app_id == static_cast<u32>(AppletId::AnyLibraryApplet)) { - is_registered = HLE::Applets::IsLibraryAppletRunning(); - } else if (auto applet = HLE::Applets::Applet::Get(static_cast<AppletId>(app_id))) { - is_registered = true; // Set to registered + if (!is_registered) { + if (app_id == AppletId::AnyLibraryApplet) { + is_registered = HLE::Applets::IsLibraryAppletRunning(); + } else if (auto applet = HLE::Applets::Applet::Get(app_id)) { + // The applet exists, set it as registered. + is_registered = true; + } } + rb.Push(is_registered); - LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); + LOG_DEBUG(Service_APT, "called app_id=0x%08X", static_cast<u32>(app_id)); } void InquireNotification(Service::Interface* self) { @@ -186,8 +342,20 @@ void SendParameter(Service::Interface* self) { std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id)); + LOG_DEBUG(Service_APT, + "called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," + "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", + src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + // A new parameter can not be sent if the previous one hasn't been consumed yet + if (next_parameter) { + rb.Push(ResultCode(ErrCodes::ParameterPresent, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + if (dest_applet == nullptr) { LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id); rb.Push<u32>(-1); // TODO(Subv): Find the right error code @@ -203,11 +371,6 @@ void SendParameter(Service::Interface* self) { Memory::ReadBlock(buffer, param.buffer.data(), param.buffer.size()); rb.Push(dest_applet->ReceiveParameter(param)); - - LOG_WARNING(Service_APT, - "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," - "buffer_size=0x%08X, handle=0x%08X, size=0x%08zX, in_param_buffer_ptr=0x%08X", - src_app_id, dst_app_id, signal_type, buffer_size, handle, size, buffer); } void ReceiveParameter(Service::Interface* self) { @@ -223,21 +386,40 @@ void ReceiveParameter(Service::Interface* self) { "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", buffer_size, static_buff_size); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); + + if (!next_parameter) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + if (next_parameter->destination_id != app_id) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, + ErrorLevel::Status)); + return; + } + IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); + rb.Push(RESULT_SUCCESS); // No error - rb.Push(next_parameter.sender_id); - rb.Push(next_parameter.signal); // Signal type - ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); - rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size + rb.Push(next_parameter->sender_id); + rb.Push(next_parameter->signal); // Signal type + ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); + rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size - rb.PushMoveHandles((next_parameter.object != nullptr) - ? Kernel::g_handle_table.Create(next_parameter.object).Unwrap() + rb.PushMoveHandles((next_parameter->object != nullptr) + ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap() : 0); - rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); - Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); + rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter->buffer.size()), 0); + + Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); - LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); + // Clear the parameter + next_parameter = boost::none; } void GlanceParameter(Service::Interface* self) { @@ -253,37 +435,74 @@ void GlanceParameter(Service::Interface* self) { "buffer_size is bigger than the size in the buffer descriptor (0x%08X > 0x%08zX)", buffer_size, static_buff_size); + LOG_DEBUG(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); + + if (!next_parameter) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NoData, ErrorModule::Applet, + ErrorSummary::InvalidState, ErrorLevel::Status)); + return; + } + + if (next_parameter->destination_id != app_id) { + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound, + ErrorLevel::Status)); + return; + } + IPC::RequestBuilder rb = rp.MakeBuilder(4, 4); rb.Push(RESULT_SUCCESS); // No error - rb.Push(next_parameter.sender_id); - rb.Push(next_parameter.signal); // Signal type - ASSERT_MSG(next_parameter.buffer.size() <= buffer_size, "Input static buffer is too small !"); - rb.Push(static_cast<u32>(next_parameter.buffer.size())); // Parameter buffer size + rb.Push(next_parameter->sender_id); + rb.Push(next_parameter->signal); // Signal type + ASSERT_MSG(next_parameter->buffer.size() <= buffer_size, "Input static buffer is too small !"); + rb.Push(static_cast<u32>(next_parameter->buffer.size())); // Parameter buffer size - rb.PushCopyHandles((next_parameter.object != nullptr) - ? Kernel::g_handle_table.Create(next_parameter.object).Unwrap() + rb.PushMoveHandles((next_parameter->object != nullptr) + ? Kernel::g_handle_table.Create(next_parameter->object).Unwrap() : 0); - rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter.buffer.size()), 0); - Memory::WriteBlock(buffer, next_parameter.buffer.data(), next_parameter.buffer.size()); + rb.PushStaticBuffer(buffer, static_cast<u32>(next_parameter->buffer.size()), 0); + + Memory::WriteBlock(buffer, next_parameter->buffer.data(), next_parameter->buffer.size()); - LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08zX", app_id, buffer_size); + // Note: The NS module always clears the DSPSleep and DSPWakeup signals even in GlanceParameter. + if (next_parameter->signal == static_cast<u32>(SignalType::DspSleep) || + next_parameter->signal == static_cast<u32>(SignalType::DspWakeup)) + next_parameter = boost::none; } void CancelParameter(Service::Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xF, 4, 0); // 0xF0100 - u32 check_sender = rp.Pop<u32>(); + bool check_sender = rp.Pop<bool>(); u32 sender_appid = rp.Pop<u32>(); - u32 check_receiver = rp.Pop<u32>(); + bool check_receiver = rp.Pop<bool>(); u32 receiver_appid = rp.Pop<u32>(); + + bool cancellation_success = true; + + if (!next_parameter) { + cancellation_success = false; + } else { + if (check_sender && next_parameter->sender_id != sender_appid) + cancellation_success = false; + + if (check_receiver && next_parameter->destination_id != receiver_appid) + cancellation_success = false; + } + + if (cancellation_success) + next_parameter = boost::none; + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); // No error - rb.Push(true); // Set to Success + rb.Push(cancellation_success); - LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " - "check_receiver=0x%08X, receiver_appid=0x%08X", - check_sender, sender_appid, check_receiver, receiver_appid); + LOG_DEBUG(Service_APT, "called check_sender=%u, sender_appid=0x%08X, " + "check_receiver=%u, receiver_appid=0x%08X", + check_sender, sender_appid, check_receiver, receiver_appid); } void PrepareToStartApplication(Service::Interface* self) { @@ -644,36 +863,146 @@ void CheckNew3DS(Service::Interface* self) { LOG_WARNING(Service_APT, "(STUBBED) called"); } -void Init() { - AddService(new APT_A_Interface); - AddService(new APT_S_Interface); - AddService(new APT_U_Interface); +static u32 DecompressLZ11(const u8* in, u8* out) { + u32_le decompressed_size; + memcpy(&decompressed_size, in, sizeof(u32)); + in += 4; + + u8 type = decompressed_size & 0xFF; + ASSERT(type == 0x11); + decompressed_size >>= 8; + + u32 current_out_size = 0; + u8 flags = 0, mask = 1; + while (current_out_size < decompressed_size) { + if (mask == 1) { + flags = *(in++); + mask = 0x80; + } else { + mask >>= 1; + } + + if (flags & mask) { + u8 byte1 = *(in++); + u32 length = byte1 >> 4; + u32 offset; + if (length == 0) { + u8 byte2 = *(in++); + u8 byte3 = *(in++); + length = (((byte1 & 0x0F) << 4) | (byte2 >> 4)) + 0x11; + offset = (((byte2 & 0x0F) << 8) | byte3) + 0x1; + } else if (length == 1) { + u8 byte2 = *(in++); + u8 byte3 = *(in++); + u8 byte4 = *(in++); + length = (((byte1 & 0x0F) << 12) | (byte2 << 4) | (byte3 >> 4)) + 0x111; + offset = (((byte3 & 0x0F) << 8) | byte4) + 0x1; + } else { + u8 byte2 = *(in++); + length = (byte1 >> 4) + 0x1; + offset = (((byte1 & 0x0F) << 8) | byte2) + 0x1; + } + + for (u32 i = 0; i < length; i++) { + *out = *(out - offset); + ++out; + } + + current_out_size += length; + } else { + *(out++) = *(in++); + current_out_size++; + } + } + return decompressed_size; +} - HLE::Applets::Init(); +static bool LoadSharedFont() { + // TODO (wwylele): load different font archive for region CHN/KOR/TWN + const u64_le shared_font_archive_id_low = 0x0004009b00014002; + const u64_le shared_font_archive_id_high = 0x00000001ffffff00; + std::vector<u8> shared_font_archive_id(16); + std::memcpy(&shared_font_archive_id[0], &shared_font_archive_id_low, sizeof(u64)); + std::memcpy(&shared_font_archive_id[8], &shared_font_archive_id_high, sizeof(u64)); + FileSys::Path archive_path(shared_font_archive_id); + auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::NCCH, archive_path); + if (archive_result.Failed()) + return false; + + std::vector<u8> romfs_path(20, 0); // 20-byte all zero path for opening RomFS + FileSys::Path file_path(romfs_path); + FileSys::Mode open_mode = {}; + open_mode.read_flag.Assign(1); + auto file_result = Service::FS::OpenFileFromArchive(*archive_result, file_path, open_mode); + if (file_result.Failed()) + return false; + + auto romfs = std::move(file_result).Unwrap(); + std::vector<u8> romfs_buffer(romfs->backend->GetSize()); + romfs->backend->Read(0, romfs_buffer.size(), romfs_buffer.data()); + romfs->backend->Close(); + + const u8* font_file = RomFS::GetFilePointer(romfs_buffer.data(), {u"cbf_std.bcfnt.lz"}); + if (font_file == nullptr) + return false; + + struct { + u32_le status; + u32_le region; + u32_le decompressed_size; + INSERT_PADDING_WORDS(0x1D); + } shared_font_header{}; + static_assert(sizeof(shared_font_header) == 0x80, "shared_font_header has incorrect size"); + + shared_font_header.status = 2; // successfully loaded + shared_font_header.region = 1; // region JPN/EUR/USA + shared_font_header.decompressed_size = + DecompressLZ11(font_file, shared_font_mem->GetPointer(0x80)); + std::memcpy(shared_font_mem->GetPointer(), &shared_font_header, sizeof(shared_font_header)); + *shared_font_mem->GetPointer(0x83) = 'U'; // Change the magic from "CFNT" to "CFNU" + + return true; +} - // Load the shared system font (if available). +static bool LoadLegacySharedFont() { + // This is the legacy method to load shared font. // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file // "shared_font.bin" in the Citra "sysdata" directory. - std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; FileUtil::CreateFullPath(filepath); // Create path if not already created FileUtil::IOFile file(filepath, "rb"); - if (file.IsOpen()) { - // Create shared font memory object - using Kernel::MemoryPermission; - shared_font_mem = - Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB - MemoryPermission::ReadWrite, MemoryPermission::Read, 0, - Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); - // Read shared font data file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize()); + return true; + } + + return false; +} + +void Init() { + AddService(new APT_A_Interface); + AddService(new APT_S_Interface); + AddService(new APT_U_Interface); + + HLE::Applets::Init(); + + using Kernel::MemoryPermission; + shared_font_mem = + Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB + MemoryPermission::ReadWrite, MemoryPermission::Read, 0, + Kernel::MemoryRegion::SYSTEM, "APT:SharedFont"); + + if (LoadSharedFont()) { + shared_font_loaded = true; + } else if (LoadLegacySharedFont()) { + LOG_WARNING(Service_APT, "Loaded shared font by legacy method"); + shared_font_loaded = true; } else { - LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); - shared_font_mem = nullptr; + LOG_WARNING(Service_APT, "Unable to load shared font"); + shared_font_loaded = false; } lock = Kernel::Mutex::Create(false, "APT_U:Lock"); @@ -683,22 +1012,38 @@ void Init() { screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value - // TODO(bunnei): Check if these are created in Initialize or on APT process startup. - notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); - parameter_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Start"); + for (size_t slot = 0; slot < applet_slots.size(); ++slot) { + auto& slot_data = applet_slots[slot]; + slot_data.slot = static_cast<AppletSlot>(slot); + slot_data.applet_id = AppletId::None; + slot_data.attributes.raw = 0; + slot_data.registered = false; + slot_data.notification_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Notification"); + slot_data.parameter_event = + Kernel::Event::Create(Kernel::ResetType::OneShot, "APT:Parameter"); + } - next_parameter.signal = static_cast<u32>(SignalType::Wakeup); - next_parameter.destination_id = 0x300; + // Initialize the parameter to wake up the application. + next_parameter.emplace(); + next_parameter->signal = static_cast<u32>(SignalType::Wakeup); + next_parameter->destination_id = static_cast<u32>(AppletId::Application); + applet_slots[static_cast<size_t>(AppletSlot::Application)].parameter_event->Signal(); } void Shutdown() { shared_font_mem = nullptr; + shared_font_loaded = false; shared_font_relocated = false; lock = nullptr; - notification_event = nullptr; - parameter_event = nullptr; - next_parameter.object = nullptr; + for (auto& slot : applet_slots) { + slot.registered = false; + slot.notification_event = nullptr; + slot.parameter_event = nullptr; + } + + next_parameter = boost::none; HLE::Applets::Shutdown(); } diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index ee80926d2..96b28b438 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -72,6 +72,8 @@ enum class SignalType : u32 { /// App Id's used by APT functions enum class AppletId : u32 { + None = 0, + AnySystemApplet = 0x100, HomeMenu = 0x101, AlternateMenu = 0x103, Camera = 0x110, @@ -83,6 +85,7 @@ enum class AppletId : u32 { Miiverse = 0x117, MiiversePost = 0x118, AmiiboSettings = 0x119, + AnySysLibraryApplet = 0x200, SoftwareKeyboard1 = 0x201, Ed1 = 0x202, PnoteApp = 0x204, @@ -116,6 +119,13 @@ enum class ScreencapPostPermission : u32 { DisableScreenshotPostingToMiiverse = 3 }; +namespace ErrCodes { +enum { + ParameterPresent = 2, + InvalidAppletSlot = 4, +}; +} // namespace ErrCodes + /// Send a parameter to the currently-running application, which will read it via ReceiveParameter void SendParameter(const MessageParameter& parameter); diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp index 57eb39d75..6d2474702 100644 --- a/src/core/hle/service/apt/bcfnt/bcfnt.cpp +++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp @@ -78,7 +78,8 @@ void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAd memcpy(&cmap, data, sizeof(cmap)); // Relocate the offsets in the CMAP section - cmap.next_cmap_offset += offset; + if (cmap.next_cmap_offset != 0) + cmap.next_cmap_offset += offset; memcpy(data, &cmap, sizeof(cmap)); } else if (memcmp(section_header.magic, "CWDH", 4) == 0) { @@ -86,7 +87,8 @@ void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAd memcpy(&cwdh, data, sizeof(cwdh)); // Relocate the offsets in the CWDH section - cwdh.next_cwdh_offset += offset; + if (cwdh.next_cwdh_offset != 0) + cwdh.next_cwdh_offset += offset; memcpy(data, &cwdh, sizeof(cwdh)); } else if (memcmp(section_header.magic, "TGLP", 4) == 0) { diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp index ee941e228..3990d0d6e 100644 --- a/src/core/hle/service/boss/boss_p.cpp +++ b/src/core/hle/service/boss/boss_p.cpp @@ -66,7 +66,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00360084, SetTaskQuery, "SetTaskQuery"}, {0x00370084, GetTaskQuery, "GetTaskQuery"}, // boss:p + {0x04010082, nullptr, "InitializeSessionPrivileged"}, {0x04040080, nullptr, "GetAppNewFlag"}, + {0x040D0182, nullptr, "GetNsDataIdListPrivileged"}, + {0x040E0182, nullptr, "GetNsDataIdListPrivileged1"}, {0x04130082, nullptr, "SendPropertyPrivileged"}, {0x041500C0, nullptr, "DeleteNsDataPrivileged"}, {0x04160142, nullptr, "GetNsDataHeaderInfoPrivileged"}, diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 6624f1711..3dbeb27cc 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -681,7 +681,7 @@ void GenerateConsoleUniqueId(u32& random_number, u64& console_id) { CryptoPP::AutoSeededRandomPool rng; random_number = rng.GenerateWord32(0, 0xFFFF); u64_le local_friend_code_seed; - rng.GenerateBlock(reinterpret_cast<byte*>(&local_friend_code_seed), + rng.GenerateBlock(reinterpret_cast<CryptoPP::byte*>(&local_friend_code_seed), sizeof(local_friend_code_seed)); console_id = (local_friend_code_seed & 0x3FFFFFFFF) | (static_cast<u64>(random_number) << 48); } diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp index 56f934b3f..6f2bf2061 100644 --- a/src/core/hle/service/dlp/dlp_clnt.cpp +++ b/src/core/hle/service/dlp/dlp_clnt.cpp @@ -8,7 +8,26 @@ namespace Service { namespace DLP { const Interface::FunctionInfo FunctionTable[] = { - {0x000100C3, nullptr, "Initialize"}, {0x00110000, nullptr, "GetWirelessRebootPassphrase"}, + {0x000100C3, nullptr, "Initialize"}, + {0x00020000, nullptr, "Finalize"}, + {0x00030000, nullptr, "GetEventDesc"}, + {0x00040000, nullptr, "GetChannel"}, + {0x00050180, nullptr, "StartScan"}, + {0x00060000, nullptr, "StopScan"}, + {0x00070080, nullptr, "GetServerInfo"}, + {0x00080100, nullptr, "GetTitleInfo"}, + {0x00090040, nullptr, "GetTitleInfoInOrder"}, + {0x000A0080, nullptr, "DeleteScanInfo"}, + {0x000B0100, nullptr, "PrepareForSystemDownload"}, + {0x000C0000, nullptr, "StartSystemDownload"}, + {0x000D0100, nullptr, "StartTitleDownload"}, + {0x000E0000, nullptr, "GetMyStatus"}, + {0x000F0040, nullptr, "GetConnectingNodes"}, + {0x00100040, nullptr, "GetNodeInfo"}, + {0x00110000, nullptr, "GetWirelessRebootPassphrase"}, + {0x00120000, nullptr, "StopSession"}, + {0x00130100, nullptr, "GetCupVersion"}, + {0x00140100, nullptr, "GetDupAvailability"}, }; DLP_CLNT_Interface::DLP_CLNT_Interface() { diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp index 29b9d52e0..fe6be7d32 100644 --- a/src/core/hle/service/dlp/dlp_fkcl.cpp +++ b/src/core/hle/service/dlp/dlp_fkcl.cpp @@ -8,7 +8,23 @@ namespace Service { namespace DLP { const Interface::FunctionInfo FunctionTable[] = { - {0x00010083, nullptr, "Initialize"}, {0x000F0000, nullptr, "GetWirelessRebootPassphrase"}, + {0x00010083, nullptr, "Initialize"}, + {0x00020000, nullptr, "Finalize"}, + {0x00030000, nullptr, "GetEventDesc"}, + {0x00040000, nullptr, "GetChannels"}, + {0x00050180, nullptr, "StartScan"}, + {0x00060000, nullptr, "StopScan"}, + {0x00070080, nullptr, "GetServerInfo"}, + {0x00080100, nullptr, "GetTitleInfo"}, + {0x00090040, nullptr, "GetTitleInfoInOrder"}, + {0x000A0080, nullptr, "DeleteScanInfo"}, + {0x000B0100, nullptr, "StartFakeSession"}, + {0x000C0000, nullptr, "GetMyStatus"}, + {0x000D0040, nullptr, "GetConnectingNodes"}, + {0x000E0040, nullptr, "GetNodeInfo"}, + {0x000F0000, nullptr, "GetWirelessRebootPassphrase"}, + {0x00100000, nullptr, "StopSession"}, + {0x00110203, nullptr, "Initialize2"}, }; DLP_FKCL_Interface::DLP_FKCL_Interface() { diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp index 32cfa2c44..1bcea43d3 100644 --- a/src/core/hle/service/dlp/dlp_srvr.cpp +++ b/src/core/hle/service/dlp/dlp_srvr.cpp @@ -11,7 +11,7 @@ namespace Service { namespace DLP { -static void unk_0x000E0040(Interface* self) { +static void IsChild(Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = RESULT_SUCCESS.raw; @@ -24,14 +24,19 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00010183, nullptr, "Initialize"}, {0x00020000, nullptr, "Finalize"}, {0x00030000, nullptr, "GetServerState"}, + {0x00040000, nullptr, "GetEventDescription"}, {0x00050080, nullptr, "StartAccepting"}, + {0x00060000, nullptr, "EndAccepting"}, {0x00070000, nullptr, "StartDistribution"}, {0x000800C0, nullptr, "SendWirelessRebootPassphrase"}, {0x00090040, nullptr, "AcceptClient"}, + {0x000A0040, nullptr, "DisconnectClient"}, {0x000B0042, nullptr, "GetConnectingClients"}, {0x000C0040, nullptr, "GetClientInfo"}, {0x000D0040, nullptr, "GetClientState"}, - {0x000E0040, unk_0x000E0040, "unk_0x000E0040"}, + {0x000E0040, IsChild, "IsChild"}, + {0x000F0303, nullptr, "InitializeWithName"}, + {0x00100000, nullptr, "GetDupNoticeNeed"}, }; DLP_SRVR_Interface::DLP_SRVR_Interface() { diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 7d746054f..42f8950f9 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -147,9 +147,10 @@ static void LoadComponent(Service::Interface* self) { LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(component_data.data(), component_data.size())); // Some versions of the firmware have the location of DSP structures listed here. - ASSERT(size > 0x37C); - LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, - Common::ComputeHash64(component_data.data() + 0x340, 60)); + if (size > 0x37C) { + LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, + Common::ComputeHash64(component_data.data() + 0x340, 60)); + } LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X", diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp index 76ecda8b7..7ad7798da 100644 --- a/src/core/hle/service/frd/frd.cpp +++ b/src/core/hle/service/frd/frd.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/hle/ipc.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/result.h" #include "core/hle/service/frd/frd.h" #include "core/hle/service/frd/frd_a.h" @@ -105,6 +106,48 @@ void GetMyScreenName(Service::Interface* self) { LOG_WARNING(Service_FRD, "(STUBBED) called"); } +void UnscrambleLocalFriendCode(Service::Interface* self) { + const size_t scrambled_friend_code_size = 12; + const size_t friend_code_size = 8; + + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1C, 1, 2); + const u32 friend_code_count = rp.Pop<u32>(); + size_t in_buffer_size; + const VAddr scrambled_friend_codes = rp.PopStaticBuffer(&in_buffer_size, false); + ASSERT_MSG(in_buffer_size == (friend_code_count * scrambled_friend_code_size), + "Wrong input buffer size"); + + size_t out_buffer_size; + VAddr unscrambled_friend_codes = rp.PeekStaticBuffer(0, &out_buffer_size); + ASSERT_MSG(out_buffer_size == (friend_code_count * friend_code_size), + "Wrong output buffer size"); + + for (u32 current = 0; current < friend_code_count; ++current) { + // TODO(B3N30): Unscramble the codes and compare them against the friend list + // Only write 0 if the code isn't in friend list, otherwise write the + // unscrambled one + // + // Code for unscrambling (should be compared to HW): + // std::array<u16, 6> scambled_friend_code; + // Memory::ReadBlock(scrambled_friend_codes+(current*scrambled_friend_code_size), + // scambled_friend_code.data(), scrambled_friend_code_size); std::array<u16, 4> + // unscrambled_friend_code; unscrambled_friend_code[0] = scambled_friend_code[0] ^ + // scambled_friend_code[5]; unscrambled_friend_code[1] = scambled_friend_code[1] ^ + // scambled_friend_code[5]; unscrambled_friend_code[2] = scambled_friend_code[2] ^ + // scambled_friend_code[5]; unscrambled_friend_code[3] = scambled_friend_code[3] ^ + // scambled_friend_code[5]; + + u64 result = 0ull; + Memory::WriteBlock(unscrambled_friend_codes + (current * sizeof(result)), &result, + sizeof(result)); + } + + LOG_WARNING(Service_FRD, "(STUBBED) called"); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(RESULT_SUCCESS); + rb.PushStaticBuffer(unscrambled_friend_codes, out_buffer_size, 0); +} + void SetClientSdkVersion(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h index e61940ea0..66a87c8cd 100644 --- a/src/core/hle/service/frd/frd.h +++ b/src/core/hle/service/frd/frd.h @@ -96,6 +96,19 @@ void GetMyFriendKey(Service::Interface* self); void GetMyScreenName(Service::Interface* self); /** + * FRD::UnscrambleLocalFriendCode service function + * Inputs: + * 1 : Friend code count + * 2 : ((count * 12) << 14) | 0x402 + * 3 : Pointer to encoded friend codes. Each is 12 bytes large + * 64 : ((count * 8) << 14) | 2 + * 65 : Pointer to write decoded local friend codes to. Each is 8 bytes large. + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void UnscrambleLocalFriendCode(Service::Interface* self); + +/** * FRD::SetClientSdkVersion service function * Inputs: * 1 : Used SDK Version diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 496f29ca9..6970ff768 100644 --- a/src/core/hle/service/frd/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp @@ -36,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00190042, nullptr, "GetFriendFavoriteGame"}, {0x001A00C4, nullptr, "GetFriendInfo"}, {0x001B0080, nullptr, "IsIncludedInFriendList"}, - {0x001C0042, nullptr, "UnscrambleLocalFriendCode"}, + {0x001C0042, UnscrambleLocalFriendCode, "UnscrambleLocalFriendCode"}, {0x001D0002, nullptr, "UpdateGameModeDescription"}, {0x001E02C2, nullptr, "UpdateGameMode"}, {0x001F0042, nullptr, "SendInvitation"}, diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index bc964ec60..88684b82d 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -475,12 +475,11 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { // TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever // possible/likely - Memory::RasterizerFlushRegion( - Memory::VirtualToPhysicalAddress(command.dma_request.source_address), - command.dma_request.size); - Memory::RasterizerFlushAndInvalidateRegion( - Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), - command.dma_request.size); + Memory::RasterizerFlushVirtualRegion(command.dma_request.source_address, + command.dma_request.size, Memory::FlushMode::Flush); + Memory::RasterizerFlushVirtualRegion(command.dma_request.dest_address, + command.dma_request.size, + Memory::FlushMode::FlushAndInvalidate); // TODO(Subv): These memory accesses should not go through the application's memory mapping. // They should go through the GSP module's memory mapping. diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2014b8461..aa5d821f9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -7,8 +7,9 @@ #include <cmath> #include <memory> #include "common/logging/log.h" +#include "core/3ds.h" +#include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/emu_window.h" #include "core/frontend/input.h" #include "core/hle/ipc.h" #include "core/hle/kernel/event.h" @@ -18,7 +19,6 @@ #include "core/hle/service/hid/hid_spvr.h" #include "core/hle/service/hid/hid_user.h" #include "core/hle/service/service.h" -#include "video_core/video_core.h" namespace Service { namespace HID { @@ -50,10 +50,15 @@ constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234; constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104; constexpr u64 gyroscope_update_ticks = BASE_CLOCK_RATE_ARM11 / 101; +constexpr float accelerometer_coef = 512.0f; // measured from hw test result +constexpr float gyroscope_coef = 14.375f; // got from hwtest GetGyroscopeLowRawToDpsCoefficient call + static std::atomic<bool> is_device_reload_pending; static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> buttons; static std::unique_ptr<Input::AnalogDevice> circle_pad; +static std::unique_ptr<Input::MotionDevice> motion_device; +static std::unique_ptr<Input::TouchDevice> touch_device; DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) { // 30 degree and 60 degree are angular thresholds for directions @@ -90,6 +95,8 @@ static void LoadInputDevices() { buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); circle_pad = Input::CreateDevice<Input::AnalogDevice>( Settings::values.analogs[Settings::NativeAnalog::CirclePad]); + motion_device = Input::CreateDevice<Input::MotionDevice>(Settings::values.motion_device); + touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); } static void UnloadInputDevices() { @@ -97,6 +104,8 @@ static void UnloadInputDevices() { button.reset(); } circle_pad.reset(); + motion_device.reset(); + touch_device.reset(); } static void UpdatePadCallback(u64 userdata, int cycles_late) { @@ -165,8 +174,10 @@ static void UpdatePadCallback(u64 userdata, int cycles_late) { // Get the current touch entry TouchDataEntry& touch_entry = mem->touch.entries[mem->touch.index]; bool pressed = false; - - std::tie(touch_entry.x, touch_entry.y, pressed) = VideoCore::g_emu_window->GetTouchState(); + float x, y; + std::tie(x, y, pressed) = touch_device->GetStatus(); + touch_entry.x = static_cast<u16>(x * Core::kScreenBottomWidth); + touch_entry.y = static_cast<u16>(y * Core::kScreenBottomHeight); touch_entry.valid.Assign(pressed ? 1 : 0); // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which @@ -193,10 +204,19 @@ static void UpdateAccelerometerCallback(u64 userdata, int cycles_late) { mem->accelerometer.index = next_accelerometer_index; next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size(); + Math::Vec3<float> accel; + std::tie(accel, std::ignore) = motion_device->GetStatus(); + accel *= accelerometer_coef; + // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback + // The time stretch formula should be like + // stretched_vector = (raw_vector - gravity) * stretch_ratio + gravity + AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index]; - std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) = - VideoCore::g_emu_window->GetAccelerometerState(); + + accelerometer_entry.x = static_cast<s16>(accel.x); + accelerometer_entry.y = static_cast<s16>(accel.y); + accelerometer_entry.z = static_cast<s16>(accel.z); // Make up "raw" entry // TODO(wwylele): @@ -227,8 +247,14 @@ static void UpdateGyroscopeCallback(u64 userdata, int cycles_late) { next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size(); GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index]; - std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) = - VideoCore::g_emu_window->GetGyroscopeState(); + + Math::Vec3<float> gyro; + std::tie(std::ignore, gyro) = motion_device->GetStatus(); + double stretch = Core::System::GetInstance().perf_stats.GetLastFrameTimeScale(); + gyro *= gyroscope_coef * stretch; + gyroscope_entry.x = static_cast<s16>(gyro.x); + gyroscope_entry.y = static_cast<s16>(gyro.y); + gyroscope_entry.z = static_cast<s16>(gyro.z); // Make up "raw" entry mem->gyroscope.raw_entry.x = gyroscope_entry.x; @@ -326,7 +352,7 @@ void GetGyroscopeLowRawToDpsCoefficient(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; - f32 coef = VideoCore::g_emu_window->GetGyroscopeRawToDpsCoefficient(); + f32 coef = gyroscope_coef; memcpy(&cmd_buff[2], &coef, 4); } diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 1ef972e70..ef25926b5 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -24,7 +24,7 @@ namespace HID { */ struct PadState { union { - u32 hex; + u32 hex{}; BitField<0, 1, u32> a; BitField<1, 1, u32> b; diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 837413f93..0912d5756 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -18,7 +18,7 @@ namespace Service { namespace IR { union PadState { - u32_le hex; + u32_le hex{}; BitField<14, 1, u32_le> zl; BitField<15, 1, u32_le> zr; diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index e73971d5f..57172ddd6 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -587,8 +587,8 @@ static void StartConversion(Interface* self) { // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( u32 total_output_size = conversion.input_lines * (conversion.dst.transfer_unit + conversion.dst.gap); - Memory::RasterizerFlushAndInvalidateRegion( - Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); + Memory::RasterizerFlushVirtualRegion(conversion.dst.address, total_output_size, + Memory::FlushMode::FlushAndInvalidate); HW::Y2R::PerformConversion(conversion); |