service: nfc: Merge device interfaces and create the device manager

master
Narr the Reg 2023-04-19 19:01:23 +07:00 committed by german77
parent 5e16fe4579
commit 94151097b9
32 changed files with 2086 additions and 2465 deletions

@ -555,21 +555,22 @@ add_library(core STATIC
hle/service/mnpp/mnpp_app.h hle/service/mnpp/mnpp_app.h
hle/service/ncm/ncm.cpp hle/service/ncm/ncm.cpp
hle/service/ncm/ncm.h hle/service/ncm/ncm.h
hle/service/nfc/mifare_user.cpp hle/service/nfc/common/amiibo_crypto.cpp
hle/service/nfc/mifare_user.h hle/service/nfc/common/amiibo_crypto.h
hle/service/nfc/common/device.cpp
hle/service/nfc/common/device.h
hle/service/nfc/common/device_manager.cpp
hle/service/nfc/common/device_manager.h
hle/service/nfc/mifare_result.h
hle/service/nfc/mifare_types.h
hle/service/nfc/nfc.cpp hle/service/nfc/nfc.cpp
hle/service/nfc/nfc.h hle/service/nfc/nfc.h
hle/service/nfc/nfc_device.cpp hle/service/nfc/nfc_interface.cpp
hle/service/nfc/nfc_device.h hle/service/nfc/nfc_interface.h
hle/service/nfc/nfc_result.h hle/service/nfc/nfc_result.h
hle/service/nfc/nfc_user.cpp hle/service/nfc/nfc_types.h
hle/service/nfc/nfc_user.h
hle/service/nfp/amiibo_crypto.cpp
hle/service/nfp/amiibo_crypto.h
hle/service/nfp/nfp.cpp hle/service/nfp/nfp.cpp
hle/service/nfp/nfp.h hle/service/nfp/nfp.h
hle/service/nfp/nfp_device.cpp
hle/service/nfp/nfp_device.h
hle/service/nfp/nfp_interface.cpp hle/service/nfp/nfp_interface.cpp
hle/service/nfp/nfp_interface.h hle/service/nfp/nfp_interface.h
hle/service/nfp/nfp_result.h hle/service/nfp/nfp_result.h

@ -14,7 +14,7 @@ void DefaultCabinetApplet::Close() const {}
void DefaultCabinetApplet::ShowCabinetApplet( void DefaultCabinetApplet::ShowCabinetApplet(
const CabinetCallback& callback, const CabinetParameters& parameters, const CabinetCallback& callback, const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
LOG_WARNING(Service_AM, "(STUBBED) called"); LOG_WARNING(Service_AM, "(STUBBED) called");
callback(false, {}); callback(false, {});
} }

@ -7,9 +7,9 @@
#include "core/frontend/applets/applet.h" #include "core/frontend/applets/applet.h"
#include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/nfp/nfp_types.h"
namespace Service::NFP { namespace Service::NFC {
class NfpDevice; class NfcDevice;
} // namespace Service::NFP } // namespace Service::NFC
namespace Core::Frontend { namespace Core::Frontend {
@ -26,14 +26,14 @@ public:
virtual ~CabinetApplet(); virtual ~CabinetApplet();
virtual void ShowCabinetApplet(const CabinetCallback& callback, virtual void ShowCabinetApplet(const CabinetCallback& callback,
const CabinetParameters& parameters, const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0; std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
}; };
class DefaultCabinetApplet final : public CabinetApplet { class DefaultCabinetApplet final : public CabinetApplet {
public: public:
void Close() const override; void Close() const override;
void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
}; };
} // namespace Core::Frontend } // namespace Core::Frontend

@ -11,7 +11,7 @@
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfc/common/device.h"
namespace Service::AM::Applets { namespace Service::AM::Applets {
@ -72,10 +72,10 @@ void Cabinet::Execute() {
// TODO: listen on all controllers // TODO: listen on all controllers
if (nfp_device == nullptr) { if (nfp_device == nullptr) {
nfp_device = std::make_shared<Service::NFP::NfpDevice>( nfp_device = std::make_shared<Service::NFC::NfcDevice>(
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
nfp_device->Initialize(); nfp_device->Initialize();
nfp_device->StartDetection(Service::NFP::TagProtocol::All); nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
} }
const Core::Frontend::CabinetParameters parameters{ const Core::Frontend::CabinetParameters parameters{
@ -106,20 +106,22 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
Cancel(); Cancel();
} }
if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
Cancel(); Cancel();
} }
if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) {
nfp_device->Mount(Service::NFP::MountTarget::All); nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
} }
switch (applet_input_common.applet_mode) { switch (applet_input_common.applet_mode) {
case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
Service::NFP::AmiiboName name{}; Service::NFP::RegisterInfoPrivate register_info{};
std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(),
nfp_device->SetRegisterInfoPrivate(name); std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1));
nfp_device->SetRegisterInfoPrivate(register_info);
break; break;
} }
case Service::NFP::CabinetMode::StartGameDataEraser: case Service::NFP::CabinetMode::StartGameDataEraser:
@ -139,7 +141,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
applet_output.device_handle = applet_input_common.device_handle; applet_output.device_handle = applet_input_common.device_handle;
applet_output.result = CabinetResult::Cancel; applet_output.result = CabinetResult::Cancel;
const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info, false);
nfp_device->Finalize(); nfp_device->Finalize();
if (reg_result.IsSuccess()) { if (reg_result.IsSuccess()) {

@ -19,8 +19,8 @@ namespace Core {
class System; class System;
} // namespace Core } // namespace Core
namespace Service::NFP { namespace Service::NFC {
class NfpDevice; class NfcDevice;
} }
namespace Service::AM::Applets { namespace Service::AM::Applets {
@ -96,7 +96,7 @@ private:
Core::System& system; Core::System& system;
bool is_complete{false}; bool is_complete{false};
std::shared_ptr<Service::NFP::NfpDevice> nfp_device; std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
Kernel::KEvent* availability_change_event; Kernel::KEvent* availability_change_event;
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
StartParamForAmiiboSettings applet_input_common{}; StartParamForAmiiboSettings applet_input_common{};

@ -12,7 +12,7 @@
#include "common/fs/fs.h" #include "common/fs/fs.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/service/nfp/amiibo_crypto.h" #include "core/hle/service/nfc/common/amiibo_crypto.h"
namespace Service::NFP::AmiiboCrypto { namespace Service::NFP::AmiiboCrypto {
@ -55,7 +55,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
if (amiibo_data.constant_value != 0xA5) { if (amiibo_data.constant_value != 0xA5) {
return false; return false;
} }
if (amiibo_data.model_info.tag_type != PackedTagType::Type2) { if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
return false; return false;
} }
if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) { if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {

@ -24,9 +24,9 @@ using DrgbOutput = std::array<u8, 0x20>;
struct HashSeed { struct HashSeed {
u16_be magic; u16_be magic;
std::array<u8, 0xE> padding; std::array<u8, 0xE> padding;
UniqueSerialNumber uid_1; NFC::UniqueSerialNumber uid_1;
u8 nintendo_id_1; u8 nintendo_id_1;
UniqueSerialNumber uid_2; NFC::UniqueSerialNumber uid_2;
u8 nintendo_id_2; u8 nintendo_id_2;
std::array<u8, 0x20> keygen_salt; std::array<u8, 0x20> keygen_salt;
}; };

@ -0,0 +1,138 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include "common/common_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfc/mifare_types.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.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(NfcProtocol allowed_protocol);
Result StopDetection();
Result GetTagInfo(TagInfo& tag_info, bool is_mifare) const;
Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
std::span<MifareReadBlockData> read_block_data) const;
Result ReadMifare(const MifareReadBlockParameter& parameter,
MifareReadBlockData& read_block_data) const;
Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
Result WriteMifare(const MifareWriteBlockParameter& parameter);
Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<u8> out_data);
Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
Result Unmount();
Result Flush();
Result FlushDebug();
Result FlushWithBreak(NFP::BreakType break_type);
Result Restore();
Result GetCommonInfo(NFP::CommonInfo& common_info) const;
Result GetModelInfo(NFP::ModelInfo& model_info) const;
Result GetRegisterInfo(NFP::RegisterInfo& register_info) const;
Result GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const;
Result GetAdminInfo(NFP::AdminInfo& admin_info) const;
Result DeleteRegisterInfo();
Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
Result RestoreAmiibo();
Result Format();
Result OpenApplicationArea(u32 access_id);
Result GetApplicationAreaId(u32& application_area_id) const;
Result GetApplicationArea(std::span<u8> data) const;
Result SetApplicationArea(std::span<const u8> data);
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
Result DeleteApplicationArea();
Result ExistsApplicationArea(bool& has_application_area) const;
Result GetAll(NFP::NfpData& data) const;
Result SetAll(const NFP::NfpData& data);
Result BreakTag(NFP::BreakType break_type);
Result ReadBackupData(std::span<u8> data) const;
Result WriteBackupData(std::span<const u8> data);
Result WriteNtf(std::span<const u8> data);
u64 GetHandle() const;
DeviceState GetCurrentState() const;
Result GetNpadId(Core::HID::NpadIdType& out_npad_id) 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();
NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name);
NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
u64 RemoveVersionByte(u64 application_id) const;
void UpdateSettingsCrc();
void UpdateRegisterInfoCrc();
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;
bool is_initalized{};
NfcProtocol allowed_protocols{};
DeviceState device_state{DeviceState::Unavailable};
// NFP data
bool is_data_moddified{};
bool is_app_area_open{};
bool is_plain_amiibo{};
s64 current_posix_time{};
NFP::MountTarget mount_target{NFP::MountTarget::None};
NFP::NTAG215File tag_data{};
std::vector<u8> mifare_data{};
NFP::EncryptedNTAG215File encrypted_tag_data{};
};
} // namespace Service::NFC

@ -0,0 +1,695 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::NFC {
DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
: system{system_}, service_context{service_context_} {
availability_change_event =
service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
for (u32 device_index = 0; device_index < devices.size(); device_index++) {
devices[device_index] =
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
service_context, availability_change_event);
}
is_initialized = false;
}
DeviceManager ::~DeviceManager() {
service_context.CloseEvent(availability_change_event);
}
Result DeviceManager::Initialize() {
for (auto& device : devices) {
device->Initialize();
}
is_initialized = true;
return ResultSuccess;
}
Result DeviceManager::Finalize() {
for (auto& device : devices) {
device->Finalize();
}
is_initialized = false;
return ResultSuccess;
}
Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
std::size_t max_allowed_devices) const {
for (auto& device : devices) {
if (nfp_devices.size() >= max_allowed_devices) {
continue;
}
if (device->GetCurrentState() != DeviceState::Unavailable) {
nfp_devices.push_back(device->GetHandle());
}
}
if (nfp_devices.empty()) {
return ResultDeviceNotFound;
}
return ResultSuccess;
}
DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
const auto result = GetDeviceFromHandle(device_handle, device, false);
if (result.IsSuccess()) {
return device->GetCurrentState();
}
return DeviceState::Unavailable;
}
Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetNpadId(npad_id);
result = VerifyDeviceResult(device, result);
}
return result;
}
Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
return availability_change_event->GetReadableEvent();
}
Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->StartDetection(tag_protocol);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::StopDetection(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->StopDetection();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetTagInfo(tag_info, is_mifare);
result = VerifyDeviceResult(device, result);
}
return result;
}
Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
GetDeviceFromHandle(device_handle, device, false);
// TODO: Return proper error code on failure
return device->GetActivateEvent();
}
Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
GetDeviceFromHandle(device_handle, device, false);
// TODO: Return proper error code on failure
return device->GetDeactivateEvent();
}
Result DeviceManager::ReadMifare(u64 device_handle,
std::span<const MifareReadBlockParameter> read_parameters,
std::span<MifareReadBlockData> read_data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->ReadMifare(read_parameters, read_data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::WriteMifare(u64 device_handle,
std::span<const MifareWriteBlockParameter> write_parameters) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->WriteMifare(write_parameters);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data,
std::span<u8> out_data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->SendCommandByPassThrough(timeout, command_data, out_data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
NFP::MountTarget mount_target) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->Mount(model_type, mount_target);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::Unmount(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->Unmount();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->OpenApplicationArea(access_id);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetApplicationArea(data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->SetApplicationArea(data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::Flush(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->Flush();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::Restore(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->Restore();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
std::span<const u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->CreateApplicationArea(access_id, data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetRegisterInfo(register_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetCommonInfo(common_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetModelInfo(model_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
u32 DeviceManager::GetApplicationAreaSize() const {
return sizeof(NFP::ApplicationArea);
}
Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
std::span<const u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->RecreateApplicationArea(access_id, data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::Format(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->Format();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetAdminInfo(admin_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
NFP::RegisterInfoPrivate& register_info) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetRegisterInfoPrivate(register_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
const NFP::RegisterInfoPrivate& register_info) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->SetRegisterInfoPrivate(register_info);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->DeleteRegisterInfo();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->DeleteApplicationArea();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->ExistsApplicationArea(has_application_area);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->GetAll(nfp_data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->SetAll(nfp_data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::FlushDebug(u64 device_handle) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->FlushDebug();
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->BreakTag(break_type);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->ReadBackupData(data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->WriteBackupData(data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
std::scoped_lock lock{mutex};
std::shared_ptr<NfcDevice> device = nullptr;
auto result = GetDeviceHandle(device_handle, device);
if (result.IsSuccess()) {
result = device->WriteNtf(data);
result = VerifyDeviceResult(device, result);
}
return result;
}
Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
bool check_state) const {
if (check_state) {
const Result is_parameter_set = IsNfcParameterSet();
if (is_parameter_set.IsError()) {
return is_parameter_set;
}
const Result is_enabled = IsNfcEnabled();
if (is_enabled.IsError()) {
return is_enabled;
}
const Result is_nfc_initialized = IsNfcInitialized();
if (is_nfc_initialized.IsError()) {
return is_nfc_initialized;
}
}
for (auto& device : devices) {
if (device->GetHandle() == handle) {
nfc_device = device;
return ResultSuccess;
}
}
return ResultDeviceNotFound;
}
std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
for (auto& device : devices) {
if (device->GetHandle() == handle) {
return device;
}
}
return std::nullopt;
}
const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
for (auto& device : devices) {
if (device->GetHandle() == handle) {
return device;
}
}
return std::nullopt;
}
Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
const auto result = GetDeviceFromHandle(handle, device, true);
if (result.IsError()) {
return result;
}
return CheckDeviceState(device);
}
Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
Result operation_result) const {
if (operation_result.IsSuccess()) {
return operation_result;
}
const Result is_parameter_set = IsNfcParameterSet();
if (is_parameter_set.IsError()) {
return is_parameter_set;
}
const Result is_enabled = IsNfcEnabled();
if (is_enabled.IsError()) {
return is_enabled;
}
const Result is_nfc_initialized = IsNfcInitialized();
if (is_nfc_initialized.IsError()) {
return is_nfc_initialized;
}
const Result device_state = CheckDeviceState(device);
if (device_state.IsError()) {
return device_state;
}
return operation_result;
}
Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
if (device == nullptr) {
return ResultInvalidArgument;
}
return ResultSuccess;
}
Result DeviceManager::IsNfcEnabled() const {
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
const bool is_enabled = true;
if (!is_enabled) {
return ResultNfcDisabled;
}
return ResultSuccess;
}
Result DeviceManager::IsNfcParameterSet() const {
// TODO: This calls checks against a bool on offset 0x450
const bool is_set = true;
if (!is_set) {
return ResultUnknown76;
}
return ResultSuccess;
}
Result DeviceManager::IsNfcInitialized() const {
if (!is_initialized) {
return ResultNfcNotInitialized;
}
return ResultSuccess;
}
} // namespace Service::NFC

@ -0,0 +1,100 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <memory>
#include <optional>
#include <span>
#include "core/hid/hid_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfc/mifare_types.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::NFC {
class NfcDevice;
class DeviceManager {
public:
explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
~DeviceManager();
// Nfc device manager
Result Initialize();
Result Finalize();
Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
DeviceState GetDeviceState(u64 device_handle) const;
Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
Result StopDetection(u64 device_handle);
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const;
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
Result ReadMifare(u64 device_handle,
const std::span<const MifareReadBlockParameter> read_parameters,
std::span<MifareReadBlockData> read_data);
Result WriteMifare(u64 device_handle,
std::span<const MifareWriteBlockParameter> write_parameters);
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
std::span<const u8> command_data, std::span<u8> out_data);
// Nfp device manager
Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
Result Unmount(u64 device_handle);
Result OpenApplicationArea(u64 device_handle, u32 access_id);
Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
Result Flush(u64 device_handle);
Result Restore(u64 device_handle);
Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
u32 GetApplicationAreaSize() const;
Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
Result Format(u64 device_handle);
Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
Result DeleteRegisterInfo(u64 device_handle);
Result DeleteApplicationArea(u64 device_handle);
Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
Result FlushDebug(u64 device_handle);
Result BreakTag(u64 device_handle, NFP::BreakType break_type);
Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
Result WriteBackupData(u64 device_handle, std::span<const u8> data);
Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
private:
Result IsNfcEnabled() const;
Result IsNfcParameterSet() const;
Result IsNfcInitialized() const;
Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
bool check_state) const;
Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
bool is_initialized = false;
mutable std::mutex mutex;
std::array<std::shared_ptr<NfcDevice>, 10> devices{};
Core::System& system;
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* availability_change_event;
};
} // namespace Service::NFC

@ -1,382 +0,0 @@
// 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/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/mifare_interface.h"
#include "core/hle/service/nfc/nfc_device.h"
#include "core/hle/service/nfc/nfc_result.h"
namespace Service::NFC {
MFInterface::MFInterface(Core::System& system_, const char* name)
: ServiceFramework{system_, name}, service_context{system_, service_name} {
availability_change_event = service_context.CreateEvent("MFInterface: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);
}
}
MFInterface ::~MFInterface() {
availability_change_event->Close();
}
void MFInterface::Initialize(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 MFInterface::Finalize(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 MFInterface::ListDevices(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
if (state == State::NonInitialized) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareNfcDisabled);
return;
}
if (!ctx.CanWriteBuffer()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareInvalidArgument);
return;
}
if (ctx.GetWriteBufferSize() == 0) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareInvalidArgument);
return;
}
std::vector<u64> nfp_devices;
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
for (const 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(MifareDeviceNotFound);
return;
}
ctx.WriteBuffer(nfp_devices);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<s32>(nfp_devices.size()));
}
void MFInterface::StartDetection(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void MFInterface::StopDetection(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
const auto result = device.value()->StopDetection();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void MFInterface::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto buffer{ctx.ReadBuffer()};
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
memcpy(read_commands.data(), buffer.data(),
number_of_commands * sizeof(NFP::MifareReadBlockParameter));
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
device_handle, number_of_commands);
if (state == State::NonInitialized) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
Result result = ResultSuccess;
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
for (std::size_t i = 0; i < number_of_commands; i++) {
result = device.value()->MifareRead(read_commands[i], out_data[i]);
if (result.IsError()) {
break;
}
}
ctx.WriteBuffer(out_data);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void MFInterface::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto buffer{ctx.ReadBuffer()};
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
memcpy(write_commands.data(), buffer.data(),
number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
device_handle, number_of_commands);
if (state == State::NonInitialized) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
Result result = ResultSuccess;
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
for (std::size_t i = 0; i < number_of_commands; i++) {
result = device.value()->MifareWrite(write_commands[i]);
if (result.IsError()) {
break;
}
}
if (result.IsSuccess()) {
result = device.value()->Flush();
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void MFInterface::GetTagInfo(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
NFP::TagInfo tag_info{};
const auto result = device.value()->GetTagInfo(tag_info, true);
ctx.WriteBuffer(tag_info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void MFInterface::GetActivateEventHandle(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(device.value()->GetActivateEvent());
}
void MFInterface::GetDeactivateEventHandle(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(device.value()->GetDeactivateEvent());
}
void MFInterface::GetState(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
void MFInterface::GetDeviceState(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(MifareDeviceNotFound);
return;
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(device.value()->GetCurrentState());
}
void MFInterface::GetNpadId(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(MifareNfcDisabled);
return;
}
auto device = GetNfcDevice(device_handle);
if (!device.has_value()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareDeviceNotFound);
return;
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(device.value()->GetNpadId());
}
void MFInterface::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) {
LOG_INFO(Service_NFC, "called");
if (state == State::NonInitialized) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(MifareNfcDisabled);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(availability_change_event->GetReadableEvent());
}
std::optional<std::shared_ptr<NfcDevice>> MFInterface::GetNfcDevice(u64 handle) {
for (auto& device : devices) {
if (device->GetHandle() == handle) {
return device;
}
}
return std::nullopt;
}
} // namespace Service::NFC

@ -1,52 +0,0 @@
// 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 MFInterface : public ServiceFramework<MFInterface> {
public:
explicit MFInterface(Core::System& system_, const char* name);
~MFInterface();
void Initialize(HLERequestContext& ctx);
void Finalize(HLERequestContext& ctx);
void ListDevices(HLERequestContext& ctx);
void StartDetection(HLERequestContext& ctx);
void StopDetection(HLERequestContext& ctx);
void Read(HLERequestContext& ctx);
void Write(HLERequestContext& ctx);
void GetTagInfo(HLERequestContext& ctx);
void GetActivateEventHandle(HLERequestContext& ctx);
void GetDeactivateEventHandle(HLERequestContext& ctx);
void GetState(HLERequestContext& ctx);
void GetDeviceState(HLERequestContext& ctx);
void GetNpadId(HLERequestContext& ctx);
void GetAvailabilityChangeEventHandle(HLERequestContext& ctx);
private:
enum class State : u32 {
NonInitialized,
Initialized,
};
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

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/result.h"
namespace Service::NFC::Mifare {
constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64);
constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
constexpr Result ResultReadError(ErrorModule::NFCMifare, 288);
} // namespace Service::NFC::Mifare

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::NFC {
enum class MifareCmd : u8 {
AuthA = 0x60,
AuthB = 0x61,
Read = 0x30,
Write = 0xA0,
Transfer = 0xB0,
Decrement = 0xC0,
Increment = 0xC1,
Store = 0xC2
};
using DataBlock = std::array<u8, 0x10>;
using KeyData = std::array<u8, 0x6>;
struct SectorKey {
MifareCmd command;
u8 unknown; // Usually 1
INSERT_PADDING_BYTES(0x6);
KeyData sector_key;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
// This is nn::nfc::MifareReadBlockParameter
struct MifareReadBlockParameter {
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
SectorKey sector_key;
};
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
"MifareReadBlockParameter is an invalid size");
// This is nn::nfc::MifareReadBlockData
struct MifareReadBlockData {
DataBlock data;
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
};
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
// This is nn::nfc::MifareWriteBlockParameter
struct MifareWriteBlockParameter {
DataBlock data;
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
SectorKey sector_key;
};
static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
"MifareWriteBlockParameter is an invalid size");
} // namespace Service::NFC

@ -6,7 +6,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/mifare_interface.h"
#include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nfc/nfc_interface.h" #include "core/hle/service/nfc/nfc_interface.h"
#include "core/hle/service/server_manager.h" #include "core/hle/service/server_manager.h"
@ -14,31 +13,31 @@
namespace Service::NFC { namespace Service::NFC {
class IUser final : public Interface { class IUser final : public NfcInterface {
public: public:
explicit IUser(Core::System& system_) : Interface(system_, "NFC::IUser") { explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &Interface::Initialize, "InitializeOld"}, {0, &NfcInterface::Initialize, "InitializeOld"},
{1, &Interface::Finalize, "FinalizeOld"}, {1, &NfcInterface::Finalize, "FinalizeOld"},
{2, &Interface::GetState, "GetStateOld"}, {2, &NfcInterface::GetState, "GetStateOld"},
{3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"}, {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
{400, &Interface::Initialize, "Initialize"}, {400, &NfcInterface::Initialize, "Initialize"},
{401, &Interface::Finalize, "Finalize"}, {401, &NfcInterface::Finalize, "Finalize"},
{402, &Interface::GetState, "GetState"}, {402, &NfcInterface::GetState, "GetState"},
{403, &Interface::IsNfcEnabled, "IsNfcEnabled"}, {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
{404, &Interface::ListDevices, "ListDevices"}, {404, &NfcInterface::ListDevices, "ListDevices"},
{405, &Interface::GetDeviceState, "GetDeviceState"}, {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
{406, &Interface::GetNpadId, "GetNpadId"}, {406, &NfcInterface::GetNpadId, "GetNpadId"},
{407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
{408, &Interface::StartDetection, "StartDetection"}, {408, &NfcInterface::StartDetection, "StartDetection"},
{409, &Interface::StopDetection, "StopDetection"}, {409, &NfcInterface::StopDetection, "StopDetection"},
{410, &Interface::GetTagInfo, "GetTagInfo"}, {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
{411, &Interface::AttachActivateEvent, "AttachActivateEvent"}, {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
{412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"}, {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
{1000, nullptr, "ReadMifare"}, {1000, &NfcInterface::ReadMifare, "ReadMifare"},
{1001, nullptr, "WriteMifare"}, {1001, &NfcInterface::WriteMifare ,"WriteMifare"},
{1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"}, {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
{1301, nullptr, "KeepPassThroughSession"}, {1301, nullptr, "KeepPassThroughSession"},
{1302, nullptr, "ReleasePassThroughSession"}, {1302, nullptr, "ReleasePassThroughSession"},
}; };
@ -48,34 +47,35 @@ public:
} }
}; };
class ISystem final : public Interface { class ISystem final : public NfcInterface {
public: public:
explicit ISystem(Core::System& system_) : Interface{system_, "NFC::ISystem"} { explicit ISystem(Core::System& system_)
: NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &Interface::Initialize, "InitializeOld"}, {0, &NfcInterface::Initialize, "InitializeOld"},
{1, &Interface::Finalize, "FinalizeOld"}, {1, &NfcInterface::Finalize, "FinalizeOld"},
{2, &Interface::GetState, "GetStateOld"}, {2, &NfcInterface::GetState, "GetStateOld"},
{3, &Interface::IsNfcEnabled, "IsNfcEnabledOld"}, {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
{100, nullptr, "SetNfcEnabledOld"}, {100, nullptr, "SetNfcEnabledOld"},
{400, &Interface::Initialize, "Initialize"}, {400, &NfcInterface::Initialize, "Initialize"},
{401, &Interface::Finalize, "Finalize"}, {401, &NfcInterface::Finalize, "Finalize"},
{402, &Interface::GetState, "GetState"}, {402, &NfcInterface::GetState, "GetState"},
{403, &Interface::IsNfcEnabled, "IsNfcEnabled"}, {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
{404, &Interface::ListDevices, "ListDevices"}, {404, &NfcInterface::ListDevices, "ListDevices"},
{405, &Interface::GetDeviceState, "GetDeviceState"}, {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
{406, &Interface::GetNpadId, "GetNpadId"}, {406, &NfcInterface::GetNpadId, "GetNpadId"},
{407, &Interface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
{408, &Interface::StartDetection, "StartDetection"}, {408, &NfcInterface::StartDetection, "StartDetection"},
{409, &Interface::StopDetection, "StopDetection"}, {409, &NfcInterface::StopDetection, "StopDetection"},
{410, &Interface::GetTagInfo, "GetTagInfo"}, {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
{411, &Interface::AttachActivateEvent, "AttachActivateEvent"}, {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
{412, &Interface::AttachDeactivateEvent, "AttachDeactivateEvent"}, {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
{500, nullptr, "SetNfcEnabled"}, {500, nullptr, "SetNfcEnabled"},
{510, nullptr, "OutputTestWave"}, {510, nullptr, "OutputTestWave"},
{1000, nullptr, "ReadMifare"}, {1000, &NfcInterface::ReadMifare, "ReadMifare"},
{1001, nullptr, "WriteMifare"}, {1001, &NfcInterface::WriteMifare, "WriteMifare"},
{1300, &Interface::SendCommandByPassThrough, "SendCommandByPassThrough"}, {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
{1301, nullptr, "KeepPassThroughSession"}, {1301, nullptr, "KeepPassThroughSession"},
{1302, nullptr, "ReleasePassThroughSession"}, {1302, nullptr, "ReleasePassThroughSession"},
}; };
@ -85,25 +85,29 @@ public:
} }
}; };
// MFInterface has an unique interface but it's identical to NfcInterface so we can keep the code
// simpler
using MFInterface = NfcInterface;
class MFIUser final : public MFInterface { class MFIUser final : public MFInterface {
public: public:
explicit MFIUser(Core::System& system_) : MFInterface{system_, "NFC::MFInterface"} { explicit MFIUser(Core::System& system_)
: MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfoTyped<MFIUser> functions[] = {
{0, &MFIUser::Initialize, "Initialize"}, {0, &MFIUser::Initialize, "Initialize"},
{1, &MFIUser::Finalize, "Finalize"}, {1, &MFIUser::Finalize, "Finalize"},
{2, &MFIUser::ListDevices, "ListDevices"}, {2, &MFIUser::ListDevices, "ListDevices"},
{3, &MFIUser::StartDetection, "StartDetection"}, {3, &MFIUser::StartDetection, "StartDetection"},
{4, &MFIUser::StopDetection, "StopDetection"}, {4, &MFIUser::StopDetection, "StopDetection"},
{5, &MFIUser::Read, "Read"}, {5, &MFIUser::ReadMifare, "Read"},
{6, &MFIUser::Write, "Write"}, {6, &MFIUser::WriteMifare, "Write"},
{7, &MFIUser::GetTagInfo, "GetTagInfo"}, {7, &MFIUser::GetTagInfo, "GetTagInfo"},
{8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, {8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
{9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, {9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
{10, &MFIUser::GetState, "GetState"}, {10, &MFIUser::GetState, "GetState"},
{11, &MFIUser::GetDeviceState, "GetDeviceState"}, {11, &MFIUser::GetDeviceState, "GetDeviceState"},
{12, &MFIUser::GetNpadId, "GetNpadId"}, {12, &MFIUser::GetNpadId, "GetNpadId"},
{13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, {13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
}; };
// clang-format on // clang-format on
@ -131,7 +135,7 @@ public:
explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} { explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, {0, &NFC_AM::CreateAmNfcInterface, "CreateAmNfcInterface"},
}; };
// clang-format on // clang-format on
@ -139,7 +143,7 @@ public:
} }
private: private:
void CreateAmInterface(HLERequestContext& ctx) { void CreateAmNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -153,7 +157,7 @@ public:
explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, {0, &NFC_MF_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
}; };
// clang-format on // clang-format on
@ -161,7 +165,7 @@ public:
} }
private: private:
void CreateUserInterface(HLERequestContext& ctx) { void CreateUserNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -175,7 +179,7 @@ public:
explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} { explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, {0, &NFC_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
}; };
// clang-format on // clang-format on
@ -183,7 +187,7 @@ public:
} }
private: private:
void CreateUserInterface(HLERequestContext& ctx) { void CreateUserNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -197,7 +201,7 @@ public:
explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} { explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, {0, &NFC_SYS::CreateSystemNfcInterface, "CreateSystemNfcInterface"},
}; };
// clang-format on // clang-format on
@ -205,7 +209,7 @@ public:
} }
private: private:
void CreateSystemInterface(HLERequestContext& ctx) { void CreateSystemNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -221,6 +225,7 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system)); server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system));
server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system)); server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system));
server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system)); server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system));
ServerManager::RunServer(std::move(server_manager)); ServerManager::RunServer(std::move(server_manager));
} }

@ -1,287 +0,0 @@
// 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/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/nfc_device.h"
#include "core/hle/service/nfc/nfc_result.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 (!is_initalized) {
return;
}
if (type == Core::HID::ControllerTriggerType::Connected) {
Initialize();
availability_change_event->Signal();
return;
}
if (type == Core::HID::ControllerTriggerType::Disconnected) {
device_state = NFP::DeviceState::Unavailable;
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;
}
tag_data.resize(data.size());
memcpy(tag_data.data(), data.data(), data.size());
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 = {};
is_initalized = true;
}
void NfcDevice::Finalize() {
if (device_state == NFP::DeviceState::SearchingForTag ||
device_state == NFP::DeviceState::TagRemoved) {
StopDetection();
}
device_state = NFP::DeviceState::Unavailable;
is_initalized = false;
}
Result NfcDevice::StartDetection(NFP::TagProtocol allowed_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(Core::HID::EmulatedDeviceIndex::RightIndex,
Common::Input::PollingMode::NFC) !=
Common::Input::DriverResult::Success) {
LOG_ERROR(Service_NFC, "Nfc not supported");
return NfcDisabled;
}
device_state = NFP::DeviceState::SearchingForTag;
allowed_protocols = allowed_protocol;
return ResultSuccess;
}
Result NfcDevice::StopDetection() {
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
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::Flush() {
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;
}
if (!npad_device->WriteNfc(tag_data)) {
LOG_ERROR(Service_NFP, "Error writing to file");
return MifareReadError;
}
return ResultSuccess;
}
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) 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;
}
if (is_mifare) {
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::Type4,
};
return ResultSuccess;
}
// 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;
}
Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
NFP::MifareReadBlockData& read_block_data) {
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
read_block_data.sector_number = parameter.sector_number;
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;
}
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
return MifareReadError;
}
// TODO: Use parameter.sector_key to read encrypted data
memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
return ResultSuccess;
}
Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
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;
}
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
return MifareReadError;
}
// TODO: Use parameter.sector_key to encrypt the data
memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
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

@ -1,78 +0,0 @@
// 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(NFP::TagProtocol allowed_protocol);
Result StopDetection();
Result Flush();
Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
NFP::MifareReadBlockData& read_block_data);
Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
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;
bool is_initalized{};
NFP::TagProtocol allowed_protocols{};
NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
NFP::EncryptedNTAG215File encrypted_tag_data{};
std::vector<u8> tag_data{};
};
} // namespace Service::NFC

@ -6,55 +6,56 @@
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/nfc_device.h" #include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfc/common/device_manager.h"
#include "core/hle/service/nfc/mifare_result.h"
#include "core/hle/service/nfc/mifare_types.h"
#include "core/hle/service/nfc/nfc_interface.h" #include "core/hle/service/nfc/nfc_interface.h"
#include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/nfc/nfc_result.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/nfp/nfp_result.h"
#include "core/hle/service/time/clock_types.h" #include "core/hle/service/time/clock_types.h"
namespace Service::NFC { namespace Service::NFC {
Interface::Interface(Core::System& system_, const char* name) NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
: ServiceFramework{system_, name}, service_context{system_, service_name} { : ServiceFramework{system_, name}, service_context{system_, service_name},
availability_change_event = service_context.CreateEvent("Interface:AvailabilityChangeEvent"); backend_type{service_backend} {}
for (u32 device_index = 0; device_index < 10; device_index++) { NfcInterface ::~NfcInterface() = default;
devices[device_index] =
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
service_context, availability_change_event);
}
}
Interface ::~Interface() { void NfcInterface::Initialize(HLERequestContext& ctx) {
availability_change_event->Close();
}
void Interface::Initialize(HLERequestContext& ctx) {
LOG_INFO(Service_NFC, "called"); LOG_INFO(Service_NFC, "called");
state = State::Initialized; auto manager = GetManager();
auto result = manager->Initialize();
for (auto& device : devices) { if (result.IsSuccess()) {
device->Initialize(); state = State::Initialized;
} else {
manager->Finalize();
} }
IPC::ResponseBuilder rb{ctx, 2, 0}; IPC::ResponseBuilder rb{ctx, 2, 0};
rb.Push(ResultSuccess); rb.Push(result);
} }
void Interface::Finalize(HLERequestContext& ctx) { void NfcInterface::Finalize(HLERequestContext& ctx) {
LOG_INFO(Service_NFC, "called"); LOG_INFO(Service_NFC, "called");
state = State::NonInitialized; if (state != State::NonInitialized) {
if (GetBackendType() != BackendType::None) {
for (auto& device : devices) { GetManager()->Finalize();
device->Finalize(); }
device_manager = nullptr;
state = State::NonInitialized;
} }
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void Interface::GetState(HLERequestContext& ctx) { void NfcInterface::GetState(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
@ -62,50 +63,28 @@ void Interface::GetState(HLERequestContext& ctx) {
rb.PushEnum(state); rb.PushEnum(state);
} }
void Interface::IsNfcEnabled(HLERequestContext& ctx) { void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called"); LOG_DEBUG(Service_NFC, "called");
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
const bool is_enabled = true;
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(state != State::NonInitialized); rb.Push(is_enabled);
} }
void Interface::ListDevices(HLERequestContext& ctx) { void NfcInterface::ListDevices(HLERequestContext& ctx) {
LOG_DEBUG(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; std::vector<u64> nfp_devices;
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
LOG_DEBUG(Service_NFC, "called");
for (auto& device : devices) { auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
if (nfp_devices.size() >= max_allowed_devices) { result = TranslateResultToServiceError(result);
continue;
}
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
nfp_devices.push_back(device->GetHandle());
}
}
if (nfp_devices.empty()) { if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(DeviceNotFound); rb.Push(result);
return; return;
} }
@ -116,210 +95,177 @@ void Interface::ListDevices(HLERequestContext& ctx) {
rb.Push(static_cast<s32>(nfp_devices.size())); rb.Push(static_cast<s32>(nfp_devices.size()));
} }
void Interface::GetDeviceState(HLERequestContext& ctx) { void NfcInterface::GetDeviceState(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
auto device = GetNfcDevice(device_handle); const auto device_state = GetManager()->GetDeviceState(device_handle);
if (!device.has_value()) { if (device_state > DeviceState::Finalized) {
ASSERT_MSG(false, "Invalid device state");
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(device_state);
}
void NfcInterface::GetNpadId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
Core::HID::NpadIdType npad_id{};
auto result = GetManager()->GetNpadId(device_handle, npad_id);
result = TranslateResultToServiceError(result);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(DeviceNotFound); rb.Push(result);
return; return;
} }
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushEnum(device.value()->GetCurrentState()); rb.PushEnum(npad_id);
} }
void Interface::GetNpadId(HLERequestContext& ctx) { void NfcInterface::AttachAvailabilityChangeEvent(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 Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
LOG_INFO(Service_NFC, "called"); LOG_INFO(Service_NFC, "called");
if (state == State::NonInitialized) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(NfcDisabled);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 1}; IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushCopyObjects(availability_change_event->GetReadableEvent()); rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
} }
void Interface::StartDetection(HLERequestContext& ctx) { void NfcInterface::StartDetection(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()}; const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
if (state == State::NonInitialized) { auto result = GetManager()->StartDetection(device_handle, tag_protocol);
IPC::ResponseBuilder rb{ctx, 2}; result = TranslateResultToServiceError(result);
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}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);
} }
void Interface::StopDetection(HLERequestContext& ctx) { void NfcInterface::StopDetection(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
if (state == State::NonInitialized) { auto result = GetManager()->StopDetection(device_handle);
IPC::ResponseBuilder rb{ctx, 2}; result = TranslateResultToServiceError(result);
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}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);
} }
void Interface::GetTagInfo(HLERequestContext& ctx) { void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
if (state == State::NonInitialized) { TagInfo tag_info{};
IPC::ResponseBuilder rb{ctx, 2}; auto result =
rb.Push(NfcDisabled); GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
return; result = TranslateResultToServiceError(result);
if (result.IsSuccess()) {
ctx.WriteBuffer(tag_info);
} }
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, false);
ctx.WriteBuffer(tag_info);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result); rb.Push(result);
} }
void Interface::AttachActivateEvent(HLERequestContext& ctx) { void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); 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}; IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushCopyObjects(device.value()->GetActivateEvent()); rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
} }
void Interface::AttachDeactivateEvent(HLERequestContext& ctx) { void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); 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}; IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushCopyObjects(device.value()->GetDeactivateEvent()); rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
} }
void Interface::SendCommandByPassThrough(HLERequestContext& ctx) { void NfcInterface::ReadMifare(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto buffer{ctx.ReadBuffer()};
const auto number_of_commands{ctx.GetReadBufferNumElements<MifareReadBlockParameter>()};
std::vector<MifareReadBlockParameter> read_commands(number_of_commands);
memcpy(read_commands.data(), buffer.data(),
number_of_commands * sizeof(MifareReadBlockParameter));
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
device_handle, number_of_commands);
std::vector<MifareReadBlockData> out_data(number_of_commands);
auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
result = TranslateResultToServiceError(result);
if (result.IsSuccess()) {
ctx.WriteBuffer(out_data);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void NfcInterface::WriteMifare(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto buffer{ctx.ReadBuffer()};
const auto number_of_commands{ctx.GetReadBufferNumElements<MifareWriteBlockParameter>()};
std::vector<MifareWriteBlockParameter> write_commands(number_of_commands);
memcpy(write_commands.data(), buffer.data(),
number_of_commands * sizeof(MifareWriteBlockParameter));
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
device_handle, number_of_commands);
auto result = GetManager()->WriteMifare(device_handle, write_commands);
result = TranslateResultToServiceError(result);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()}; const auto device_handle{rp.Pop<u64>()};
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
const auto command_data{ctx.ReadBuffer()}; const auto command_data{ctx.ReadBuffer()};
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
device_handle, timeout.ToSeconds(), command_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); std::vector<u8> out_data(1);
// TODO: Request data from nfc device auto result =
GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
result = TranslateResultToServiceError(result);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
ctx.WriteBuffer(out_data); ctx.WriteBuffer(out_data);
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
@ -327,13 +273,110 @@ void Interface::SendCommandByPassThrough(HLERequestContext& ctx) {
rb.Push(static_cast<u32>(out_data.size())); rb.Push(static_cast<u32>(out_data.size()));
} }
std::optional<std::shared_ptr<NfcDevice>> Interface::GetNfcDevice(u64 handle) { std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
for (auto& device : devices) { if (device_manager == nullptr) {
if (device->GetHandle() == handle) { device_manager = std::make_shared<DeviceManager>(system, service_context);
return device;
}
} }
return std::nullopt; return device_manager;
}
BackendType NfcInterface::GetBackendType() const {
return backend_type;
}
Result NfcInterface::TranslateResultToServiceError(Result result) const {
const auto backend = GetBackendType();
if (result.IsSuccess()) {
return result;
}
if (result.module != ErrorModule::NFC) {
return result;
}
switch (backend) {
case BackendType::Mifare:
return TranslateResultToNfp(result);
case BackendType::Nfp: {
return TranslateResultToNfp(result);
}
default:
if (result != ResultUnknown216) {
return result;
}
return ResultUnknown74;
}
}
Result NfcInterface::TranslateResultToNfp(Result result) const {
if (result == ResultDeviceNotFound) {
return NFP::ResultDeviceNotFound;
}
if (result == ResultInvalidArgument) {
return NFP::ResultInvalidArgument;
}
if (result == ResultWrongApplicationAreaSize) {
return NFP::ResultWrongApplicationAreaSize;
}
if (result == ResultWrongDeviceState) {
return NFP::ResultWrongDeviceState;
}
if (result == ResultUnknown74) {
return NFP::ResultUnknown74;
}
if (result == ResultNfcDisabled) {
return NFP::ResultNfcDisabled;
}
if (result == ResultNfcNotInitialized) {
return NFP::ResultNfcDisabled;
}
if (result == ResultWriteAmiiboFailed) {
return NFP::ResultWriteAmiiboFailed;
}
if (result == ResultTagRemoved) {
return NFP::ResultTagRemoved;
}
if (result == ResultRegistrationIsNotInitialized) {
return NFP::ResultRegistrationIsNotInitialized;
}
if (result == ResultApplicationAreaIsNotInitialized) {
return NFP::ResultApplicationAreaIsNotInitialized;
}
if (result == ResultCorruptedData) {
return NFP::ResultCorruptedData;
}
if (result == ResultWrongApplicationAreaId) {
return NFP::ResultWrongApplicationAreaId;
}
if (result == ResultApplicationAreaExist) {
return NFP::ResultApplicationAreaExist;
}
if (result == ResultNotAnAmiibo) {
return NFP::ResultNotAnAmiibo;
}
LOG_WARNING(Service_NFC, "Result conversion not handled");
return result;
}
Result NfcInterface::TranslateResultToMifare(Result result) const {
if (result == ResultDeviceNotFound) {
return Mifare::ResultDeviceNotFound;
}
if (result == ResultInvalidArgument) {
return Mifare::ResultInvalidArgument;
}
if (result == ResultWrongDeviceState) {
return Mifare::ResultWrongDeviceState;
}
if (result == ResultNfcDisabled) {
return Mifare::ResultNfcDisabled;
}
if (result == ResultTagRemoved) {
return Mifare::ResultTagRemoved;
}
LOG_WARNING(Service_NFC, "Result conversion not handled");
return result;
} }
} // namespace Service::NFC } // namespace Service::NFC

@ -3,20 +3,17 @@
#pragma once #pragma once
#include <array>
#include <memory>
#include <optional>
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfc/nfc_types.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Service::NFC { namespace Service::NFC {
class NfcDevice; class DeviceManager;
class Interface : public ServiceFramework<Interface> { class NfcInterface : public ServiceFramework<NfcInterface> {
public: public:
explicit Interface(Core::System& system_, const char* name); explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
~Interface(); ~NfcInterface();
void Initialize(HLERequestContext& ctx); void Initialize(HLERequestContext& ctx);
void Finalize(HLERequestContext& ctx); void Finalize(HLERequestContext& ctx);
@ -31,22 +28,22 @@ public:
void GetTagInfo(HLERequestContext& ctx); void GetTagInfo(HLERequestContext& ctx);
void AttachActivateEvent(HLERequestContext& ctx); void AttachActivateEvent(HLERequestContext& ctx);
void AttachDeactivateEvent(HLERequestContext& ctx); void AttachDeactivateEvent(HLERequestContext& ctx);
void ReadMifare(HLERequestContext& ctx);
void WriteMifare(HLERequestContext& ctx);
void SendCommandByPassThrough(HLERequestContext& ctx); void SendCommandByPassThrough(HLERequestContext& ctx);
private: protected:
enum class State : u32 { std::shared_ptr<DeviceManager> GetManager();
NonInitialized, BackendType GetBackendType() const;
Initialized, Result TranslateResultToServiceError(Result result) const;
}; Result TranslateResultToNfp(Result result) const;
Result TranslateResultToMifare(Result result) const;
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
std::array<std::shared_ptr<NfcDevice>, 10> devices{}; BackendType backend_type;
State state{State::NonInitialized}; State state{State::NonInitialized};
Kernel::KEvent* availability_change_event; std::shared_ptr<DeviceManager> device_manager = nullptr;
}; };
} // namespace Service::NFC } // namespace Service::NFC

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
@ -7,17 +7,22 @@
namespace Service::NFC { namespace Service::NFC {
constexpr Result DeviceNotFound(ErrorModule::NFC, 64); constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
constexpr Result InvalidArgument(ErrorModule::NFC, 65); constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
constexpr Result WrongDeviceState(ErrorModule::NFC, 73); constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
constexpr Result NfcDisabled(ErrorModule::NFC, 80); constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
constexpr Result TagRemoved(ErrorModule::NFC, 97); constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
constexpr Result ResultUnknown216(ErrorModule::NFC, 216);
} // namespace Service::NFC } // namespace Service::NFC

@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Service::NFC {
enum class BackendType : u32 {
None,
Nfc,
Nfp,
Mifare,
};
// This is nn::nfc::DeviceState
enum class DeviceState : u32 {
Initialized,
SearchingForTag,
TagFound,
TagRemoved,
TagMounted,
Unavailable,
Finalized,
};
// This is nn::nfc::State
enum class State : u32 {
NonInitialized,
Initialized,
};
// This is nn::nfc::TagType
enum class TagType : u32 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
enum class PackedTagType : u8 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony FeliCa RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
// This is nn::nfc::NfcProtocol
// Verify this enum. It might be completely wrong default protocol is 0x48
enum class NfcProtocol : u32 {
None,
TypeA = 1U << 0, // ISO14443A
TypeB = 1U << 1, // ISO14443B
TypeF = 1U << 2, // Sony FeliCa
Unknown1 = 1U << 3,
Unknown2 = 1U << 5,
All = 0xFFFFFFFFU,
};
// this is nn::nfc::TestWaveType
enum class TestWaveType : u32 {
Unknown,
};
using UniqueSerialNumber = std::array<u8, 7>;
using UniqueSerialNumberExtension = std::array<u8, 3>;
// This is nn::nfc::DeviceHandle
using DeviceHandle = u64;
// This is nn::nfc::TagInfo
struct TagInfo {
UniqueSerialNumber uuid;
UniqueSerialNumberExtension uuid_extension;
u8 uuid_length;
INSERT_PADDING_BYTES(0x15);
NfcProtocol protocol;
TagType tag_type;
INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
} // namespace Service::NFC

@ -13,7 +13,7 @@ class IUser final : public Interface {
public: public:
explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") { explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfoTyped<IUser> functions[] = {
{0, &IUser::Initialize, "Initialize"}, {0, &IUser::Initialize, "Initialize"},
{1, &IUser::Finalize, "Finalize"}, {1, &IUser::Finalize, "Finalize"},
{2, &IUser::ListDevices, "ListDevices"}, {2, &IUser::ListDevices, "ListDevices"},
@ -50,7 +50,7 @@ class ISystem final : public Interface {
public: public:
explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfoTyped<ISystem> functions[] = {
{0, &ISystem::InitializeSystem, "InitializeSystem"}, {0, &ISystem::InitializeSystem, "InitializeSystem"},
{1, &ISystem::FinalizeSystem, "FinalizeSystem"}, {1, &ISystem::FinalizeSystem, "FinalizeSystem"},
{2, &ISystem::ListDevices, "ListDevices"}, {2, &ISystem::ListDevices, "ListDevices"},
@ -89,7 +89,7 @@ class IDebug final : public Interface {
public: public:
explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfoTyped<IDebug> functions[] = {
{0, &IDebug::InitializeDebug, "InitializeDebug"}, {0, &IDebug::InitializeDebug, "InitializeDebug"},
{1, &IDebug::FinalizeDebug, "FinalizeDebug"}, {1, &IDebug::FinalizeDebug, "FinalizeDebug"},
{2, &IDebug::ListDevices, "ListDevices"}, {2, &IDebug::ListDevices, "ListDevices"},
@ -126,9 +126,9 @@ public:
{201, &IDebug::SetAll, "SetAll"}, {201, &IDebug::SetAll, "SetAll"},
{202, &IDebug::FlushDebug, "FlushDebug"}, {202, &IDebug::FlushDebug, "FlushDebug"},
{203, &IDebug::BreakTag, "BreakTag"}, {203, &IDebug::BreakTag, "BreakTag"},
{204, nullptr, "ReadBackupData"}, {204, &IDebug::ReadBackupData, "ReadBackupData"},
{205, nullptr, "WriteBackupData"}, {205, &IDebug::WriteBackupData, "WriteBackupData"},
{206, nullptr, "WriteNtf"}, {206, &IDebug::WriteNtf, "WriteNtf"},
}; };
// clang-format on // clang-format on

@ -1,120 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <vector>
#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::NFP {
class NfpDevice {
public:
NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
KernelHelpers::ServiceContext& service_context_,
Kernel::KEvent* availability_change_event_);
~NfpDevice();
void Initialize();
void Finalize();
Result StartDetection(TagProtocol allowed_protocol);
Result StopDetection();
Result Mount(MountTarget mount_target);
Result Unmount();
Result Flush();
Result FlushDebug();
Result FlushWithBreak(BreakType break_type);
Result GetTagInfo(TagInfo& tag_info) const;
Result GetCommonInfo(CommonInfo& common_info) const;
Result GetModelInfo(ModelInfo& model_info) const;
Result GetRegisterInfo(RegisterInfo& register_info) const;
Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const;
Result GetAdminInfo(AdminInfo& admin_info) const;
Result DeleteRegisterInfo();
Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name);
Result RestoreAmiibo();
Result Format();
Result OpenApplicationArea(u32 access_id);
Result GetApplicationAreaId(u32& application_area_id) const;
Result GetApplicationArea(std::vector<u8>& data) const;
Result SetApplicationArea(std::span<const u8> data);
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
Result DeleteApplicationArea();
Result ExistApplicationArea(bool& has_application_area);
Result GetAll(NfpData& data) const;
Result SetAll(const NfpData& data);
Result BreakTag(BreakType break_type);
Result ReadBackupData();
Result WriteBackupData();
Result WriteNtf();
u64 GetHandle() const;
u32 GetApplicationAreaSize() const;
DeviceState GetCurrentState() const;
Core::HID::NpadIdType GetNpadId() const;
Kernel::KReadableEvent& GetActivateEvent() const;
Kernel::KReadableEvent& GetDeactivateEvent() const;
private:
void NpadUpdate(Core::HID::ControllerTriggerType type);
bool LoadAmiibo(std::span<const u8> data);
void CloseAmiibo();
AmiiboName GetAmiiboName(const AmiiboSettings& settings) const;
void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name);
AmiiboDate GetAmiiboDate(s64 posix_time) const;
u64 RemoveVersionByte(u64 application_id) const;
void UpdateSettingsCrc();
void UpdateRegisterInfoCrc();
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;
bool is_initalized{};
bool is_data_moddified{};
bool is_app_area_open{};
bool is_plain_amiibo{};
TagProtocol allowed_protocols{};
s64 current_posix_time{};
MountTarget mount_target{MountTarget::None};
DeviceState device_state{DeviceState::Unavailable};
NTAG215File tag_data{};
EncryptedNTAG215File encrypted_tag_data{};
};
} // namespace Service::NFP

File diff suppressed because it is too large Load Diff

@ -1,32 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array>
#include <memory>
#include <optional>
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfc/nfc_interface.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Service::NFP { namespace Service::NFP {
class NfpDevice;
class Interface : public ServiceFramework<Interface> { class Interface : public NFC::NfcInterface {
public: public:
explicit Interface(Core::System& system_, const char* name); explicit Interface(Core::System& system_, const char* name);
~Interface() override; ~Interface() override;
void Initialize(HLERequestContext& ctx);
void InitializeSystem(HLERequestContext& ctx); void InitializeSystem(HLERequestContext& ctx);
void InitializeDebug(HLERequestContext& ctx); void InitializeDebug(HLERequestContext& ctx);
void Finalize(HLERequestContext& ctx);
void FinalizeSystem(HLERequestContext& ctx); void FinalizeSystem(HLERequestContext& ctx);
void FinalizeDebug(HLERequestContext& ctx); void FinalizeDebug(HLERequestContext& ctx);
void ListDevices(HLERequestContext& ctx);
void StartDetection(HLERequestContext& ctx);
void StopDetection(HLERequestContext& ctx);
void Mount(HLERequestContext& ctx); void Mount(HLERequestContext& ctx);
void Unmount(HLERequestContext& ctx); void Unmount(HLERequestContext& ctx);
void OpenApplicationArea(HLERequestContext& ctx); void OpenApplicationArea(HLERequestContext& ctx);
@ -35,17 +26,10 @@ public:
void Flush(HLERequestContext& ctx); void Flush(HLERequestContext& ctx);
void Restore(HLERequestContext& ctx); void Restore(HLERequestContext& ctx);
void CreateApplicationArea(HLERequestContext& ctx); void CreateApplicationArea(HLERequestContext& ctx);
void GetTagInfo(HLERequestContext& ctx);
void GetRegisterInfo(HLERequestContext& ctx); void GetRegisterInfo(HLERequestContext& ctx);
void GetCommonInfo(HLERequestContext& ctx); void GetCommonInfo(HLERequestContext& ctx);
void GetModelInfo(HLERequestContext& ctx); void GetModelInfo(HLERequestContext& ctx);
void AttachActivateEvent(HLERequestContext& ctx);
void AttachDeactivateEvent(HLERequestContext& ctx);
void GetState(HLERequestContext& ctx);
void GetDeviceState(HLERequestContext& ctx);
void GetNpadId(HLERequestContext& ctx);
void GetApplicationAreaSize(HLERequestContext& ctx); void GetApplicationAreaSize(HLERequestContext& ctx);
void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
void RecreateApplicationArea(HLERequestContext& ctx); void RecreateApplicationArea(HLERequestContext& ctx);
void Format(HLERequestContext& ctx); void Format(HLERequestContext& ctx);
void GetAdminInfo(HLERequestContext& ctx); void GetAdminInfo(HLERequestContext& ctx);
@ -61,21 +45,6 @@ public:
void ReadBackupData(HLERequestContext& ctx); void ReadBackupData(HLERequestContext& ctx);
void WriteBackupData(HLERequestContext& ctx); void WriteBackupData(HLERequestContext& ctx);
void WriteNtf(HLERequestContext& ctx); void WriteNtf(HLERequestContext& ctx);
private:
enum class State : u32 {
NonInitialized,
Initialized,
};
std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle);
KernelHelpers::ServiceContext service_context;
std::array<std::shared_ptr<NfpDevice>, 10> devices{};
State state{State::NonInitialized};
Kernel::KEvent* availability_change_event;
}; };
} // namespace Service::NFP } // namespace Service::NFP

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@ -7,18 +7,19 @@
namespace Service::NFP { namespace Service::NFP {
constexpr Result DeviceNotFound(ErrorModule::NFP, 64); constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64);
constexpr Result InvalidArgument(ErrorModule::NFP, 65); constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65);
constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68); constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
constexpr Result WrongDeviceState(ErrorModule::NFP, 73); constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73);
constexpr Result NfcDisabled(ErrorModule::NFP, 80); constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88); constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80);
constexpr Result TagRemoved(ErrorModule::NFP, 97); constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120); constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
constexpr Result CorruptedData(ErrorModule::NFP, 144); constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152); constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168); constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
constexpr Result NotAnAmiibo(ErrorModule::NFP, 178); constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
} // namespace Service::NFP } // namespace Service::NFP

@ -7,32 +7,19 @@
#include "common/swap.h" #include "common/swap.h"
#include "core/hle/service/mii/types.h" #include "core/hle/service/mii/types.h"
#include "core/hle/service/nfc/nfc_types.h"
namespace Service::NFP { namespace Service::NFP {
static constexpr std::size_t amiibo_name_length = 0xA; static constexpr std::size_t amiibo_name_length = 0xA;
static constexpr std::size_t application_id_version_offset = 0x1c; static constexpr std::size_t application_id_version_offset = 0x1c;
static constexpr std::size_t counter_limit = 0xffff; static constexpr std::size_t counter_limit = 0xffff;
enum class ServiceType : u32 { // This is nn::nfp::ModelType
User,
Debug,
System,
};
enum class DeviceState : u32 {
Initialized,
SearchingForTag,
TagFound,
TagRemoved,
TagMounted,
Unavailable,
Finalized,
};
enum class ModelType : u32 { enum class ModelType : u32 {
Amiibo, Amiibo,
}; };
// This is nn::nfp::MountTarget
enum class MountTarget : u32 { enum class MountTarget : u32 {
None, None,
Rom, Rom,
@ -72,35 +59,6 @@ enum class AmiiboSeries : u8 {
Diablo, Diablo,
}; };
enum class TagType : u32 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
enum class PackedTagType : u8 {
None,
Type1, // ISO14443A RW 96-2k bytes 106kbit/s
Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
// Verify this enum. It might be completely wrong default protocol is 0x48
enum class TagProtocol : u32 {
None,
TypeA = 1U << 0, // ISO14443A
TypeB = 1U << 1, // ISO14443B
TypeF = 1U << 2, // Sony Felica
Unknown1 = 1U << 3,
Unknown2 = 1U << 5,
All = 0xFFFFFFFFU,
};
enum class AppAreaVersion : u8 { enum class AppAreaVersion : u8 {
Nintendo3DS = 0, Nintendo3DS = 0,
NintendoWiiU = 1, NintendoWiiU = 1,
@ -115,6 +73,11 @@ enum class BreakType : u32 {
Unknown2, Unknown2,
}; };
enum class WriteType : u32 {
Unknown0,
Unknown1,
};
enum class CabinetMode : u8 { enum class CabinetMode : u8 {
StartNicknameAndOwnerSettings, StartNicknameAndOwnerSettings,
StartGameDataEraser, StartGameDataEraser,
@ -122,27 +85,16 @@ enum class CabinetMode : u8 {
StartFormatter, StartFormatter,
}; };
enum class MifareCmd : u8 {
AuthA = 0x60,
AuthB = 0x61,
Read = 0x30,
Write = 0xA0,
Transfer = 0xB0,
Decrement = 0xC0,
Increment = 0xC1,
Store = 0xC2
};
using UniqueSerialNumber = std::array<u8, 7>;
using LockBytes = std::array<u8, 2>; using LockBytes = std::array<u8, 2>;
using HashData = std::array<u8, 0x20>; using HashData = std::array<u8, 0x20>;
using ApplicationArea = std::array<u8, 0xD8>; using ApplicationArea = std::array<u8, 0xD8>;
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
using DataBlock = std::array<u8, 0x10>;
using KeyData = std::array<u8, 0x6>; // This is nn::nfp::TagInfo
using TagInfo = NFC::TagInfo;
struct TagUuid { struct TagUuid {
UniqueSerialNumber uid; NFC::UniqueSerialNumber uid;
u8 nintendo_id; u8 nintendo_id;
LockBytes lock_bytes; LockBytes lock_bytes;
}; };
@ -243,7 +195,7 @@ struct AmiiboModelInfo {
AmiiboType amiibo_type; AmiiboType amiibo_type;
u16_be model_number; u16_be model_number;
AmiiboSeries series; AmiiboSeries series;
PackedTagType tag_type; NFC::PackedTagType tag_type;
INSERT_PADDING_BYTES(0x4); // Unknown INSERT_PADDING_BYTES(0x4); // Unknown
}; };
static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size"); static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size");
@ -298,7 +250,7 @@ struct NTAG215File {
u32_be register_info_crc; u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data ApplicationArea application_area; // Encrypted Game data
HashData hmac_tag; // Hash HashData hmac_tag; // Hash
UniqueSerialNumber uid; // Unique serial number NFC::UniqueSerialNumber uid; // Unique serial number
u8 nintendo_id; // Tag UUID u8 nintendo_id; // Tag UUID
AmiiboModelInfo model_info; AmiiboModelInfo model_info;
HashData keygen_salt; // Salt HashData keygen_salt; // Salt
@ -326,17 +278,7 @@ static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File),
static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>, static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>,
"EncryptedNTAG215File must be trivially copyable."); "EncryptedNTAG215File must be trivially copyable.");
struct TagInfo { // This is nn::nfp::CommonInfo
UniqueSerialNumber uuid;
INSERT_PADDING_BYTES(0x3);
u8 uuid_length;
INSERT_PADDING_BYTES(0x15);
TagProtocol protocol;
TagType tag_type;
INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
struct CommonInfo { struct CommonInfo {
WriteDate last_write_date; WriteDate last_write_date;
u16 write_counter; u16 write_counter;
@ -347,6 +289,7 @@ struct CommonInfo {
}; };
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
// This is nn::nfp::ModelInfo
struct ModelInfo { struct ModelInfo {
u16 character_id; u16 character_id;
u8 character_variant; u8 character_variant;
@ -357,6 +300,7 @@ struct ModelInfo {
}; };
static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
// This is nn::nfp::RegisterInfo
struct RegisterInfo { struct RegisterInfo {
Service::Mii::CharInfo mii_char_info; Service::Mii::CharInfo mii_char_info;
WriteDate creation_date; WriteDate creation_date;
@ -366,6 +310,7 @@ struct RegisterInfo {
}; };
static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
// This is nn::nfp::RegisterInfoPrivate
struct RegisterInfoPrivate { struct RegisterInfoPrivate {
Service::Mii::MiiStoreData mii_store_data; Service::Mii::MiiStoreData mii_store_data;
WriteDate creation_date; WriteDate creation_date;
@ -375,12 +320,13 @@ struct RegisterInfoPrivate {
}; };
static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
// This is nn::nfp::AdminInfo
struct AdminInfo { struct AdminInfo {
u64 application_id; u64 application_id;
u32 application_area_id; u32 application_area_id;
u16 crc_change_counter; u16 crc_change_counter;
u8 flags; u8 flags;
PackedTagType tag_type; NFC::PackedTagType tag_type;
AppAreaVersion app_area_version; AppAreaVersion app_area_version;
INSERT_PADDING_BYTES(0x7); INSERT_PADDING_BYTES(0x7);
INSERT_PADDING_BYTES(0x28); INSERT_PADDING_BYTES(0x28);
@ -411,7 +357,7 @@ struct NfpData {
u32 access_id; u32 access_id;
u16 settings_crc_counter; u16 settings_crc_counter;
u8 font_region; u8 font_region;
PackedTagType tag_type; NFC::PackedTagType tag_type;
AppAreaVersion console_type; AppAreaVersion console_type;
u8 application_id_byte; u8 application_id_byte;
INSERT_PADDING_BYTES(0x2E); INSERT_PADDING_BYTES(0x2E);
@ -420,37 +366,4 @@ struct NfpData {
static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
#pragma pack() #pragma pack()
struct SectorKey {
MifareCmd command;
u8 unknown; // Usually 1
INSERT_PADDING_BYTES(0x6);
KeyData sector_key;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
struct MifareReadBlockParameter {
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
SectorKey sector_key;
};
static_assert(sizeof(MifareReadBlockParameter) == 0x18,
"MifareReadBlockParameter is an invalid size");
struct MifareReadBlockData {
DataBlock data;
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
};
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
struct MifareWriteBlockParameter {
DataBlock data;
u8 sector_number;
INSERT_PADDING_BYTES(0x7);
SectorKey sector_key;
};
static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
"MifareWriteBlockParameter is an invalid size");
} // namespace Service::NFP } // namespace Service::NFP

@ -8,7 +8,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfc/common/device.h"
#include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_result.h"
#include "input_common/drivers/virtual_amiibo.h" #include "input_common/drivers/virtual_amiibo.h"
#include "input_common/main.h" #include "input_common/main.h"
@ -22,7 +22,7 @@
QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent,
Core::Frontend::CabinetParameters parameters_, Core::Frontend::CabinetParameters parameters_,
InputCommon::InputSubsystem* input_subsystem_, InputCommon::InputSubsystem* input_subsystem_,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device_) std::shared_ptr<Service::NFC::NfcDevice> nfp_device_)
: QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()), : QDialog(parent), ui(std::make_unique<Ui::QtAmiiboSettingsDialog>()),
input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)}, input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)},
parameters(std::move(parameters_)) { parameters(std::move(parameters_)) {
@ -52,11 +52,11 @@ void QtAmiiboSettingsDialog::LoadInfo() {
return; return;
} }
if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
return; return;
} }
nfp_device->Mount(Service::NFP::MountTarget::All); nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
LoadAmiiboInfo(); LoadAmiiboInfo();
LoadAmiiboData(); LoadAmiiboData();
@ -261,7 +261,7 @@ void QtAmiiboSettings::Close() const {
void QtAmiiboSettings::ShowCabinetApplet( void QtAmiiboSettings::ShowCabinetApplet(
const Core::Frontend::CabinetCallback& callback_, const Core::Frontend::CabinetCallback& callback_,
const Core::Frontend::CabinetParameters& parameters, const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
callback = std::move(callback_); callback = std::move(callback_);
emit MainWindowShowAmiiboSettings(parameters, nfp_device); emit MainWindowShowAmiiboSettings(parameters, nfp_device);
} }

@ -23,9 +23,9 @@ namespace Ui {
class QtAmiiboSettingsDialog; class QtAmiiboSettingsDialog;
} }
namespace Service::NFP { namespace Service::NFC {
class NfpDevice; class NfcDevice;
} // namespace Service::NFP } // namespace Service::NFC
class QtAmiiboSettingsDialog final : public QDialog { class QtAmiiboSettingsDialog final : public QDialog {
Q_OBJECT Q_OBJECT
@ -33,7 +33,7 @@ class QtAmiiboSettingsDialog final : public QDialog {
public: public:
explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_,
InputCommon::InputSubsystem* input_subsystem_, InputCommon::InputSubsystem* input_subsystem_,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device_); std::shared_ptr<Service::NFC::NfcDevice> nfp_device_);
~QtAmiiboSettingsDialog() override; ~QtAmiiboSettingsDialog() override;
int exec() override; int exec() override;
@ -52,7 +52,7 @@ private:
std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui; std::unique_ptr<Ui::QtAmiiboSettingsDialog> ui;
InputCommon::InputSubsystem* input_subsystem; InputCommon::InputSubsystem* input_subsystem;
std::shared_ptr<Service::NFP::NfpDevice> nfp_device; std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
// Parameters sent in from the backend HLE applet. // Parameters sent in from the backend HLE applet.
Core::Frontend::CabinetParameters parameters; Core::Frontend::CabinetParameters parameters;
@ -71,11 +71,11 @@ public:
void Close() const override; void Close() const override;
void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_,
const Core::Frontend::CabinetParameters& parameters, const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
signals: signals:
void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const; std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const;
void MainWindowRequestExit() const; void MainWindowRequestExit() const;
private: private:

@ -570,8 +570,8 @@ void GMainWindow::RegisterMetaTypes() {
// Cabinet Applet // Cabinet Applet
qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters"); qRegisterMetaType<Core::Frontend::CabinetParameters>("Core::Frontend::CabinetParameters");
qRegisterMetaType<std::shared_ptr<Service::NFP::NfpDevice>>( qRegisterMetaType<std::shared_ptr<Service::NFC::NfcDevice>>(
"std::shared_ptr<Service::NFP::NfpDevice>"); "std::shared_ptr<Service::NFC::NfcDevice>");
// Controller Applet // Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters"); qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
@ -599,7 +599,7 @@ void GMainWindow::RegisterMetaTypes() {
} }
void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) { std::shared_ptr<Service::NFC::NfcDevice> nfp_device) {
cabinet_applet = cabinet_applet =
new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device); new QtAmiiboSettingsDialog(this, parameters, input_subsystem.get(), nfp_device);
SCOPE_EXIT({ SCOPE_EXIT({

@ -93,9 +93,9 @@ enum class SwkbdReplyType : u32;
enum class WebExitReason : u32; enum class WebExitReason : u32;
} // namespace Service::AM::Applets } // namespace Service::AM::Applets
namespace Service::NFP { namespace Service::NFC {
class NfpDevice; class NfcDevice;
} // namespace Service::NFP } // namespace Service::NFC
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -188,7 +188,7 @@ public slots:
void OnExit(); void OnExit();
void OnSaveConfig(); void OnSaveConfig();
void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device); std::shared_ptr<Service::NFC::NfcDevice> nfp_device);
void AmiiboSettingsRequestExit(); void AmiiboSettingsRequestExit();
void ControllerSelectorReconfigureControllers( void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters); const Core::Frontend::ControllerParameters& parameters);