diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 5 | ||||
| -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 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/amiibo_crypto.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_user.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_user.h | 5 | 
12 files changed, 723 insertions, 84 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f67f1ce92..705667080 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -526,6 +526,11 @@ add_library(core STATIC      hle/service/ncm/ncm.h      hle/service/nfc/nfc.cpp      hle/service/nfc/nfc.h +    hle/service/nfc/nfc_device.cpp +    hle/service/nfc/nfc_device.h +    hle/service/nfc/nfc_result.h +    hle/service/nfc/nfc_user.cpp +    hle/service/nfc/nfc_user.h      hle/service/nfp/amiibo_crypto.cpp      hle/service/nfp/amiibo_crypto.h      hle/service/nfp/nfp.cpp 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 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..296603764 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;      } diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 76d0e9ae4..6d8fc1099 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -3,10 +3,9 @@  #pragma once -#include <array>  #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" diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 33e2ef518..3f7f17598 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);  } @@ -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 { | 
