summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/acc/acc.cpp1
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp1
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp177
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.h104
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp1
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.cpp2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp20
-rw-r--r--src/core/hle/service/am/applets/applets.h12
-rw-r--r--src/core/hle/service/audio/audin_u.cpp10
-rw-r--r--src/core/hle/service/audio/audout_u.cpp10
-rw-r--r--src/core/hle/service/audio/audren_u.cpp7
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp4
-rw-r--r--src/core/hle/service/es/es.cpp27
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp4
-rw-r--r--src/core/hle/service/hid/hid.cpp32
-rw-r--r--src/core/hle/service/hid/hid.h4
-rw-r--r--src/core/hle/service/ldn/ldn.cpp4
-rw-r--r--src/core/hle/service/nfc/nfc.cpp71
-rw-r--r--src/core/hle/service/nfc/nfc_device.cpp197
-rw-r--r--src/core/hle/service/nfc/nfc_device.h70
-rw-r--r--src/core/hle/service/nfc/nfc_result.h17
-rw-r--r--src/core/hle/service/nfc/nfc_user.cpp365
-rw-r--r--src/core/hle/service/nfc/nfc_user.h52
-rw-r--r--src/core/hle/service/nfp/amiibo_crypto.cpp1
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp41
-rw-r--r--src/core/hle/service/nfp/nfp_device.h9
-rw-r--r--src/core/hle/service/nfp/nfp_types.h17
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp23
-rw-r--r--src/core/hle/service/nfp/nfp_user.h5
-rw-r--r--src/core/hle/service/nifm/nifm.cpp41
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.cpp11
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.cpp46
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp44
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_item_consumer.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_consumer.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h5
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp14
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h3
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.cpp6
-rw-r--r--src/core/hle/service/nvflinger/consumer_base.h16
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp3
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h1
-rw-r--r--src/core/hle/service/nvflinger/producer_listener.h1
-rw-r--r--src/core/hle/service/service.cpp1
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp1
53 files changed, 1276 insertions, 237 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 85a3f0802..6d1084fd1 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -7,6 +7,7 @@
#include "common/fs/file.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
#include "common/string_util.h"
#include "common/swap.h"
#include "core/constants.h"
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 481e0d141..97f7c6688 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -9,6 +9,7 @@
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
+#include "common/polyfill_ranges.h"
#include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h"
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 8ea7fd760..22999c942 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
const u64 offset{rp.Pop<u64>()};
const std::vector<u8> data{ctx.ReadBuffer()};
- const std::size_t size{std::min(data.size(), backing.GetSize() - offset)};
+ const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
@@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 offset{rp.Pop<u64>()};
- const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
+ const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
new file mode 100644
index 000000000..d0969b0f1
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -0,0 +1,177 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/assert.h"
+#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/nfp/nfp_device.h"
+
+namespace Service::AM::Applets {
+
+Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::CabinetApplet& frontend_)
+ : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
+ system_,
+ "CabinetApplet"} {
+
+ availability_change_event =
+ service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent");
+}
+
+Cabinet::~Cabinet() = default;
+
+void Cabinet::Initialize() {
+ Applet::Initialize();
+
+ LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
+
+ LOG_DEBUG(Service_HID,
+ "Initializing Applet with common_args: arg_version={}, lib_version={}, "
+ "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
+ common_args.arguments_version, common_args.library_version,
+ common_args.play_startup_sound, common_args.size, common_args.system_tick,
+ common_args.theme_color);
+
+ const auto storage = broker.PopNormalDataToApplet();
+ ASSERT(storage != nullptr);
+
+ const auto applet_input_data = storage->GetData();
+ ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings));
+
+ std::memcpy(&applet_input_common, applet_input_data.data(),
+ sizeof(StartParamForAmiiboSettings));
+}
+
+bool Cabinet::TransactionComplete() const {
+ return is_complete;
+}
+
+Result Cabinet::GetStatus() const {
+ return ResultSuccess;
+}
+
+void Cabinet::ExecuteInteractive() {
+ ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
+}
+
+void Cabinet::Execute() {
+ if (is_complete) {
+ return;
+ }
+
+ const auto callback = [this](bool apply_changes, const std::string& amiibo_name) {
+ DisplayCompleted(apply_changes, amiibo_name);
+ };
+
+ // TODO: listen on all controllers
+ if (nfp_device == nullptr) {
+ nfp_device = std::make_shared<Service::NFP::NfpDevice>(
+ system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
+ nfp_device->Initialize();
+ nfp_device->StartDetection(Service::NFP::TagProtocol::All);
+ }
+
+ const Core::Frontend::CabinetParameters parameters{
+ .tag_info = applet_input_common.tag_info,
+ .register_info = applet_input_common.register_info,
+ .mode = applet_input_common.applet_mode,
+ };
+
+ switch (applet_input_common.applet_mode) {
+ case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
+ case Service::NFP::CabinetMode::StartGameDataEraser:
+ case Service::NFP::CabinetMode::StartRestorer:
+ case Service::NFP::CabinetMode::StartFormatter:
+ frontend.ShowCabinetApplet(callback, parameters, nfp_device);
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
+ DisplayCompleted(false, {});
+ break;
+ }
+}
+
+void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) {
+ Service::Mii::MiiManager manager;
+ ReturnValueForAmiiboSettings applet_output{};
+
+ if (!apply_changes) {
+ Cancel();
+ }
+
+ if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
+ nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+ Cancel();
+ }
+
+ if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
+ nfp_device->Mount(Service::NFP::MountTarget::All);
+ }
+
+ switch (applet_input_common.applet_mode) {
+ case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
+ Service::NFP::AmiiboName name{};
+ std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
+ nfp_device->SetNicknameAndOwner(name);
+ break;
+ }
+ case Service::NFP::CabinetMode::StartGameDataEraser:
+ nfp_device->DeleteApplicationArea();
+ break;
+ case Service::NFP::CabinetMode::StartRestorer:
+ nfp_device->RestoreAmiibo();
+ break;
+ case Service::NFP::CabinetMode::StartFormatter:
+ nfp_device->DeleteAllData();
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
+ break;
+ }
+
+ applet_output.device_handle = applet_input_common.device_handle;
+ applet_output.result = CabinetResult::Cancel;
+ const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
+ const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
+ nfp_device->Finalize();
+
+ if (reg_result.IsSuccess()) {
+ applet_output.result |= CabinetResult::RegisterInfo;
+ }
+
+ if (tag_result.IsSuccess()) {
+ applet_output.result |= CabinetResult::TagInfo;
+ }
+
+ std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
+ std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
+
+ is_complete = true;
+
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+ broker.SignalStateChanged();
+}
+
+void Cabinet::Cancel() {
+ ReturnValueForAmiiboSettings applet_output{};
+ applet_output.device_handle = applet_input_common.device_handle;
+ applet_output.result = CabinetResult::Cancel;
+ nfp_device->Finalize();
+
+ std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
+ std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
+
+ is_complete = true;
+
+ broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
+ broker.SignalStateChanged();
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
new file mode 100644
index 000000000..84197a807
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -0,0 +1,104 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfp/nfp_types.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Service::NFP {
+class NfpDevice;
+}
+
+namespace Service::AM::Applets {
+
+enum class CabinetAppletVersion : u32 {
+ Version1 = 0x1,
+};
+
+enum class CabinetResult : u8 {
+ Cancel = 0,
+ TagInfo = 1 << 1,
+ RegisterInfo = 1 << 2,
+ All = TagInfo | RegisterInfo,
+};
+DECLARE_ENUM_FLAG_OPERATORS(CabinetResult)
+
+// This is nn::nfp::AmiiboSettingsStartParam
+struct AmiiboSettingsStartParam {
+ u64 device_handle;
+ std::array<u8, 0x20> param_1;
+ u8 param_2;
+};
+static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
+ "AmiiboSettingsStartParam is an invalid size");
+
+#pragma pack(push, 1)
+// This is nn::nfp::StartParamForAmiiboSettings
+struct StartParamForAmiiboSettings {
+ u8 param_1;
+ Service::NFP::CabinetMode applet_mode;
+ u8 flags;
+ u8 amiibo_settings_1;
+ u64 device_handle;
+ Service::NFP::TagInfo tag_info;
+ Service::NFP::RegisterInfo register_info;
+ std::array<u8, 0x20> amiibo_settings_3;
+ INSERT_PADDING_BYTES(0x24);
+};
+static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8,
+ "StartParamForAmiiboSettings is an invalid size");
+
+// This is nn::nfp::ReturnValueForAmiiboSettings
+struct ReturnValueForAmiiboSettings {
+ CabinetResult result;
+ INSERT_PADDING_BYTES(0x3);
+ u64 device_handle;
+ Service::NFP::TagInfo tag_info;
+ Service::NFP::RegisterInfo register_info;
+ INSERT_PADDING_BYTES(0x24);
+};
+static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
+ "ReturnValueForAmiiboSettings is an invalid size");
+#pragma pack(pop)
+
+class Cabinet final : public Applet {
+public:
+ explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
+ const Core::Frontend::CabinetApplet& frontend_);
+ ~Cabinet() override;
+
+ void Initialize() override;
+
+ bool TransactionComplete() const override;
+ Result GetStatus() const override;
+ void ExecuteInteractive() override;
+ void Execute() override;
+ void DisplayCompleted(bool apply_changes, std::string_view amiibo_name);
+ void Cancel();
+
+private:
+ const Core::Frontend::CabinetApplet& frontend;
+ Core::System& system;
+
+ bool is_complete{false};
+ std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+ Kernel::KEvent* availability_change_event;
+ KernelHelpers::ServiceContext service_context;
+ StartParamForAmiiboSettings applet_input_common{};
+};
+
+} // 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 fcf34bf7e..bae0d99a6 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -144,6 +144,7 @@ void Error::Initialize() {
break;
default:
UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
+ break;
}
}
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp
index c34ef08b3..e50acdaf6 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.cpp
+++ b/src/core/hle/service/am/applets/applet_general_backend.cpp
@@ -129,6 +129,7 @@ void Auth::Execute() {
}
default:
unimplemented_log();
+ break;
}
}
@@ -192,6 +193,7 @@ void PhotoViewer::Execute() {
break;
default:
UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode);
+ break;
}
}
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 7062df21c..10afbc2da 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
#include "common/assert.h"
#include "core/core.h"
+#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
@@ -16,6 +17,7 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
+#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
@@ -171,13 +173,15 @@ void Applet::Initialize() {
AppletFrontendSet::AppletFrontendSet() = default;
-AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
+AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
+ ControllerApplet controller_applet, ErrorApplet error_applet,
MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet,
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
- : controller{std::move(controller_applet)}, error{std::move(error_applet)},
- mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)},
+ : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
+ error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
+ parental_controls{std::move(parental_controls_applet)},
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
@@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
}
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
+ if (set.cabinet != nullptr) {
+ frontend.cabinet = std::move(set.cabinet);
+ }
+
if (set.controller != nullptr) {
frontend.controller = std::move(set.controller);
}
@@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() {
}
void AppletManager::SetDefaultAppletsIfMissing() {
+ if (frontend.cabinet == nullptr) {
+ frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
+ }
+
if (frontend.controller == nullptr) {
frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
@@ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
+ case AppletId::Cabinet:
+ return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
case AppletId::Controller:
return std::make_shared<Controller>(system, mode, *frontend.controller);
case AppletId::Error:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 12c6a5b1a..a22eb62a8 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -16,6 +16,7 @@ class System;
}
namespace Core::Frontend {
+class CabinetApplet;
class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
@@ -176,6 +177,7 @@ protected:
};
struct AppletFrontendSet {
+ using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
@@ -186,10 +188,11 @@ struct AppletFrontendSet {
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
AppletFrontendSet();
- AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
- MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet,
- PhotoViewer photo_viewer_, ProfileSelect profile_select_,
- SoftwareKeyboard software_keyboard_, WebBrowser web_browser_);
+ AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
+ ErrorApplet error_applet, MiiEdit mii_edit_,
+ ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
+ ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
+ WebBrowser web_browser_);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -198,6 +201,7 @@ struct AppletFrontendSet {
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
+ CabinetApplet cabinet;
ControllerApplet controller;
ErrorApplet error;
MiiEdit mii_edit;
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 8ba96583d..26dec7147 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -122,10 +122,10 @@ private:
}
void GetReleasedAudioInBuffer(Kernel::HLERequestContext& ctx) {
- auto write_buffer_size = ctx.GetWriteBufferSize() / sizeof(u64);
- std::vector<u64> released_buffers(write_buffer_size, 0);
+ const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
+ std::vector<u64> released_buffers(write_buffer_size);
- auto count = impl->GetReleasedBuffers(released_buffers);
+ const auto count = impl->GetReleasedBuffers(released_buffers);
[[maybe_unused]] std::string tags{};
for (u32 i = 0; i < count; i++) {
@@ -227,7 +227,7 @@ void AudInU::ListAudioIns(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName));
+ static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
std::vector<AudioDevice::AudioDeviceName> device_names{};
u32 out_count{0};
@@ -247,7 +247,7 @@ void AudInU::ListAudioInsAutoFiltered(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName));
+ static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
std::vector<AudioDevice::AudioDeviceName> device_names{};
u32 out_count{0};
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index eb6bd34b6..991e30ba1 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -128,16 +128,16 @@ private:
}
void GetReleasedAudioOutBuffers(Kernel::HLERequestContext& ctx) {
- auto write_buffer_size = ctx.GetWriteBufferSize() / sizeof(u64);
- std::vector<u64> released_buffers(write_buffer_size, 0);
+ const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
+ std::vector<u64> released_buffers(write_buffer_size);
- auto count = impl->GetReleasedBuffers(released_buffers);
+ const auto count = impl->GetReleasedBuffers(released_buffers);
[[maybe_unused]] std::string tags{};
for (u32 i = 0; i < count; i++) {
tags += fmt::format("{:08X}, ", released_buffers[i]);
}
- [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
+ [[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()};
LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count,
tags);
@@ -242,7 +242,7 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
std::scoped_lock l{impl->mutex};
const auto write_count =
- static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName));
+ static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>());
std::vector<AudioDevice::AudioDeviceName> device_names{};
if (write_count > 0) {
device_names.emplace_back("DeviceOut");
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 615ba1f78..ead16c321 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -14,6 +14,7 @@
#include "common/bit_util.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "common/polyfill_ranges.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
@@ -271,7 +272,7 @@ public:
private:
void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName);
+ const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
std::vector<AudioDevice::AudioDeviceName> out_names{};
@@ -332,7 +333,7 @@ private:
}
void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
- const auto write_size = ctx.GetWriteBufferSize() / sizeof(char);
+ const auto write_size = ctx.GetWriteBufferSize();
std::string out_name{"AudioTvOutput"};
LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);
@@ -384,7 +385,7 @@ private:
}
void ListAudioOutputDeviceName(Kernel::HLERequestContext& ctx) {
- const size_t in_count = ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName);
+ const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
std::vector<AudioDevice::AudioDeviceName> out_names{};
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 8bafc3a98..825fb8bcc 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -68,7 +68,7 @@ private:
ExtraBehavior extra_behavior) {
u32 consumed = 0;
u32 sample_count = 0;
- std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
+ std::vector<opus_int16> samples(ctx.GetWriteBufferNumElements<opus_int16>());
if (extra_behavior == ExtraBehavior::ResetContext) {
ResetDecoderContext();
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index bc08ac487..cbe690a5d 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -443,7 +443,7 @@ private:
}
void Read(Kernel::HLERequestContext& ctx) {
- auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry);
+ auto write_size = ctx.GetWriteBufferNumElements<DeliveryCacheDirectoryEntry>();
LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size);
@@ -533,7 +533,7 @@ private:
}
void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) {
- auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName);
+ auto size = ctx.GetWriteBufferNumElements<DirectoryName>();
LOG_DEBUG(Service_BCAT, "called, size={:016X}", size);
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index ff9b0427c..d183e5829 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -192,12 +192,10 @@ private:
}
void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) {
- u32 out_entries;
- if (keys.GetCommonTickets().empty())
- out_entries = 0;
- else
- out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128));
-
+ size_t out_entries = 0;
+ if (!keys.GetCommonTickets().empty()) {
+ out_entries = ctx.GetWriteBufferNumElements<u128>();
+ }
LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
keys.PopulateTickets();
@@ -206,20 +204,19 @@ private:
std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
[](const auto& pair) { return pair.first; });
- out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries));
+ out_entries = std::min(ids.size(), out_entries);
ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push<u32>(out_entries);
+ rb.Push<u32>(static_cast<u32>(out_entries));
}
void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) {
- u32 out_entries;
- if (keys.GetPersonalizedTickets().empty())
- out_entries = 0;
- else
- out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128));
+ size_t out_entries = 0;
+ if (!keys.GetPersonalizedTickets().empty()) {
+ out_entries = ctx.GetWriteBufferNumElements<u128>();
+ }
LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries);
@@ -229,12 +226,12 @@ private:
std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids),
[](const auto& pair) { return pair.first; });
- out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries));
+ out_entries = std::min(ids.size(), out_entries);
ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128));
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- rb.Push<u32>(out_entries);
+ rb.Push<u32>(static_cast<u32>(out_entries));
}
void GetCommonTicketSize(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index c08274ef9..fbb16a7da 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -277,7 +277,7 @@ private:
LOG_DEBUG(Service_FS, "called.");
// Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
+ 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);
@@ -543,7 +543,7 @@ public:
LOG_DEBUG(Service_FS, "called");
// Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
+ 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);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79375bd2f..bf28440c6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -36,8 +36,9 @@ 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 pad_update_ns is 4ms this is overclocked to lower input lag
-constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
+// 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)
@@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_,
GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
// Register update callbacks
- pad_update_event = Core::Timing::CreateEvent(
+ npad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
[this](std::uintptr_t user_data, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
const auto guard = LockService();
+ UpdateNpad(user_data, ns_late);
+ return std::nullopt;
+ });
+ default_update_event = Core::Timing::CreateEvent(
+ "HID::UpdateDefaultCallback",
+ [this](std::uintptr_t user_data, s64 time,
+ std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
+ const auto guard = LockService();
UpdateControllers(user_data, ns_late);
return std::nullopt;
});
@@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_,
return std::nullopt;
});
- system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event);
+ 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,
@@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) {
}
IAppletResource::~IAppletResource() {
- system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(default_update_event, 0);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
}
@@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
continue;
}
+ // Npad has it's own update event
+ if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
+ continue;
+ }
controller->OnUpdate(core_timing);
}
}
+void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
+}
+
void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 340d26fdc..b7c2a23ef 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -71,12 +71,14 @@ private:
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
KernelHelpers::ServiceContext& service_context;
- std::shared_ptr<Core::Timing::EventType> pad_update_event;
+ 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;
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 6df563136..c49c61cff 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -292,7 +292,7 @@ public:
void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
- const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate);
+ const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1);
if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size,
@@ -333,7 +333,7 @@ public:
const auto channel{rp.PopEnum<WifiChannel>()};
const auto scan_filter{rp.PopRaw<ScanFilter>()};
- const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo);
+ const std::size_t network_info_size = ctx.GetWriteBufferNumElements<NetworkInfo>();
if (network_info_size == 0) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 046c5f18f..2f4bacb3b 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -7,6 +7,7 @@
#include "common/settings.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/nfc/nfc_user.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -97,76 +98,6 @@ private:
}
};
-class IUser final : public ServiceFramework<IUser> {
-public:
- explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IUser::InitializeOld, "InitializeOld"},
- {1, &IUser::FinalizeOld, "FinalizeOld"},
- {2, &IUser::GetStateOld, "GetStateOld"},
- {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"},
- {400, &IUser::InitializeOld, "Initialize"},
- {401, &IUser::FinalizeOld, "Finalize"},
- {402, &IUser::GetStateOld, "GetState"},
- {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"},
- {404, nullptr, "ListDevices"},
- {405, nullptr, "GetDeviceState"},
- {406, nullptr, "GetNpadId"},
- {407, nullptr, "AttachAvailabilityChangeEvent"},
- {408, nullptr, "StartDetection"},
- {409, nullptr, "StopDetection"},
- {410, nullptr, "GetTagInfo"},
- {411, nullptr, "AttachActivateEvent"},
- {412, nullptr, "AttachDeactivateEvent"},
- {1000, nullptr, "ReadMifare"},
- {1001, nullptr, "WriteMifare"},
- {1300, nullptr, "SendCommandByPassThrough"},
- {1301, nullptr, "KeepPassThroughSession"},
- {1302, nullptr, "ReleasePassThroughSession"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- enum class NfcStates : u32 {
- Finalized = 6,
- };
-
- void InitializeOld(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0};
- rb.Push(ResultSuccess);
- // We don't deal with hardware initialization so we can just stub this.
- }
-
- void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw<u8>(true);
- }
-
- void GetStateOld(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFC, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(NfcStates::Finalized); // TODO(ogniK): Figure out if this matches nfp
- }
-
- void FinalizeOld(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NFC, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
-
class NFC_U final : public ServiceFramework<NFC_U> {
public:
explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
new file mode 100644
index 000000000..4d514cf5f
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_device.cpp
@@ -0,0 +1,197 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/input.h"
+#include "common/logging/log.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/ipc_helpers.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/nfc/nfc_device.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_user.h"
+
+namespace Service::NFC {
+NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_)
+ : npad_id{npad_id_}, system{system_}, service_context{service_context_},
+ availability_change_event{availability_change_event_} {
+ activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
+ deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
+ npad_device = system.HIDCore().GetEmulatedController(npad_id);
+
+ Core::HID::ControllerUpdateCallback engine_callback{
+ .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
+ .is_npad_service = false,
+ };
+ is_controller_set = true;
+ callback_key = npad_device->SetCallback(engine_callback);
+}
+
+NfcDevice::~NfcDevice() {
+ activate_event->Close();
+ deactivate_event->Close();
+ if (!is_controller_set) {
+ return;
+ }
+ npad_device->DeleteCallback(callback_key);
+ is_controller_set = false;
+};
+
+void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
+ if (type == Core::HID::ControllerTriggerType::Connected ||
+ type == Core::HID::ControllerTriggerType::Disconnected) {
+ availability_change_event->Signal();
+ return;
+ }
+
+ if (type != Core::HID::ControllerTriggerType::Nfc) {
+ return;
+ }
+
+ if (!npad_device->IsConnected()) {
+ return;
+ }
+
+ const auto nfc_status = npad_device->GetNfc();
+ switch (nfc_status.state) {
+ case Common::Input::NfcState::NewAmiibo:
+ LoadNfcTag(nfc_status.data);
+ break;
+ case Common::Input::NfcState::AmiiboRemoved:
+ if (device_state != NFP::DeviceState::SearchingForTag) {
+ CloseNfcTag();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
+ if (device_state != NFP::DeviceState::SearchingForTag) {
+ LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
+ return false;
+ }
+
+ if (data.size() != sizeof(NFP::EncryptedNTAG215File)) {
+ LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
+ return false;
+ }
+
+ memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+
+ device_state = NFP::DeviceState::TagFound;
+ deactivate_event->GetReadableEvent().Clear();
+ activate_event->Signal();
+ return true;
+}
+
+void NfcDevice::CloseNfcTag() {
+ LOG_INFO(Service_NFC, "Remove nfc tag");
+
+ device_state = NFP::DeviceState::TagRemoved;
+ encrypted_tag_data = {};
+ activate_event->GetReadableEvent().Clear();
+ deactivate_event->Signal();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
+ return activate_event->GetReadableEvent();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
+ return deactivate_event->GetReadableEvent();
+}
+
+void NfcDevice::Initialize() {
+ device_state =
+ npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
+ encrypted_tag_data = {};
+}
+
+void NfcDevice::Finalize() {
+ if (device_state == NFP::DeviceState::SearchingForTag ||
+ device_state == NFP::DeviceState::TagRemoved) {
+ StopDetection();
+ }
+ device_state = NFP::DeviceState::Unavailable;
+}
+
+Result NfcDevice::StartDetection(s32 protocol_) {
+ if (device_state != NFP::DeviceState::Initialized &&
+ device_state != NFP::DeviceState::TagRemoved) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return WrongDeviceState;
+ }
+
+ if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) {
+ LOG_ERROR(Service_NFC, "Nfc not supported");
+ return NfcDisabled;
+ }
+
+ device_state = NFP::DeviceState::SearchingForTag;
+ protocol = protocol_;
+ return ResultSuccess;
+}
+
+Result NfcDevice::StopDetection() {
+ npad_device->SetPollingMode(Common::Input::PollingMode::Active);
+
+ if (device_state == NFP::DeviceState::Initialized) {
+ return ResultSuccess;
+ }
+
+ if (device_state == NFP::DeviceState::TagFound ||
+ device_state == NFP::DeviceState::TagMounted) {
+ CloseNfcTag();
+ return ResultSuccess;
+ }
+ if (device_state == NFP::DeviceState::SearchingForTag ||
+ device_state == NFP::DeviceState::TagRemoved) {
+ device_state = NFP::DeviceState::Initialized;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return WrongDeviceState;
+}
+
+Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
+ if (device_state != NFP::DeviceState::TagFound &&
+ device_state != NFP::DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == NFP::DeviceState::TagRemoved) {
+ return TagRemoved;
+ }
+ return WrongDeviceState;
+ }
+
+ // Protocol and tag type may change here
+ tag_info = {
+ .uuid = encrypted_tag_data.uuid.uid,
+ .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
+ .protocol = NFP::TagProtocol::TypeA,
+ .tag_type = NFP::TagType::Type2,
+ };
+
+ return ResultSuccess;
+}
+
+u64 NfcDevice::GetHandle() const {
+ // Generate a handle based of the npad id
+ return static_cast<u64>(npad_id);
+}
+
+NFP::DeviceState NfcDevice::GetCurrentState() const {
+ return device_state;
+}
+
+Core::HID::NpadIdType NfcDevice::GetNpadId() const {
+ return npad_id;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h
new file mode 100644
index 000000000..fa1348f1a
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_device.h
@@ -0,0 +1,70 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Core::HID {
+class EmulatedController;
+enum class ControllerTriggerType;
+enum class NpadIdType : u32;
+} // namespace Core::HID
+
+namespace Service::NFC {
+class NfcDevice {
+public:
+ NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_);
+ ~NfcDevice();
+
+ void Initialize();
+ void Finalize();
+
+ Result StartDetection(s32 protocol_);
+ Result StopDetection();
+
+ Result GetTagInfo(NFP::TagInfo& tag_info) const;
+
+ u64 GetHandle() const;
+ NFP::DeviceState GetCurrentState() const;
+ Core::HID::NpadIdType GetNpadId() const;
+
+ Kernel::KReadableEvent& GetActivateEvent() const;
+ Kernel::KReadableEvent& GetDeactivateEvent() const;
+
+private:
+ void NpadUpdate(Core::HID::ControllerTriggerType type);
+ bool LoadNfcTag(std::span<const u8> data);
+ void CloseNfcTag();
+
+ bool is_controller_set{};
+ int callback_key;
+ const Core::HID::NpadIdType npad_id;
+ Core::System& system;
+ Core::HID::EmulatedController* npad_device = nullptr;
+ KernelHelpers::ServiceContext& service_context;
+ Kernel::KEvent* activate_event = nullptr;
+ Kernel::KEvent* deactivate_event = nullptr;
+ Kernel::KEvent* availability_change_event = nullptr;
+
+ s32 protocol{};
+ NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
+
+ NFP::EncryptedNTAG215File encrypted_tag_data{};
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
new file mode 100644
index 000000000..537dc15f4
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::NFC {
+
+constexpr Result DeviceNotFound(ErrorModule::NFC, 64);
+constexpr Result InvalidArgument(ErrorModule::NFC, 65);
+constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
+constexpr Result NfcDisabled(ErrorModule::NFC, 80);
+constexpr Result TagRemoved(ErrorModule::NFC, 97);
+constexpr Result CorruptedData(ErrorModule::NFC, 144);
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp
new file mode 100644
index 000000000..ced2d560b
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_user.cpp
@@ -0,0 +1,365 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/nfc/nfc_device.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_user.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+IUser::IUser(Core::System& system_)
+ : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
+ static const FunctionInfo functions[] = {
+ {0, &IUser::Initialize, "InitializeOld"},
+ {1, &IUser::Finalize, "FinalizeOld"},
+ {2, &IUser::GetState, "GetStateOld"},
+ {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
+ {400, &IUser::Initialize, "Initialize"},
+ {401, &IUser::Finalize, "Finalize"},
+ {402, &IUser::GetState, "GetState"},
+ {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
+ {404, &IUser::ListDevices, "ListDevices"},
+ {405, &IUser::GetDeviceState, "GetDeviceState"},
+ {406, &IUser::GetNpadId, "GetNpadId"},
+ {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {408, &IUser::StartDetection, "StartDetection"},
+ {409, &IUser::StopDetection, "StopDetection"},
+ {410, &IUser::GetTagInfo, "GetTagInfo"},
+ {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
+ {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {1000, nullptr, "ReadMifare"},
+ {1001, nullptr, "WriteMifare"},
+ {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ RegisterHandlers(functions);
+
+ availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
+
+ for (u32 device_index = 0; device_index < 10; device_index++) {
+ devices[device_index] =
+ std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
+ service_context, availability_change_event);
+ }
+}
+
+IUser ::~IUser() {
+ availability_change_event->Close();
+}
+
+void IUser::Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ state = State::Initialized;
+
+ for (auto& device : devices) {
+ device->Initialize();
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0};
+ rb.Push(ResultSuccess);
+}
+
+void IUser::Finalize(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ state = State::NonInitialized;
+
+ for (auto& device : devices) {
+ device->Finalize();
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IUser::GetState(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(state);
+}
+
+void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(state != State::NonInitialized);
+}
+
+void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ if (!ctx.CanWriteBuffer()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(InvalidArgument);
+ return;
+ }
+
+ if (ctx.GetWriteBufferSize() == 0) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(InvalidArgument);
+ return;
+ }
+
+ std::vector<u64> nfp_devices;
+ const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
+
+ for (auto& device : devices) {
+ if (nfp_devices.size() >= max_allowed_devices) {
+ continue;
+ }
+ if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
+ nfp_devices.push_back(device->GetHandle());
+ }
+ }
+
+ if (nfp_devices.empty()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ ctx.WriteBuffer(nfp_devices);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<s32>(nfp_devices.size()));
+}
+
+void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(device.value()->GetCurrentState());
+}
+
+void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(device.value()->GetNpadId());
+}
+
+void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(availability_change_event->GetReadableEvent());
+}
+
+void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto nfp_protocol{rp.Pop<s32>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ const auto result = device.value()->StartDetection(nfp_protocol);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ const auto result = device.value()->StopDetection();
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ NFP::TagInfo tag_info{};
+ const auto result = device.value()->GetTagInfo(tag_info);
+ ctx.WriteBuffer(tag_info);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(device.value()->GetActivateEvent());
+}
+
+void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(device.value()->GetDeactivateEvent());
+}
+
+void IUser::SendCommandByPassThrough(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
+ const auto command_data{ctx.ReadBuffer()};
+
+ LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
+ device_handle, timeout.ToSeconds(), command_data.size());
+
+ if (state == State::NonInitialized) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(NfcDisabled);
+ return;
+ }
+
+ auto device = GetNfcDevice(device_handle);
+
+ if (!device.has_value()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(DeviceNotFound);
+ return;
+ }
+
+ std::vector<u8> out_data(1);
+ // TODO: Request data from nfc device
+ ctx.WriteBuffer(out_data);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<u32>(out_data.size()));
+}
+
+std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_user.h
new file mode 100644
index 000000000..a5a4f12f9
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_user.h
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <optional>
+
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Service::NFC {
+class NfcDevice;
+
+class IUser final : public ServiceFramework<IUser> {
+public:
+ explicit IUser(Core::System& system_);
+ ~IUser();
+
+private:
+ enum class State : u32 {
+ NonInitialized,
+ Initialized,
+ };
+
+ void Initialize(Kernel::HLERequestContext& ctx);
+ void Finalize(Kernel::HLERequestContext& ctx);
+ void GetState(Kernel::HLERequestContext& ctx);
+ void IsNfcEnabled(Kernel::HLERequestContext& ctx);
+ void ListDevices(Kernel::HLERequestContext& ctx);
+ void GetDeviceState(Kernel::HLERequestContext& ctx);
+ void GetNpadId(Kernel::HLERequestContext& ctx);
+ void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
+ void StartDetection(Kernel::HLERequestContext& ctx);
+ void StopDetection(Kernel::HLERequestContext& ctx);
+ void GetTagInfo(Kernel::HLERequestContext& ctx);
+ void AttachActivateEvent(Kernel::HLERequestContext& ctx);
+ void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
+ void SendCommandByPassThrough(Kernel::HLERequestContext& ctx);
+
+ std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
+
+ KernelHelpers::ServiceContext service_context;
+
+ std::array<std::shared_ptr<NfcDevice>, 10> devices{};
+
+ State state{State::NonInitialized};
+ Kernel::KEvent* availability_change_event;
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp
index 167e29572..ffb2f959c 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfp/amiibo_crypto.cpp
@@ -12,7 +12,6 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
-#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfp/amiibo_crypto.h"
namespace Service::NFP::AmiiboCrypto {
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
index b19672560..c860fd1a1 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfp/nfp_device.cpp
@@ -2,10 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
-#include <atomic>
-#include "common/fs/file.h"
-#include "common/fs/path_util.h"
#include "common/input.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -19,7 +16,6 @@
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/mii/types.h"
#include "core/hle/service/nfp/amiibo_crypto.h"
-#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nfp/nfp_device.h"
#include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/nfp/nfp_user.h"
@@ -49,6 +45,8 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
}
NfpDevice::~NfpDevice() {
+ activate_event->Close();
+ deactivate_event->Close();
if (!is_controller_set) {
return;
}
@@ -77,6 +75,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
LoadAmiibo(nfc_status.data);
break;
case Common::Input::NfcState::AmiiboRemoved:
+ if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
+ break;
+ }
if (device_state != DeviceState::SearchingForTag) {
CloseAmiibo();
}
@@ -97,6 +98,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
return false;
}
+ // TODO: Filter by allowed_protocols here
+
memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
device_state = DeviceState::TagFound;
@@ -143,7 +146,7 @@ void NfpDevice::Finalize() {
device_state = DeviceState::Unavailable;
}
-Result NfpDevice::StartDetection(s32 protocol_) {
+Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
return WrongDeviceState;
@@ -155,7 +158,7 @@ Result NfpDevice::StartDetection(s32 protocol_) {
}
device_state = DeviceState::SearchingForTag;
- protocol = protocol_;
+ allowed_protocols = allowed_protocol;
return ResultSuccess;
}
@@ -469,6 +472,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
return ResultSuccess;
}
+Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
+ application_area_id = {};
+
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return TagRemoved;
+ }
+ return WrongDeviceState;
+ }
+
+ if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return WrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
+ LOG_WARNING(Service_NFP, "Application area is not initialized");
+ return ApplicationAreaIsNotInitialized;
+ }
+
+ application_area_id = tag_data.application_area_id;
+
+ return ResultSuccess;
+}
+
Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
if (device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
index 76d0e9ae4..b6a46f2ac 100644
--- a/src/core/hle/service/nfp/nfp_device.h
+++ b/src/core/hle/service/nfp/nfp_device.h
@@ -3,10 +3,10 @@
#pragma once
-#include <array>
+#include <span>
#include <vector>
-#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
@@ -37,7 +37,7 @@ public:
void Initialize();
void Finalize();
- Result StartDetection(s32 protocol_);
+ Result StartDetection(TagProtocol allowed_protocol);
Result StopDetection();
Result Mount(MountTarget mount_target);
Result Unmount();
@@ -53,6 +53,7 @@ public:
Result DeleteAllData();
Result OpenApplicationArea(u32 access_id);
+ Result GetApplicationAreaId(u32& application_area_id) const;
Result GetApplicationArea(std::vector<u8>& data) const;
Result SetApplicationArea(std::span<const u8> data);
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
@@ -88,7 +89,7 @@ private:
bool is_data_moddified{};
bool is_app_area_open{};
- s32 protocol{};
+ TagProtocol allowed_protocols{};
s64 current_posix_time{};
MountTarget mount_target{MountTarget::None};
DeviceState device_state{DeviceState::Unavailable};
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 63d5917cb..69858096a 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -88,11 +88,22 @@ enum class PackedTagType : u8 {
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
+// Verify this enum. It might be completely wrong default protocol is 0x48
enum class TagProtocol : u32 {
None,
- TypeA, // ISO14443A
- TypeB, // ISO14443B
- TypeF, // Sony Felica
+ TypeA = 1U << 0, // ISO14443A
+ TypeB = 1U << 1, // ISO14443B
+ TypeF = 1U << 2, // Sony Felica
+ Unknown1 = 1U << 3,
+ Unknown2 = 1U << 5,
+ All = 0xFFFFFFFFU,
+};
+
+enum class CabinetMode : u8 {
+ StartNicknameAndOwnerSettings,
+ StartGameDataEraser,
+ StartRestorer,
+ StartFormatter,
};
using UniqueSerialNumber = std::array<u8, 7>;
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 33e2ef518..49816b4c7 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <array>
-#include <atomic>
-
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hid/hid_types.h"
@@ -55,8 +52,12 @@ IUser::IUser(Core::System& system_)
}
}
+IUser ::~IUser() {
+ availability_change_event->Close();
+}
+
void IUser::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
+ LOG_INFO(Service_NFP, "called");
state = State::Initialized;
@@ -64,7 +65,7 @@ void IUser::Initialize(Kernel::HLERequestContext& ctx) {
device->Initialize();
}
- IPC::ResponseBuilder rb{ctx, 2, 0};
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
@@ -103,9 +104,9 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
}
std::vector<u64> nfp_devices;
- const std::size_t max_allowed_devices = ctx.GetWriteBufferSize() / sizeof(u64);
+ const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
- for (auto& device : devices) {
+ for (const auto& device : devices) {
if (nfp_devices.size() >= max_allowed_devices) {
continue;
}
@@ -114,7 +115,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
}
}
- if (nfp_devices.size() == 0) {
+ if (nfp_devices.empty()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(DeviceNotFound);
return;
@@ -130,7 +131,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
- const auto nfp_protocol{rp.Pop<s32>()};
+ const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
if (state == State::NonInitialized) {
@@ -551,9 +552,9 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
}
void IUser::GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
+ LOG_DEBUG(Service_NFP, "called");
- IPC::ResponseBuilder rb{ctx, 3, 0};
+ IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 47aff3695..7e9a90af8 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -3,6 +3,10 @@
#pragma once
+#include <array>
+#include <memory>
+#include <optional>
+
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
@@ -12,6 +16,7 @@ class NfpDevice;
class IUser final : public ServiceFramework<IUser> {
public:
explicit IUser(Core::System& system_);
+ ~IUser();
private:
enum class State : u32 {
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index e3ef06481..4fa9f51a6 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -129,6 +129,9 @@ static_assert(sizeof(NifmNetworkProfileData) == 0x18E,
"NifmNetworkProfileData has incorrect size.");
#pragma pack(pop)
+constexpr Result ResultPendingConnection{ErrorModule::NIFM, 111};
+constexpr Result ResultNetworkCommunicationDisabled{ErrorModule::NIFM, 1111};
+
class IScanRequest final : public ServiceFramework<IScanRequest> {
public:
explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} {
@@ -192,6 +195,10 @@ private:
void Submit(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ if (state == RequestState::NotSubmitted) {
+ UpdateState(RequestState::Pending);
+ }
+
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
@@ -201,19 +208,32 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
-
- if (Network::GetHostIPv4Address().has_value()) {
- rb.PushEnum(RequestState::Connected);
- } else {
- rb.PushEnum(RequestState::NotSubmitted);
- }
+ rb.PushEnum(state);
}
void GetResult(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ const auto result = [this] {
+ const auto has_connection = Network::GetHostIPv4Address().has_value();
+ switch (state) {
+ case RequestState::NotSubmitted:
+ return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled;
+ case RequestState::Pending:
+ if (has_connection) {
+ UpdateState(RequestState::Connected);
+ } else {
+ UpdateState(RequestState::Error);
+ }
+ return ResultPendingConnection;
+ case RequestState::Connected:
+ default:
+ return ResultSuccess;
+ }
+ }();
+
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
}
void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
@@ -252,8 +272,15 @@ private:
rb.Push<u32>(0);
}
+ void UpdateState(RequestState new_state) {
+ state = new_state;
+ event1->Signal();
+ }
+
KernelHelpers::ServiceContext service_context;
+ RequestState state;
+
Kernel::KEvent* event1;
Kernel::KEvent* event2;
};
diff --git a/src/core/hle/service/ns/iplatform_service_manager.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp
index fd047ff26..1fab2f0dd 100644
--- a/src/core/hle/service/ns/iplatform_service_manager.cpp
+++ b/src/core/hle/service/ns/iplatform_service_manager.cpp
@@ -279,13 +279,10 @@ void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestC
font_sizes.push_back(region.size);
}
- // Resize buffers if game requests smaller size output.
- font_codes.resize(
- std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32)));
- font_offsets.resize(
- std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32)));
- font_sizes.resize(
- std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32)));
+ // Resize buffers if game requests smaller size output
+ font_codes.resize(std::min(font_codes.size(), ctx.GetWriteBufferNumElements<u32>(0)));
+ font_offsets.resize(std::min(font_offsets.size(), ctx.GetWriteBufferNumElements<u32>(1)));
+ font_sizes.resize(std::min(font_sizes.size(), ctx.GetWriteBufferNumElements<u32>(2)));
ctx.WriteBuffer(font_codes, 0);
ctx.WriteBuffer(font_offsets, 1);
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
index eda2041a0..aba51d280 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
@@ -28,13 +28,15 @@ SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host
SyncpointManager::~SyncpointManager() = default;
u32 SyncpointManager::ReserveSyncpoint(u32 id, bool client_managed) {
- if (syncpoints.at(id).reserved) {
+ auto& syncpoint = syncpoints.at(id);
+
+ if (syncpoint.reserved) {
ASSERT_MSG(false, "Requested syncpoint is in use");
return 0;
}
- syncpoints.at(id).reserved = true;
- syncpoints.at(id).interface_managed = client_managed;
+ syncpoint.reserved = true;
+ syncpoint.interface_managed = client_managed;
return id;
}
@@ -56,11 +58,12 @@ u32 SyncpointManager::AllocateSyncpoint(bool client_managed) {
void SyncpointManager::FreeSyncpoint(u32 id) {
std::lock_guard lock(reservation_lock);
- ASSERT(syncpoints.at(id).reserved);
- syncpoints.at(id).reserved = false;
+ auto& syncpoint = syncpoints.at(id);
+ ASSERT(syncpoint.reserved);
+ syncpoint.reserved = false;
}
-bool SyncpointManager::IsSyncpointAllocated(u32 id) {
+bool SyncpointManager::IsSyncpointAllocated(u32 id) const {
return (id <= SyncpointCount) && syncpoints[id].reserved;
}
@@ -69,7 +72,7 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const {
if (!syncpoint.reserved) {
ASSERT(false);
- return 0;
+ return false;
}
// If the interface manages counters then we don't keep track of the maximum value as it handles
@@ -82,40 +85,51 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const {
}
u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) {
- if (!syncpoints.at(id).reserved) {
+ auto& syncpoint = syncpoints.at(id);
+
+ if (!syncpoint.reserved) {
ASSERT(false);
return 0;
}
- return syncpoints.at(id).counter_max += amount;
+ return syncpoint.counter_max += amount;
}
u32 SyncpointManager::ReadSyncpointMinValue(u32 id) {
- if (!syncpoints.at(id).reserved) {
+ auto& syncpoint = syncpoints.at(id);
+
+ if (!syncpoint.reserved) {
ASSERT(false);
return 0;
}
- return syncpoints.at(id).counter_min;
+ return syncpoint.counter_min;
}
u32 SyncpointManager::UpdateMin(u32 id) {
- if (!syncpoints.at(id).reserved) {
+ auto& syncpoint = syncpoints.at(id);
+
+ if (!syncpoint.reserved) {
ASSERT(false);
return 0;
}
- syncpoints.at(id).counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id);
- return syncpoints.at(id).counter_min;
+ syncpoint.counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id);
+ return syncpoint.counter_min;
}
NvFence SyncpointManager::GetSyncpointFence(u32 id) {
- if (!syncpoints.at(id).reserved) {
+ auto& syncpoint = syncpoints.at(id);
+
+ if (!syncpoint.reserved) {
ASSERT(false);
return NvFence{};
}
- return {.id = static_cast<s32>(id), .value = syncpoints.at(id).counter_max};
+ return {
+ .id = static_cast<s32>(id),
+ .value = syncpoint.counter_max,
+ };
}
} // namespace Service::Nvidia::NvCore
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
index b76ef9032..4f2cefae5 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
@@ -44,7 +44,7 @@ public:
/**
* @brief Checks if the given syncpoint is both allocated and below the number of HW syncpoints
*/
- bool IsSyncpointAllocated(u32 id);
+ bool IsSyncpointAllocated(u32 id) const;
/**
* @brief Finds a free syncpoint and reserves it
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 ced57dfe6..b97813fbc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {
return error_notifier_event;
case 2:
return unknown_event;
- default: {
+ default:
LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
+ return nullptr;
}
- }
- return nullptr;
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 45a759fa8..e123564c6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) {
return sm_exception_breakpoint_pause_report_event;
case 3:
return error_notifier_event;
- default: {
+ default:
LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
+ return nullptr;
}
- }
- return nullptr;
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 9f4c7c99a..6fc8565c0 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -55,48 +55,40 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
Module::Module(Core::System& system)
: container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} {
builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_as_gpu>(system, *this, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_as_gpu>(system, *this, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_gpu>(system, events_interface, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_gpu>(system, events_interface, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvmap"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvmap>(system, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvmap>(system, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvdisp_disp0>(system, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvdisp_disp0>(system, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_nvdec>(system, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_nvdec>(system, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_nvjpg>(system);
+ return open_files.emplace(fd, std::move(device)).first;
};
builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) {
- std::shared_ptr<Devices::nvdevice> device =
- std::make_shared<Devices::nvhost_vic>(system, container);
- return open_files.emplace(fd, device).first;
+ auto device = std::make_shared<Devices::nvhost_vic>(system, container);
+ return open_files.emplace(fd, std::move(device)).first;
};
}
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
index 6d2c92a2c..152bb5bdf 100644
--- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
@@ -39,7 +39,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco
return Status::NoError;
}
-Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) {
+Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, const Fence& release_fence) {
std::scoped_lock lock{mutex};
if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h
index 69046233d..a5c655d9e 100644
--- a/src/core/hle/service/nvflinger/buffer_item_consumer.h
+++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h
@@ -22,7 +22,7 @@ public:
explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer);
Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when,
bool wait_for_fence = true);
- Status ReleaseBuffer(const BufferItem& item, Fence& release_fence);
+ Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence);
};
} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
index 1ce67c771..0767e548d 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
@@ -169,7 +169,7 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
return Status::NoInit;
}
- core->consumer_listener = consumer_listener;
+ core->consumer_listener = std::move(consumer_listener);
core->consumer_controlled_by_app = controlled_by_app;
return Status::NoError;
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
index ea4a14ea4..3d1338e66 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() {
}
void BufferQueueCore::SignalDequeueCondition() {
+ dequeue_possible.store(true);
dequeue_condition.notify_all();
}
-bool BufferQueueCore::WaitForDequeueCondition() {
+bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
if (is_shutting_down) {
return false;
}
- dequeue_condition.wait(mutex);
+ dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
+ dequeue_possible.store(false);
return true;
}
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
index ca6baefaf..85b3bc4c1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -38,7 +38,7 @@ public:
private:
void SignalDequeueCondition();
- bool WaitForDequeueCondition();
+ bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
s32 GetMinUndequeuedBufferCountLocked(bool async) const;
s32 GetMinMaxBufferCountLocked(bool async) const;
@@ -60,7 +60,8 @@ private:
BufferQueueDefs::SlotsType slots{};
std::vector<BufferItem> queue;
s32 override_max_buffer_count{};
- mutable std::condition_variable_any dequeue_condition;
+ std::condition_variable dequeue_condition;
+ std::atomic<bool> dequeue_possible{};
const bool use_async_buffer{}; // This is always disabled on HOS
bool dequeue_buffer_cannot_block{};
PixelFormat default_buffer_format{PixelFormat::Rgba8888};
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index 41ba44b21..e601b5da1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
return Status::NoError;
}
-Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
- Status* return_flags) const {
+Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
+ std::unique_lock<std::mutex>& lk) const {
bool try_again = true;
while (try_again) {
@@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
return Status::WouldBlock;
}
- if (!core->WaitForDequeueCondition()) {
+ if (!core->WaitForDequeueCondition(lk)) {
// We are no longer running
return Status::NoError;
}
@@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
Status return_flags = Status::NoError;
bool attached_by_consumer = false;
{
- std::scoped_lock lock{core->mutex};
+ std::unique_lock lock{core->mutex};
core->WaitWhileAllocatingLocked();
if (format == PixelFormat::NoFormat) {
@@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
usage |= core->consumer_usage_bit;
s32 found{};
- Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags);
+ Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock);
if (status != Status::NoError) {
return status;
}
@@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
return Status::BadValue;
}
- std::scoped_lock lock{core->mutex};
+ std::unique_lock lock{core->mutex};
core->WaitWhileAllocatingLocked();
Status return_flags = Status::NoError;
s32 found{};
- const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags);
+ const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock);
if (status != Status::NoError) {
return status;
}
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
index 7526bf8ec..1d380480f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -70,7 +70,8 @@ public:
private:
BufferQueueProducer(const BufferQueueProducer&) = delete;
- Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const;
+ Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
+ std::unique_lock<std::mutex>& lk) const;
Kernel::KEvent* buffer_wait_event{};
Service::KernelHelpers::ServiceContext& service_context;
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp
index 5b9995854..982531e2d 100644
--- a/src/core/hle/service/nvflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvflinger/consumer_base.cpp
@@ -83,7 +83,7 @@ Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseco
}
Status ConsumerBase::AddReleaseFenceLocked(s32 slot,
- const std::shared_ptr<GraphicBuffer> graphic_buffer,
+ const std::shared_ptr<GraphicBuffer>& graphic_buffer,
const Fence& fence) {
LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
@@ -100,7 +100,7 @@ Status ConsumerBase::AddReleaseFenceLocked(s32 slot,
}
Status ConsumerBase::ReleaseBufferLocked(s32 slot,
- const std::shared_ptr<GraphicBuffer> graphic_buffer) {
+ const std::shared_ptr<GraphicBuffer>& graphic_buffer) {
// If consumer no longer tracks this graphic_buffer (we received a new
// buffer on the same slot), the buffer producer is definitely no longer
// tracking it.
@@ -121,7 +121,7 @@ Status ConsumerBase::ReleaseBufferLocked(s32 slot,
}
bool ConsumerBase::StillTracking(s32 slot,
- const std::shared_ptr<GraphicBuffer> graphic_buffer) const {
+ const std::shared_ptr<GraphicBuffer>& graphic_buffer) const {
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
return false;
}
diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h
index 90ba07f45..9a8a5f6bb 100644
--- a/src/core/hle/service/nvflinger/consumer_base.h
+++ b/src/core/hle/service/nvflinger/consumer_base.h
@@ -27,18 +27,18 @@ public:
protected:
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
- virtual ~ConsumerBase();
+ ~ConsumerBase() override;
- virtual void OnFrameAvailable(const BufferItem& item) override;
- virtual void OnFrameReplaced(const BufferItem& item) override;
- virtual void OnBuffersReleased() override;
- virtual void OnSidebandStreamChanged() override;
+ void OnFrameAvailable(const BufferItem& item) override;
+ void OnFrameReplaced(const BufferItem& item) override;
+ void OnBuffersReleased() override;
+ void OnSidebandStreamChanged() override;
void FreeBufferLocked(s32 slot_index);
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
- Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer);
- bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const;
- Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer,
+ Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer);
+ bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer) const;
+ Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer,
const Fence& fence);
struct Slot final {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index c3af12c90..d1cbadde4 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -307,8 +307,7 @@ void NVFlinger::Compose() {
swap_interval = buffer.swap_interval;
- auto fence = android::Fence::NoFence();
- layer.GetConsumer().ReleaseBuffer(buffer, fence);
+ layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence());
}
}
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 460bef976..9b22397db 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -11,6 +11,7 @@
#include <vector>
#include "common/common_types.h"
+#include "common/polyfill_thread.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h
index 1c4d5db0e..6bf8aaf1e 100644
--- a/src/core/hle/service/nvflinger/producer_listener.h
+++ b/src/core/hle/service/nvflinger/producer_listener.h
@@ -10,6 +10,7 @@ namespace Service::android {
class IProducerListener {
public:
+ virtual ~IProducerListener() = default;
virtual void OnBufferReleased() = 0;
};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 5ab41c0c4..0de67f1e1 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
}
UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
+ break;
}
// If emulation was shutdown, we are closing service threads, do not write the response back to
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index f761c2da4..4f1a8d6b7 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -83,7 +83,7 @@ void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_la
}
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) {
- const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode);
+ 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);
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 2aa675df9..f9ada7c93 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {
}
default:
ASSERT(false);
+ break;
}
return value + rule.transition_time + offset;
}