mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Added Amiibo support (#1390)
* Fixed conflict with nfp * Few fixups for nfc * Conflict 2 * Fixed AttachAvailabilityChangeEvent * Conflict 3 * Fixed byte padding * Refactored amiibo to not reside in "System" * Removed remaining references of nfc from system * used enum for Nfc GetStateOld * Added missing newline * Moved file operations to front end * Conflict 4 * Amiibos now use structs and added mutexes * Removed amiibo_path
This commit is contained in:
		
							parent
							
								
									5edb2403c2
								
							
						
					
					
						commit
						50e4e81fd3
					
				@ -10,12 +10,13 @@
 | 
			
		||||
#include "core/hle/service/nfc/nfc.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::NFC {
 | 
			
		||||
 | 
			
		||||
class IAm final : public ServiceFramework<IAm> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IAm() : ServiceFramework{"IAm"} {
 | 
			
		||||
    explicit IAm() : ServiceFramework{"NFC::IAm"} {
 | 
			
		||||
        // clang-format off
 | 
			
		||||
        static const FunctionInfo functions[] = {
 | 
			
		||||
            {0, nullptr, "Initialize"},
 | 
			
		||||
@ -52,7 +53,7 @@ private:
 | 
			
		||||
 | 
			
		||||
class MFIUser final : public ServiceFramework<MFIUser> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit MFIUser() : ServiceFramework{"IUser"} {
 | 
			
		||||
    explicit MFIUser() : ServiceFramework{"NFC::MFIUser"} {
 | 
			
		||||
        // clang-format off
 | 
			
		||||
        static const FunctionInfo functions[] = {
 | 
			
		||||
            {0, nullptr, "Initialize"},
 | 
			
		||||
@ -100,13 +101,13 @@ private:
 | 
			
		||||
 | 
			
		||||
class IUser final : public ServiceFramework<IUser> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IUser() : ServiceFramework{"IUser"} {
 | 
			
		||||
    explicit IUser() : ServiceFramework{"NFC::IUser"} {
 | 
			
		||||
        // clang-format off
 | 
			
		||||
        static const FunctionInfo functions[] = {
 | 
			
		||||
            {0, nullptr, "Initialize"},
 | 
			
		||||
            {1, nullptr, "Finalize"},
 | 
			
		||||
            {2, nullptr, "GetState"},
 | 
			
		||||
            {3, nullptr, "IsNfcEnabled"},
 | 
			
		||||
            {0, &IUser::InitializeOld, "InitializeOld"},
 | 
			
		||||
            {1, &IUser::FinalizeOld, "FinalizeOld"},
 | 
			
		||||
            {2, &IUser::GetStateOld, "GetStateOld"},
 | 
			
		||||
            {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"},
 | 
			
		||||
            {400, nullptr, "Initialize"},
 | 
			
		||||
            {401, nullptr, "Finalize"},
 | 
			
		||||
            {402, nullptr, "GetState"},
 | 
			
		||||
@ -130,11 +131,47 @@ public:
 | 
			
		||||
 | 
			
		||||
        RegisterHandlers(functions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    enum class NfcStates : u32 {
 | 
			
		||||
        Finalized = 6,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void InitializeOld(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2, 0};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
        // We don't deal with hardware initialization so we can just stub this.
 | 
			
		||||
        LOG_DEBUG(Service_NFC, "called");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushRaw<u8>(Settings::values.enable_nfc);
 | 
			
		||||
 | 
			
		||||
        LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetStateOld(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFC, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        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(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class NFC_U final : public ServiceFramework<NFC_U> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit NFC_U() : ServiceFramework{"nfc:u"} {
 | 
			
		||||
    explicit NFC_U() : ServiceFramework{"nfc:user"} {
 | 
			
		||||
        // clang-format off
 | 
			
		||||
        static const FunctionInfo functions[] = {
 | 
			
		||||
            {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
 | 
			
		||||
 | 
			
		||||
@ -2,56 +2,67 @@
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
#include "core/hle/kernel/event.h"
 | 
			
		||||
#include "core/hle/lock.h"
 | 
			
		||||
#include "core/hle/service/hid/hid.h"
 | 
			
		||||
#include "core/hle/service/nfp/nfp.h"
 | 
			
		||||
#include "core/hle/service/nfp/nfp_user.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::NFP {
 | 
			
		||||
 | 
			
		||||
namespace ErrCodes {
 | 
			
		||||
constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
 | 
			
		||||
                                    -1); // TODO(ogniK): Find the actual error code
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
 | 
			
		||||
    : ServiceFramework(name), module(std::move(module)) {}
 | 
			
		||||
    : ServiceFramework(name), module(std::move(module)) {
 | 
			
		||||
    auto& kernel = Core::System::GetInstance().Kernel();
 | 
			
		||||
    nfc_tag_load =
 | 
			
		||||
        Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Module::Interface::~Interface() = default;
 | 
			
		||||
 | 
			
		||||
class IUser final : public ServiceFramework<IUser> {
 | 
			
		||||
public:
 | 
			
		||||
    IUser() : ServiceFramework("IUser") {
 | 
			
		||||
    IUser(Module::Interface& nfp_interface)
 | 
			
		||||
        : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) {
 | 
			
		||||
        static const FunctionInfo functions[] = {
 | 
			
		||||
            {0, &IUser::Initialize, "Initialize"},
 | 
			
		||||
            {1, nullptr, "Finalize"},
 | 
			
		||||
            {1, &IUser::Finalize, "Finalize"},
 | 
			
		||||
            {2, &IUser::ListDevices, "ListDevices"},
 | 
			
		||||
            {3, nullptr, "StartDetection"},
 | 
			
		||||
            {4, nullptr, "StopDetection"},
 | 
			
		||||
            {5, nullptr, "Mount"},
 | 
			
		||||
            {6, nullptr, "Unmount"},
 | 
			
		||||
            {7, nullptr, "OpenApplicationArea"},
 | 
			
		||||
            {8, nullptr, "GetApplicationArea"},
 | 
			
		||||
            {3, &IUser::StartDetection, "StartDetection"},
 | 
			
		||||
            {4, &IUser::StopDetection, "StopDetection"},
 | 
			
		||||
            {5, &IUser::Mount, "Mount"},
 | 
			
		||||
            {6, &IUser::Unmount, "Unmount"},
 | 
			
		||||
            {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
 | 
			
		||||
            {8, &IUser::GetApplicationArea, "GetApplicationArea"},
 | 
			
		||||
            {9, nullptr, "SetApplicationArea"},
 | 
			
		||||
            {10, nullptr, "Flush"},
 | 
			
		||||
            {11, nullptr, "Restore"},
 | 
			
		||||
            {12, nullptr, "CreateApplicationArea"},
 | 
			
		||||
            {13, nullptr, "GetTagInfo"},
 | 
			
		||||
            {14, nullptr, "GetRegisterInfo"},
 | 
			
		||||
            {15, nullptr, "GetCommonInfo"},
 | 
			
		||||
            {16, nullptr, "GetModelInfo"},
 | 
			
		||||
            {13, &IUser::GetTagInfo, "GetTagInfo"},
 | 
			
		||||
            {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
 | 
			
		||||
            {15, &IUser::GetCommonInfo, "GetCommonInfo"},
 | 
			
		||||
            {16, &IUser::GetModelInfo, "GetModelInfo"},
 | 
			
		||||
            {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
 | 
			
		||||
            {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
 | 
			
		||||
            {19, &IUser::GetState, "GetState"},
 | 
			
		||||
            {20, &IUser::GetDeviceState, "GetDeviceState"},
 | 
			
		||||
            {21, &IUser::GetNpadId, "GetNpadId"},
 | 
			
		||||
            {22, nullptr, "GetApplicationArea2"},
 | 
			
		||||
            {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
 | 
			
		||||
            {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
 | 
			
		||||
            {24, nullptr, "RecreateApplicationArea"},
 | 
			
		||||
        };
 | 
			
		||||
        RegisterHandlers(functions);
 | 
			
		||||
 | 
			
		||||
        auto& kernel = Core::System::GetInstance().Kernel();
 | 
			
		||||
        activate_event =
 | 
			
		||||
            Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:ActivateEvent");
 | 
			
		||||
        deactivate_event =
 | 
			
		||||
            Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
 | 
			
		||||
        availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
 | 
			
		||||
@ -59,6 +70,17 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct TagInfo {
 | 
			
		||||
        std::array<u8, 10> uuid;
 | 
			
		||||
        u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
 | 
			
		||||
                        // mean something else
 | 
			
		||||
        INSERT_PADDING_BYTES(0x15);
 | 
			
		||||
        u32_le protocol;
 | 
			
		||||
        u32_le tag_type;
 | 
			
		||||
        INSERT_PADDING_BYTES(0x2c);
 | 
			
		||||
    };
 | 
			
		||||
    static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
 | 
			
		||||
 | 
			
		||||
    enum class State : u32 {
 | 
			
		||||
        NonInitialized = 0,
 | 
			
		||||
        Initialized = 1,
 | 
			
		||||
@ -66,15 +88,40 @@ private:
 | 
			
		||||
 | 
			
		||||
    enum class DeviceState : u32 {
 | 
			
		||||
        Initialized = 0,
 | 
			
		||||
        SearchingForTag = 1,
 | 
			
		||||
        TagFound = 2,
 | 
			
		||||
        TagRemoved = 3,
 | 
			
		||||
        TagNearby = 4,
 | 
			
		||||
        Unknown5 = 5,
 | 
			
		||||
        Finalized = 6
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CommonInfo {
 | 
			
		||||
        u16_be last_write_year;
 | 
			
		||||
        u8 last_write_month;
 | 
			
		||||
        u8 last_write_day;
 | 
			
		||||
        u16_be write_counter;
 | 
			
		||||
        u16_be version;
 | 
			
		||||
        u32_be application_area_size;
 | 
			
		||||
        INSERT_PADDING_BYTES(0x34);
 | 
			
		||||
    };
 | 
			
		||||
    static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
 | 
			
		||||
 | 
			
		||||
    void Initialize(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2, 0};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
 | 
			
		||||
        state = State::Initialized;
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        LOG_DEBUG(Service_NFC, "called");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetState(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3, 0};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushRaw<u32>(static_cast<u32>(state));
 | 
			
		||||
 | 
			
		||||
        LOG_DEBUG(Service_NFC, "called");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void ListDevices(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
@ -83,80 +130,217 @@ private:
 | 
			
		||||
 | 
			
		||||
        ctx.WriteBuffer(&device_handle, sizeof(device_handle));
 | 
			
		||||
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called, array_size={}", array_size);
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push<u32>(0);
 | 
			
		||||
        rb.Push<u32>(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetNpadId(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::RequestParser rp{ctx};
 | 
			
		||||
        const u64 dev_handle = rp.Pop<u64>();
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push<u32>(npad_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::RequestParser rp{ctx};
 | 
			
		||||
        const u64 dev_handle = rp.Pop<u64>();
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2, 1};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushCopyObjects(activate_event);
 | 
			
		||||
        rb.PushCopyObjects(nfp_interface.GetNFCEvent());
 | 
			
		||||
        has_attached_handle = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::RequestParser rp{ctx};
 | 
			
		||||
        const u64 dev_handle = rp.Pop<u64>();
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2, 1};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushCopyObjects(deactivate_event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetState(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
    void StopDetection(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
        switch (device_state) {
 | 
			
		||||
        case DeviceState::TagFound:
 | 
			
		||||
        case DeviceState::TagNearby:
 | 
			
		||||
            deactivate_event->Signal();
 | 
			
		||||
            device_state = DeviceState::Initialized;
 | 
			
		||||
            break;
 | 
			
		||||
        case DeviceState::SearchingForTag:
 | 
			
		||||
        case DeviceState::TagRemoved:
 | 
			
		||||
            device_state = DeviceState::Initialized;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push<u32>(static_cast<u32>(state));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetDeviceState(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
        auto nfc_event = nfp_interface.GetNFCEvent();
 | 
			
		||||
        if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
 | 
			
		||||
            device_state = DeviceState::TagFound;
 | 
			
		||||
            nfc_event->Clear();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push<u32>(static_cast<u32>(device_state));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetNpadId(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::RequestParser rp{ctx};
 | 
			
		||||
        const u64 dev_handle = rp.Pop<u64>();
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
    void StartDetection(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
 | 
			
		||||
            device_state = DeviceState::SearchingForTag;
 | 
			
		||||
        }
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetTagInfo(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        auto amiibo = nfp_interface.GetAmiiboBuffer();
 | 
			
		||||
        TagInfo tag_info{};
 | 
			
		||||
        std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size()));
 | 
			
		||||
        tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
 | 
			
		||||
 | 
			
		||||
        tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
 | 
			
		||||
        tag_info.tag_type = 2;
 | 
			
		||||
        ctx.WriteBuffer(&tag_info, sizeof(TagInfo));
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Mount(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        device_state = DeviceState::TagNearby;
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetModelInfo(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        auto amiibo = nfp_interface.GetAmiiboBuffer();
 | 
			
		||||
        ctx.WriteBuffer(&amiibo.model_info, sizeof(amiibo.model_info));
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Unmount(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        device_state = DeviceState::TagFound;
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Finalize(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
 | 
			
		||||
        device_state = DeviceState::Finalized;
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.Push<u32>(npad_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        IPC::RequestParser rp{ctx};
 | 
			
		||||
        const u64 dev_handle = rp.Pop<u64>();
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called, dev_handle=0x{:X}", dev_handle);
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2, 1};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushCopyObjects(availability_change_event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const u64 device_handle{0xDEAD};
 | 
			
		||||
    const u32 npad_id{0}; // This is the first player controller id
 | 
			
		||||
    void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
        // TODO(ogniK): Pull Mii and owner data from amiibo
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetCommonInfo(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
        // TODO(ogniK): Pull common information from amiibo
 | 
			
		||||
 | 
			
		||||
        CommonInfo common_info{};
 | 
			
		||||
        common_info.application_area_size = 0;
 | 
			
		||||
        ctx.WriteBuffer(&common_info, sizeof(CommonInfo));
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void OpenApplicationArea(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
        // We don't need to worry about this since we can just open the file
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
        // We don't need to worry about this since we can just open the file
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void GetApplicationArea(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_WARNING(Service_NFP, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
        // TODO(ogniK): Pull application area from amiibo
 | 
			
		||||
 | 
			
		||||
        IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
        rb.Push(RESULT_SUCCESS);
 | 
			
		||||
        rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool has_attached_handle{};
 | 
			
		||||
    const u64 device_handle{Common::MakeMagic('Y', 'U', 'Z', 'U')};
 | 
			
		||||
    const u32 npad_id{0}; // Player 1 controller
 | 
			
		||||
    State state{State::NonInitialized};
 | 
			
		||||
    DeviceState device_state{DeviceState::Initialized};
 | 
			
		||||
    Kernel::SharedPtr<Kernel::Event> activate_event;
 | 
			
		||||
    Kernel::SharedPtr<Kernel::Event> deactivate_event;
 | 
			
		||||
    Kernel::SharedPtr<Kernel::Event> availability_change_event;
 | 
			
		||||
    const Module::Interface& nfp_interface;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    LOG_DEBUG(Service_NFP, "called");
 | 
			
		||||
    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    rb.PushIpcInterface<IUser>();
 | 
			
		||||
    rb.PushIpcInterface<IUser>(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
 | 
			
		||||
    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
 | 
			
		||||
    if (buffer.size() < sizeof(AmiiboFile)) {
 | 
			
		||||
        return; // Failed to load file
 | 
			
		||||
    }
 | 
			
		||||
    std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
 | 
			
		||||
    nfc_tag_load->Signal();
 | 
			
		||||
}
 | 
			
		||||
const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const {
 | 
			
		||||
    return nfc_tag_load;
 | 
			
		||||
}
 | 
			
		||||
const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
 | 
			
		||||
    return amiibo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,9 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "core/hle/kernel/event.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::NFP {
 | 
			
		||||
@ -15,7 +18,27 @@ public:
 | 
			
		||||
        explicit Interface(std::shared_ptr<Module> module, const char* name);
 | 
			
		||||
        ~Interface() override;
 | 
			
		||||
 | 
			
		||||
        struct ModelInfo {
 | 
			
		||||
            std::array<u8, 0x8> amiibo_identification_block;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x38);
 | 
			
		||||
        };
 | 
			
		||||
        static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
 | 
			
		||||
 | 
			
		||||
        struct AmiiboFile {
 | 
			
		||||
            std::array<u8, 10> uuid;
 | 
			
		||||
            INSERT_PADDING_BYTES(0x4a);
 | 
			
		||||
            ModelInfo model_info;
 | 
			
		||||
        };
 | 
			
		||||
        static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size");
 | 
			
		||||
 | 
			
		||||
        void CreateUserInterface(Kernel::HLERequestContext& ctx);
 | 
			
		||||
        void LoadAmiibo(const std::vector<u8>& buffer);
 | 
			
		||||
        const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const;
 | 
			
		||||
        const AmiiboFile& GetAmiiboBuffer() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        Kernel::SharedPtr<Kernel::Event> nfc_tag_load{};
 | 
			
		||||
        AmiiboFile amiibo{};
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        std::shared_ptr<Module> module;
 | 
			
		||||
 | 
			
		||||
@ -113,6 +113,7 @@ static const std::array<const char*, NumAnalogs> mapping = {{
 | 
			
		||||
struct Values {
 | 
			
		||||
    // System
 | 
			
		||||
    bool use_docked_mode;
 | 
			
		||||
    bool enable_nfc;
 | 
			
		||||
    std::string username;
 | 
			
		||||
    int language_index;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -122,6 +122,7 @@ void Config::ReadValues() {
 | 
			
		||||
 | 
			
		||||
    qt_config->beginGroup("System");
 | 
			
		||||
    Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool();
 | 
			
		||||
    Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool();
 | 
			
		||||
    Settings::values.username = qt_config->value("username", "yuzu").toString().toStdString();
 | 
			
		||||
    Settings::values.language_index = qt_config->value("language_index", 1).toInt();
 | 
			
		||||
    qt_config->endGroup();
 | 
			
		||||
@ -258,6 +259,7 @@ void Config::SaveValues() {
 | 
			
		||||
 | 
			
		||||
    qt_config->beginGroup("System");
 | 
			
		||||
    qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
 | 
			
		||||
    qt_config->setValue("enable_nfc", Settings::values.enable_nfc);
 | 
			
		||||
    qt_config->setValue("username", QString::fromStdString(Settings::values.username));
 | 
			
		||||
    qt_config->setValue("language_index", Settings::values.language_index);
 | 
			
		||||
    qt_config->endGroup();
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ void ConfigureGeneral::setConfiguration() {
 | 
			
		||||
    ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
 | 
			
		||||
    ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
 | 
			
		||||
    ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
 | 
			
		||||
    ui->enable_nfc->setChecked(Settings::values.enable_nfc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
 | 
			
		||||
@ -45,4 +46,5 @@ void ConfigureGeneral::applyConfiguration() {
 | 
			
		||||
 | 
			
		||||
    Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
 | 
			
		||||
    Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
 | 
			
		||||
    Settings::values.enable_nfc = ui->enable_nfc->isChecked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -78,6 +78,13 @@
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
          <item>
 | 
			
		||||
           <widget class="QCheckBox" name="enable_nfc">
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Enable NFC</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
         </layout>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 | 
			
		||||
#include "core/hle/kernel/process.h"
 | 
			
		||||
#include "core/hle/service/filesystem/filesystem.h"
 | 
			
		||||
#include "core/hle/service/filesystem/fsp_ldr.h"
 | 
			
		||||
#include "core/hle/service/nfp/nfp.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "core/loader/loader.h"
 | 
			
		||||
#include "core/perf_stats.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
@ -424,6 +426,7 @@ void GMainWindow::ConnectMenuEvents() {
 | 
			
		||||
    connect(ui.action_Select_SDMC_Directory, &QAction::triggered, this,
 | 
			
		||||
            [this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::SDMC); });
 | 
			
		||||
    connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close);
 | 
			
		||||
    connect(ui.action_Load_Amiibo, &QAction::triggered, this, &GMainWindow::OnLoadAmiibo);
 | 
			
		||||
 | 
			
		||||
    // Emulation
 | 
			
		||||
    connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame);
 | 
			
		||||
@ -692,6 +695,7 @@ void GMainWindow::ShutdownGame() {
 | 
			
		||||
    ui.action_Stop->setEnabled(false);
 | 
			
		||||
    ui.action_Restart->setEnabled(false);
 | 
			
		||||
    ui.action_Report_Compatibility->setEnabled(false);
 | 
			
		||||
    ui.action_Load_Amiibo->setEnabled(false);
 | 
			
		||||
    render_window->hide();
 | 
			
		||||
    game_list->show();
 | 
			
		||||
    game_list->setFilterFocus();
 | 
			
		||||
@ -1191,6 +1195,7 @@ void GMainWindow::OnStartGame() {
 | 
			
		||||
    ui.action_Report_Compatibility->setEnabled(true);
 | 
			
		||||
 | 
			
		||||
    discord_rpc->Update();
 | 
			
		||||
    ui.action_Load_Amiibo->setEnabled(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnPauseGame() {
 | 
			
		||||
@ -1295,6 +1300,27 @@ void GMainWindow::OnConfigure() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnLoadAmiibo() {
 | 
			
		||||
    const QString extensions{"*.bin"};
 | 
			
		||||
    const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);
 | 
			
		||||
    const QString filename = QFileDialog::getOpenFileName(this, tr("Load Amiibo"), "", file_filter);
 | 
			
		||||
    if (!filename.isEmpty()) {
 | 
			
		||||
        Core::System& system{Core::System::GetInstance()};
 | 
			
		||||
        Service::SM::ServiceManager& sm = system.ServiceManager();
 | 
			
		||||
        auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
 | 
			
		||||
        if (nfc != nullptr) {
 | 
			
		||||
            auto nfc_file = FileUtil::IOFile(filename.toStdString(), "rb");
 | 
			
		||||
            if (!nfc_file.IsOpen()) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            std::vector<u8> amiibo_buffer(nfc_file.GetSize());
 | 
			
		||||
            nfc_file.ReadBytes(amiibo_buffer.data(), amiibo_buffer.size());
 | 
			
		||||
            nfc_file.Close();
 | 
			
		||||
            nfc->LoadAmiibo(amiibo_buffer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnAbout() {
 | 
			
		||||
    AboutDialog aboutDialog(this);
 | 
			
		||||
    aboutDialog.exec();
 | 
			
		||||
@ -1335,13 +1361,15 @@ void GMainWindow::UpdateStatusBar() {
 | 
			
		||||
void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
 | 
			
		||||
    QMessageBox::StandardButton answer;
 | 
			
		||||
    QString status_message;
 | 
			
		||||
    const QString common_message = tr(
 | 
			
		||||
        "The game you are trying to load requires additional files from your Switch to be dumped "
 | 
			
		||||
    const QString common_message =
 | 
			
		||||
        tr("The game you are trying to load requires additional files from your Switch to be "
 | 
			
		||||
           "dumped "
 | 
			
		||||
           "before playing.<br/><br/>For more information on dumping these files, please see the "
 | 
			
		||||
           "following wiki page: <a "
 | 
			
		||||
           "href='https://yuzu-emu.org/wiki/"
 | 
			
		||||
           "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
 | 
			
		||||
        "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit "
 | 
			
		||||
           "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to "
 | 
			
		||||
           "quit "
 | 
			
		||||
           "back to the game list? Continuing emulation may result in crashes, corrupted save "
 | 
			
		||||
           "data, or other bugs.");
 | 
			
		||||
    switch (result) {
 | 
			
		||||
@ -1374,9 +1402,12 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
 | 
			
		||||
            this, tr("Fatal Error"),
 | 
			
		||||
            tr("yuzu has encountered a fatal error, please see the log for more details. "
 | 
			
		||||
               "For more information on accessing the log, please see the following page: "
 | 
			
		||||
               "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How to "
 | 
			
		||||
               "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game list? "
 | 
			
		||||
               "Continuing emulation may result in crashes, corrupted save data, or other bugs."),
 | 
			
		||||
               "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
 | 
			
		||||
               "to "
 | 
			
		||||
               "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game "
 | 
			
		||||
               "list? "
 | 
			
		||||
               "Continuing emulation may result in crashes, corrupted save data, or other "
 | 
			
		||||
               "bugs."),
 | 
			
		||||
            QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
 | 
			
		||||
        status_message = "Fatal Error encountered";
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
@ -166,6 +166,7 @@ private slots:
 | 
			
		||||
    void OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target);
 | 
			
		||||
    void OnMenuRecentFile();
 | 
			
		||||
    void OnConfigure();
 | 
			
		||||
    void OnLoadAmiibo();
 | 
			
		||||
    void OnAbout();
 | 
			
		||||
    void OnToggleFilterBar();
 | 
			
		||||
    void OnDisplayTitleBars(bool);
 | 
			
		||||
 | 
			
		||||
@ -68,6 +68,8 @@
 | 
			
		||||
    <addaction name="action_Select_NAND_Directory"/>
 | 
			
		||||
    <addaction name="action_Select_SDMC_Directory"/>
 | 
			
		||||
    <addaction name="separator"/>
 | 
			
		||||
    <addaction name="action_Load_Amiibo"/>
 | 
			
		||||
    <addaction name="separator"/>
 | 
			
		||||
    <addaction name="action_Exit"/>
 | 
			
		||||
   </widget>
 | 
			
		||||
   <widget class="QMenu" name="menu_Emulation">
 | 
			
		||||
@ -118,6 +120,9 @@
 | 
			
		||||
   <addaction name="menu_Help"/>
 | 
			
		||||
  </widget>
 | 
			
		||||
  <action name="action_Install_File_NAND">
 | 
			
		||||
   <property name="enabled">
 | 
			
		||||
    <bool>true</bool>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="text">
 | 
			
		||||
    <string>Install File to NAND...</string>
 | 
			
		||||
   </property>
 | 
			
		||||
@ -253,6 +258,14 @@
 | 
			
		||||
       <string>Restart</string>
 | 
			
		||||
     </property>
 | 
			
		||||
   </action>
 | 
			
		||||
  <action name="action_Load_Amiibo">
 | 
			
		||||
    <property name="enabled">
 | 
			
		||||
      <bool>false</bool>
 | 
			
		||||
    </property>
 | 
			
		||||
    <property name="text">
 | 
			
		||||
      <string>Load Amiibo...</string>
 | 
			
		||||
    </property>
 | 
			
		||||
  </action>
 | 
			
		||||
   <action name="action_Report_Compatibility">
 | 
			
		||||
     <property name="enabled">
 | 
			
		||||
       <bool>false</bool>
 | 
			
		||||
 | 
			
		||||
@ -125,6 +125,7 @@ void Config::ReadValues() {
 | 
			
		||||
 | 
			
		||||
    // System
 | 
			
		||||
    Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
 | 
			
		||||
    Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true);
 | 
			
		||||
    Settings::values.username = sdl2_config->Get("System", "username", "yuzu");
 | 
			
		||||
    if (Settings::values.username.empty()) {
 | 
			
		||||
        Settings::values.username = "yuzu";
 | 
			
		||||
 | 
			
		||||
@ -174,6 +174,10 @@ use_virtual_sd =
 | 
			
		||||
# 1: Yes, 0 (default): No
 | 
			
		||||
use_docked_mode =
 | 
			
		||||
 | 
			
		||||
# Allow the use of NFC in games
 | 
			
		||||
# 1 (default): Yes, 0 : No
 | 
			
		||||
enable_nfc =
 | 
			
		||||
 | 
			
		||||
# Sets the account username, max length is 32 characters
 | 
			
		||||
# yuzu (default)
 | 
			
		||||
username = yuzu
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user