diff options
Diffstat (limited to 'src/core/hle/service/nfc')
-rw-r--r-- | src/core/hle/service/nfc/nfc.cpp | 71 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_device.cpp | 197 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_device.h | 70 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_result.h | 17 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_user.cpp | 365 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_user.h | 52 |
6 files changed, 702 insertions, 70 deletions
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..0753333bf --- /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.GetWriteBufferSize() / sizeof(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 |