early-access version 3566
This commit is contained in:
parent
ee3e26bfd1
commit
2aa90dd2b4
29 changed files with 3673 additions and 1048 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3565.
|
This is the source code for early-access 3566.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -554,21 +554,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{};
|
||||||
|
|
405
src/core/hle/service/nfc/common/amiibo_crypto.cpp
Executable file
405
src/core/hle/service/nfc/common/amiibo_crypto.cpp
Executable file
|
@ -0,0 +1,405 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2017 socram8888/amiitool
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <mbedtls/aes.h>
|
||||||
|
#include <mbedtls/hmac_drbg.h>
|
||||||
|
|
||||||
|
#include "common/fs/file.h"
|
||||||
|
#include "common/fs/fs.h"
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/hle/service/nfc/common/amiibo_crypto.h"
|
||||||
|
|
||||||
|
namespace Service::NFP::AmiiboCrypto {
|
||||||
|
|
||||||
|
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
|
||||||
|
const auto& amiibo_data = ntag_file.user_memory;
|
||||||
|
LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock);
|
||||||
|
LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container);
|
||||||
|
LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter));
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
|
||||||
|
LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant);
|
||||||
|
LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type);
|
||||||
|
LOG_DEBUG(Service_NFP, "model_number=0x{0:x}",
|
||||||
|
static_cast<u16>(amiibo_data.model_info.model_number));
|
||||||
|
LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series);
|
||||||
|
LOG_DEBUG(Service_NFP, "tag_type=0x{0:x}", amiibo_data.model_info.tag_type);
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", ntag_file.dynamic_lock);
|
||||||
|
LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", ntag_file.CFG0);
|
||||||
|
LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", ntag_file.CFG1);
|
||||||
|
|
||||||
|
// Validate UUID
|
||||||
|
constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3`
|
||||||
|
if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) !=
|
||||||
|
ntag_file.uuid.uid[3]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^
|
||||||
|
ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against all know constants on an amiibo binary
|
||||||
|
if (ntag_file.static_lock != 0xE00F) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ntag_file.compability_container != 0xEEFF10F1U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (amiibo_data.constant_value != 0xA5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ntag_file.CFG0 != 0x04000000U) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ntag_file.CFG1 != 0x5F) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAmiiboValid(const NTAG215File& ntag_file) {
|
||||||
|
return IsAmiiboValid(EncodedDataToNfcData(ntag_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
|
||||||
|
NTAG215File encoded_data{};
|
||||||
|
|
||||||
|
encoded_data.uid = nfc_data.uuid.uid;
|
||||||
|
encoded_data.nintendo_id = nfc_data.uuid.nintendo_id;
|
||||||
|
encoded_data.static_lock = nfc_data.static_lock;
|
||||||
|
encoded_data.compability_container = nfc_data.compability_container;
|
||||||
|
encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
|
||||||
|
encoded_data.constant_value = nfc_data.user_memory.constant_value;
|
||||||
|
encoded_data.write_counter = nfc_data.user_memory.write_counter;
|
||||||
|
encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version;
|
||||||
|
encoded_data.settings = nfc_data.user_memory.settings;
|
||||||
|
encoded_data.owner_mii = nfc_data.user_memory.owner_mii;
|
||||||
|
encoded_data.application_id = nfc_data.user_memory.application_id;
|
||||||
|
encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter;
|
||||||
|
encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
|
||||||
|
encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;
|
||||||
|
encoded_data.unknown = nfc_data.user_memory.unknown;
|
||||||
|
encoded_data.mii_extension = nfc_data.user_memory.mii_extension;
|
||||||
|
encoded_data.unknown2 = nfc_data.user_memory.unknown2;
|
||||||
|
encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
|
||||||
|
encoded_data.application_area = nfc_data.user_memory.application_area;
|
||||||
|
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
|
||||||
|
encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
|
||||||
|
encoded_data.model_info = nfc_data.user_memory.model_info;
|
||||||
|
encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt;
|
||||||
|
encoded_data.dynamic_lock = nfc_data.dynamic_lock;
|
||||||
|
encoded_data.CFG0 = nfc_data.CFG0;
|
||||||
|
encoded_data.CFG1 = nfc_data.CFG1;
|
||||||
|
encoded_data.password = nfc_data.password;
|
||||||
|
|
||||||
|
return encoded_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
|
||||||
|
EncryptedNTAG215File nfc_data{};
|
||||||
|
|
||||||
|
nfc_data.uuid.uid = encoded_data.uid;
|
||||||
|
nfc_data.uuid.nintendo_id = encoded_data.nintendo_id;
|
||||||
|
nfc_data.uuid.lock_bytes = encoded_data.lock_bytes;
|
||||||
|
nfc_data.static_lock = encoded_data.static_lock;
|
||||||
|
nfc_data.compability_container = encoded_data.compability_container;
|
||||||
|
nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
|
||||||
|
nfc_data.user_memory.constant_value = encoded_data.constant_value;
|
||||||
|
nfc_data.user_memory.write_counter = encoded_data.write_counter;
|
||||||
|
nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version;
|
||||||
|
nfc_data.user_memory.settings = encoded_data.settings;
|
||||||
|
nfc_data.user_memory.owner_mii = encoded_data.owner_mii;
|
||||||
|
nfc_data.user_memory.application_id = encoded_data.application_id;
|
||||||
|
nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter;
|
||||||
|
nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
|
||||||
|
nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;
|
||||||
|
nfc_data.user_memory.unknown = encoded_data.unknown;
|
||||||
|
nfc_data.user_memory.mii_extension = encoded_data.mii_extension;
|
||||||
|
nfc_data.user_memory.unknown2 = encoded_data.unknown2;
|
||||||
|
nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc;
|
||||||
|
nfc_data.user_memory.application_area = encoded_data.application_area;
|
||||||
|
nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag;
|
||||||
|
nfc_data.user_memory.model_info = encoded_data.model_info;
|
||||||
|
nfc_data.user_memory.keygen_salt = encoded_data.keygen_salt;
|
||||||
|
nfc_data.dynamic_lock = encoded_data.dynamic_lock;
|
||||||
|
nfc_data.CFG0 = encoded_data.CFG0;
|
||||||
|
nfc_data.CFG1 = encoded_data.CFG1;
|
||||||
|
nfc_data.password = encoded_data.password;
|
||||||
|
|
||||||
|
return nfc_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetTagPassword(const TagUuid& uuid) {
|
||||||
|
// Verify that the generated password is correct
|
||||||
|
u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]);
|
||||||
|
password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8;
|
||||||
|
password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16;
|
||||||
|
password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24;
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashSeed GetSeed(const NTAG215File& data) {
|
||||||
|
HashSeed seed{
|
||||||
|
.magic = data.write_counter,
|
||||||
|
.padding = {},
|
||||||
|
.uid_1 = data.uid,
|
||||||
|
.nintendo_id_1 = data.nintendo_id,
|
||||||
|
.uid_2 = data.uid,
|
||||||
|
.nintendo_id_2 = data.nintendo_id,
|
||||||
|
.keygen_salt = data.keygen_salt,
|
||||||
|
};
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed) {
|
||||||
|
const std::size_t seedPart1Len = sizeof(key.magic_bytes) - key.magic_length;
|
||||||
|
const std::size_t string_size = key.type_string.size();
|
||||||
|
std::vector<u8> output(string_size + seedPart1Len);
|
||||||
|
|
||||||
|
// Copy whole type string
|
||||||
|
memccpy(output.data(), key.type_string.data(), '\0', string_size);
|
||||||
|
|
||||||
|
// Append (16 - magic_length) from the input seed
|
||||||
|
memcpy(output.data() + string_size, &seed, seedPart1Len);
|
||||||
|
|
||||||
|
// Append all bytes from magicBytes
|
||||||
|
output.insert(output.end(), key.magic_bytes.begin(),
|
||||||
|
key.magic_bytes.begin() + key.magic_length);
|
||||||
|
|
||||||
|
output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end());
|
||||||
|
output.emplace_back(seed.nintendo_id_1);
|
||||||
|
output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end());
|
||||||
|
output.emplace_back(seed.nintendo_id_2);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) {
|
||||||
|
output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
|
||||||
|
const std::vector<u8>& seed) {
|
||||||
|
// Initialize context
|
||||||
|
ctx.used = false;
|
||||||
|
ctx.counter = 0;
|
||||||
|
ctx.buffer_size = sizeof(ctx.counter) + seed.size();
|
||||||
|
memcpy(ctx.buffer.data() + sizeof(u16), seed.data(), seed.size());
|
||||||
|
|
||||||
|
// Initialize HMAC context
|
||||||
|
mbedtls_md_init(&hmac_ctx);
|
||||||
|
mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
|
||||||
|
mbedtls_md_hmac_starts(&hmac_ctx, hmac_key.data(), hmac_key.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output) {
|
||||||
|
// If used at least once, reinitialize the HMAC
|
||||||
|
if (ctx.used) {
|
||||||
|
mbedtls_md_hmac_reset(&hmac_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.used = true;
|
||||||
|
|
||||||
|
// Store counter in big endian, and increment it
|
||||||
|
ctx.buffer[0] = static_cast<u8>(ctx.counter >> 8);
|
||||||
|
ctx.buffer[1] = static_cast<u8>(ctx.counter >> 0);
|
||||||
|
ctx.counter++;
|
||||||
|
|
||||||
|
// Do HMAC magic
|
||||||
|
mbedtls_md_hmac_update(&hmac_ctx, reinterpret_cast<const unsigned char*>(ctx.buffer.data()),
|
||||||
|
ctx.buffer_size);
|
||||||
|
mbedtls_md_hmac_finish(&hmac_ctx, output.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data) {
|
||||||
|
const auto seed = GetSeed(data);
|
||||||
|
|
||||||
|
// Generate internal seed
|
||||||
|
const std::vector<u8> internal_key = GenerateInternalKey(key, seed);
|
||||||
|
|
||||||
|
// Initialize context
|
||||||
|
CryptoCtx ctx{};
|
||||||
|
mbedtls_md_context_t hmac_ctx;
|
||||||
|
CryptoInit(ctx, hmac_ctx, key.hmac_key, internal_key);
|
||||||
|
|
||||||
|
// Generate derived keys
|
||||||
|
DerivedKeys derived_keys{};
|
||||||
|
std::array<DrgbOutput, 2> temp{};
|
||||||
|
CryptoStep(ctx, hmac_ctx, temp[0]);
|
||||||
|
CryptoStep(ctx, hmac_ctx, temp[1]);
|
||||||
|
memcpy(&derived_keys, temp.data(), sizeof(DerivedKeys));
|
||||||
|
|
||||||
|
// Cleanup context
|
||||||
|
mbedtls_md_free(&hmac_ctx);
|
||||||
|
|
||||||
|
return derived_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data) {
|
||||||
|
mbedtls_aes_context aes;
|
||||||
|
std::size_t nc_off = 0;
|
||||||
|
std::array<u8, sizeof(keys.aes_iv)> nonce_counter{};
|
||||||
|
std::array<u8, sizeof(keys.aes_iv)> stream_block{};
|
||||||
|
|
||||||
|
const auto aes_key_size = static_cast<u32>(keys.aes_key.size() * 8);
|
||||||
|
mbedtls_aes_setkey_enc(&aes, keys.aes_key.data(), aes_key_size);
|
||||||
|
memcpy(nonce_counter.data(), keys.aes_iv.data(), sizeof(keys.aes_iv));
|
||||||
|
|
||||||
|
constexpr std::size_t encrypted_data_size = HMAC_TAG_START - SETTINGS_START;
|
||||||
|
mbedtls_aes_crypt_ctr(&aes, encrypted_data_size, &nc_off, nonce_counter.data(),
|
||||||
|
stream_block.data(),
|
||||||
|
reinterpret_cast<const unsigned char*>(&in_data.settings),
|
||||||
|
reinterpret_cast<unsigned char*>(&out_data.settings));
|
||||||
|
|
||||||
|
// Copy the rest of the data directly
|
||||||
|
out_data.uid = in_data.uid;
|
||||||
|
out_data.nintendo_id = in_data.nintendo_id;
|
||||||
|
out_data.lock_bytes = in_data.lock_bytes;
|
||||||
|
out_data.static_lock = in_data.static_lock;
|
||||||
|
out_data.compability_container = in_data.compability_container;
|
||||||
|
|
||||||
|
out_data.constant_value = in_data.constant_value;
|
||||||
|
out_data.write_counter = in_data.write_counter;
|
||||||
|
|
||||||
|
out_data.model_info = in_data.model_info;
|
||||||
|
out_data.keygen_salt = in_data.keygen_salt;
|
||||||
|
out_data.dynamic_lock = in_data.dynamic_lock;
|
||||||
|
out_data.CFG0 = in_data.CFG0;
|
||||||
|
out_data.CFG1 = in_data.CFG1;
|
||||||
|
out_data.password = in_data.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info) {
|
||||||
|
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
|
||||||
|
|
||||||
|
const Common::FS::IOFile keys_file{yuzu_keys_dir / "key_retail.bin",
|
||||||
|
Common::FS::FileAccessMode::Read,
|
||||||
|
Common::FS::FileType::BinaryFile};
|
||||||
|
|
||||||
|
if (!keys_file.IsOpen()) {
|
||||||
|
LOG_ERROR(Service_NFP, "Failed to open key file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys_file.Read(unfixed_info) != 1) {
|
||||||
|
LOG_ERROR(Service_NFP, "Failed to read unfixed_info");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (keys_file.Read(locked_secret) != 1) {
|
||||||
|
LOG_ERROR(Service_NFP, "Failed to read locked-secret");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsKeyAvailable() {
|
||||||
|
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
|
||||||
|
return Common::FS::Exists(yuzu_keys_dir / "key_retail.bin");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data) {
|
||||||
|
InternalKey locked_secret{};
|
||||||
|
InternalKey unfixed_info{};
|
||||||
|
|
||||||
|
if (!LoadKeys(locked_secret, unfixed_info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate keys
|
||||||
|
NTAG215File encoded_data = NfcDataToEncodedData(encrypted_tag_data);
|
||||||
|
const auto data_keys = GenerateKey(unfixed_info, encoded_data);
|
||||||
|
const auto tag_keys = GenerateKey(locked_secret, encoded_data);
|
||||||
|
|
||||||
|
// Decrypt
|
||||||
|
Cipher(data_keys, encoded_data, tag_data);
|
||||||
|
|
||||||
|
// Regenerate tag HMAC. Note: order matters, data HMAC depends on tag HMAC!
|
||||||
|
constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START;
|
||||||
|
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(),
|
||||||
|
sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid),
|
||||||
|
input_length, reinterpret_cast<unsigned char*>(&tag_data.hmac_tag));
|
||||||
|
|
||||||
|
// Regenerate data HMAC
|
||||||
|
constexpr std::size_t input_length2 = DYNAMIC_LOCK_START - WRITE_COUNTER_START;
|
||||||
|
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), data_keys.hmac_key.data(),
|
||||||
|
sizeof(HmacKey),
|
||||||
|
reinterpret_cast<const unsigned char*>(&tag_data.write_counter), input_length2,
|
||||||
|
reinterpret_cast<unsigned char*>(&tag_data.hmac_data));
|
||||||
|
|
||||||
|
if (tag_data.hmac_data != encrypted_tag_data.user_memory.hmac_data) {
|
||||||
|
LOG_ERROR(Service_NFP, "hmac_data doesn't match");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag_data.hmac_tag != encrypted_tag_data.user_memory.hmac_tag) {
|
||||||
|
LOG_ERROR(Service_NFP, "hmac_tag doesn't match");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_tag_data) {
|
||||||
|
InternalKey locked_secret{};
|
||||||
|
InternalKey unfixed_info{};
|
||||||
|
|
||||||
|
if (!LoadKeys(locked_secret, unfixed_info)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate keys
|
||||||
|
const auto data_keys = GenerateKey(unfixed_info, tag_data);
|
||||||
|
const auto tag_keys = GenerateKey(locked_secret, tag_data);
|
||||||
|
|
||||||
|
NTAG215File encoded_tag_data{};
|
||||||
|
|
||||||
|
// Generate tag HMAC
|
||||||
|
constexpr std::size_t input_length = DYNAMIC_LOCK_START - UUID_START;
|
||||||
|
constexpr std::size_t input_length2 = HMAC_TAG_START - WRITE_COUNTER_START;
|
||||||
|
mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), tag_keys.hmac_key.data(),
|
||||||
|
sizeof(HmacKey), reinterpret_cast<const unsigned char*>(&tag_data.uid),
|
||||||
|
input_length, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag));
|
||||||
|
|
||||||
|
// Init mbedtls HMAC context
|
||||||
|
mbedtls_md_context_t ctx;
|
||||||
|
mbedtls_md_init(&ctx);
|
||||||
|
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
|
||||||
|
|
||||||
|
// Generate data HMAC
|
||||||
|
mbedtls_md_hmac_starts(&ctx, data_keys.hmac_key.data(), sizeof(HmacKey));
|
||||||
|
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.write_counter),
|
||||||
|
input_length2); // Data
|
||||||
|
mbedtls_md_hmac_update(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_tag),
|
||||||
|
sizeof(HashData)); // Tag HMAC
|
||||||
|
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char*>(&tag_data.uid),
|
||||||
|
input_length);
|
||||||
|
mbedtls_md_hmac_finish(&ctx, reinterpret_cast<unsigned char*>(&encoded_tag_data.hmac_data));
|
||||||
|
|
||||||
|
// HMAC cleanup
|
||||||
|
mbedtls_md_free(&ctx);
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
Cipher(data_keys, tag_data, encoded_tag_data);
|
||||||
|
|
||||||
|
// Convert back to hardware
|
||||||
|
encrypted_tag_data = EncodedDataToNfcData(encoded_tag_data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::NFP::AmiiboCrypto
|
106
src/core/hle/service/nfc/common/amiibo_crypto.h
Executable file
106
src/core/hle/service/nfc/common/amiibo_crypto.h
Executable file
|
@ -0,0 +1,106 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "core/hle/service/nfp/nfp_types.h"
|
||||||
|
|
||||||
|
struct mbedtls_md_context_t;
|
||||||
|
|
||||||
|
namespace Service::NFP::AmiiboCrypto {
|
||||||
|
// Byte locations in Service::NFP::NTAG215File
|
||||||
|
constexpr std::size_t HMAC_DATA_START = 0x8;
|
||||||
|
constexpr std::size_t SETTINGS_START = 0x2c;
|
||||||
|
constexpr std::size_t WRITE_COUNTER_START = 0x29;
|
||||||
|
constexpr std::size_t HMAC_TAG_START = 0x1B4;
|
||||||
|
constexpr std::size_t UUID_START = 0x1D4;
|
||||||
|
constexpr std::size_t DYNAMIC_LOCK_START = 0x208;
|
||||||
|
|
||||||
|
using HmacKey = std::array<u8, 0x10>;
|
||||||
|
using DrgbOutput = std::array<u8, 0x20>;
|
||||||
|
|
||||||
|
struct HashSeed {
|
||||||
|
u16_be magic;
|
||||||
|
std::array<u8, 0xE> padding;
|
||||||
|
NFC::UniqueSerialNumber uid_1;
|
||||||
|
u8 nintendo_id_1;
|
||||||
|
NFC::UniqueSerialNumber uid_2;
|
||||||
|
u8 nintendo_id_2;
|
||||||
|
std::array<u8, 0x20> keygen_salt;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size");
|
||||||
|
|
||||||
|
struct InternalKey {
|
||||||
|
HmacKey hmac_key;
|
||||||
|
std::array<char, 0xE> type_string;
|
||||||
|
u8 reserved;
|
||||||
|
u8 magic_length;
|
||||||
|
std::array<u8, 0x10> magic_bytes;
|
||||||
|
std::array<u8, 0x20> xor_pad;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(InternalKey) == 0x50, "InternalKey is an invalid size");
|
||||||
|
static_assert(std::is_trivially_copyable_v<InternalKey>, "InternalKey must be trivially copyable.");
|
||||||
|
|
||||||
|
struct CryptoCtx {
|
||||||
|
std::array<char, 480> buffer;
|
||||||
|
bool used;
|
||||||
|
std::size_t buffer_size;
|
||||||
|
s16 counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DerivedKeys {
|
||||||
|
std::array<u8, 0x10> aes_key;
|
||||||
|
std::array<u8, 0x10> aes_iv;
|
||||||
|
std::array<u8, 0x10> hmac_key;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(DerivedKeys) == 0x30, "DerivedKeys is an invalid size");
|
||||||
|
|
||||||
|
/// Validates that the amiibo file is not corrupted
|
||||||
|
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file);
|
||||||
|
|
||||||
|
/// Validates that the amiibo file is not corrupted
|
||||||
|
bool IsAmiiboValid(const NTAG215File& ntag_file);
|
||||||
|
|
||||||
|
/// Converts from encrypted file format to encoded file format
|
||||||
|
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data);
|
||||||
|
|
||||||
|
/// Converts from encoded file format to encrypted file format
|
||||||
|
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data);
|
||||||
|
|
||||||
|
/// Returns password needed to allow write access to protected memory
|
||||||
|
u32 GetTagPassword(const TagUuid& uuid);
|
||||||
|
|
||||||
|
// Generates Seed needed for key derivation
|
||||||
|
HashSeed GetSeed(const NTAG215File& data);
|
||||||
|
|
||||||
|
// Middle step on the generation of derived keys
|
||||||
|
std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed);
|
||||||
|
|
||||||
|
// Initializes mbedtls context
|
||||||
|
void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key,
|
||||||
|
const std::vector<u8>& seed);
|
||||||
|
|
||||||
|
// Feeds data to mbedtls context to generate the derived key
|
||||||
|
void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output);
|
||||||
|
|
||||||
|
// Generates the derived key from amiibo data
|
||||||
|
DerivedKeys GenerateKey(const InternalKey& key, const NTAG215File& data);
|
||||||
|
|
||||||
|
// Encodes or decodes amiibo data
|
||||||
|
void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& out_data);
|
||||||
|
|
||||||
|
/// Loads both amiibo keys from key_retail.bin
|
||||||
|
bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info);
|
||||||
|
|
||||||
|
/// Returns true if key_retail.bin exist
|
||||||
|
bool IsKeyAvailable();
|
||||||
|
|
||||||
|
/// Decodes encrypted amiibo data returns true if output is valid
|
||||||
|
bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data);
|
||||||
|
|
||||||
|
/// Encodes plain amiibo data returns true if output is valid
|
||||||
|
bool EncodeAmiibo(const NTAG215File& tag_data, EncryptedNTAG215File& encrypted_tag_data);
|
||||||
|
|
||||||
|
} // namespace Service::NFP::AmiiboCrypto
|
1249
src/core/hle/service/nfc/common/device.cpp
Executable file
1249
src/core/hle/service/nfc/common/device.cpp
Executable file
File diff suppressed because it is too large
Load diff
138
src/core/hle/service/nfc/common/device.h
Executable file
138
src/core/hle/service/nfc/common/device.h
Executable file
|
@ -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
|
695
src/core/hle/service/nfc/common/device_manager.cpp
Executable file
695
src/core/hle/service/nfc/common/device_manager.cpp
Executable file
|
@ -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
|
100
src/core/hle/service/nfc/common/device_manager.h
Executable file
100
src/core/hle/service/nfc/common/device_manager.h
Executable file
|
@ -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
|
17
src/core/hle/service/nfc/mifare_result.h
Executable file
17
src/core/hle/service/nfc/mifare_result.h
Executable file
|
@ -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
|
63
src/core/hle/service/nfc/mifare_types.h
Executable file
63
src/core/hle/service/nfc/mifare_types.h
Executable file
|
@ -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,14 +6,115 @@
|
||||||
#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_user.h"
|
|
||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
#include "core/hle/service/nfc/nfc_user.h"
|
#include "core/hle/service/nfc/nfc_interface.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Service::NFC {
|
namespace Service::NFC {
|
||||||
|
|
||||||
|
class IUser final : public NfcInterface {
|
||||||
|
public:
|
||||||
|
explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &NfcInterface::Initialize, "InitializeOld"},
|
||||||
|
{1, &NfcInterface::Finalize, "FinalizeOld"},
|
||||||
|
{2, &NfcInterface::GetState, "GetStateOld"},
|
||||||
|
{3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
|
||||||
|
{400, &NfcInterface::Initialize, "Initialize"},
|
||||||
|
{401, &NfcInterface::Finalize, "Finalize"},
|
||||||
|
{402, &NfcInterface::GetState, "GetState"},
|
||||||
|
{403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
|
||||||
|
{404, &NfcInterface::ListDevices, "ListDevices"},
|
||||||
|
{405, &NfcInterface::GetDeviceState, "GetDeviceState"},
|
||||||
|
{406, &NfcInterface::GetNpadId, "GetNpadId"},
|
||||||
|
{407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||||
|
{408, &NfcInterface::StartDetection, "StartDetection"},
|
||||||
|
{409, &NfcInterface::StopDetection, "StopDetection"},
|
||||||
|
{410, &NfcInterface::GetTagInfo, "GetTagInfo"},
|
||||||
|
{411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
|
||||||
|
{412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
|
||||||
|
{1000, &NfcInterface::ReadMifare, "ReadMifare"},
|
||||||
|
{1001, &NfcInterface::WriteMifare ,"WriteMifare"},
|
||||||
|
{1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
|
||||||
|
{1301, nullptr, "KeepPassThroughSession"},
|
||||||
|
{1302, nullptr, "ReleasePassThroughSession"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ISystem final : public NfcInterface {
|
||||||
|
public:
|
||||||
|
explicit ISystem(Core::System& system_)
|
||||||
|
: NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &NfcInterface::Initialize, "InitializeOld"},
|
||||||
|
{1, &NfcInterface::Finalize, "FinalizeOld"},
|
||||||
|
{2, &NfcInterface::GetState, "GetStateOld"},
|
||||||
|
{3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
|
||||||
|
{100, nullptr, "SetNfcEnabledOld"},
|
||||||
|
{400, &NfcInterface::Initialize, "Initialize"},
|
||||||
|
{401, &NfcInterface::Finalize, "Finalize"},
|
||||||
|
{402, &NfcInterface::GetState, "GetState"},
|
||||||
|
{403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
|
||||||
|
{404, &NfcInterface::ListDevices, "ListDevices"},
|
||||||
|
{405, &NfcInterface::GetDeviceState, "GetDeviceState"},
|
||||||
|
{406, &NfcInterface::GetNpadId, "GetNpadId"},
|
||||||
|
{407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
|
||||||
|
{408, &NfcInterface::StartDetection, "StartDetection"},
|
||||||
|
{409, &NfcInterface::StopDetection, "StopDetection"},
|
||||||
|
{410, &NfcInterface::GetTagInfo, "GetTagInfo"},
|
||||||
|
{411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
|
||||||
|
{412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
|
||||||
|
{500, nullptr, "SetNfcEnabled"},
|
||||||
|
{510, nullptr, "OutputTestWave"},
|
||||||
|
{1000, &NfcInterface::ReadMifare, "ReadMifare"},
|
||||||
|
{1001, &NfcInterface::WriteMifare, "WriteMifare"},
|
||||||
|
{1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
|
||||||
|
{1301, nullptr, "KeepPassThroughSession"},
|
||||||
|
{1302, nullptr, "ReleasePassThroughSession"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
public:
|
||||||
|
explicit MFIUser(Core::System& system_)
|
||||||
|
: MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
|
||||||
|
// clang-format off
|
||||||
|
static const FunctionInfoTyped<MFIUser> functions[] = {
|
||||||
|
{0, &MFIUser::Initialize, "Initialize"},
|
||||||
|
{1, &MFIUser::Finalize, "Finalize"},
|
||||||
|
{2, &MFIUser::ListDevices, "ListDevices"},
|
||||||
|
{3, &MFIUser::StartDetection, "StartDetection"},
|
||||||
|
{4, &MFIUser::StopDetection, "StopDetection"},
|
||||||
|
{5, &MFIUser::ReadMifare, "Read"},
|
||||||
|
{6, &MFIUser::WriteMifare, "Write"},
|
||||||
|
{7, &MFIUser::GetTagInfo, "GetTagInfo"},
|
||||||
|
{8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
|
||||||
|
{9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
|
||||||
|
{10, &MFIUser::GetState, "GetState"},
|
||||||
|
{11, &MFIUser::GetDeviceState, "GetDeviceState"},
|
||||||
|
{12, &MFIUser::GetNpadId, "GetNpadId"},
|
||||||
|
{13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class IAm final : public ServiceFramework<IAm> {
|
class IAm final : public ServiceFramework<IAm> {
|
||||||
public:
|
public:
|
||||||
explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
|
explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
|
||||||
|
@ -34,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
|
||||||
|
|
||||||
|
@ -42,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};
|
||||||
|
@ -56,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
|
||||||
|
|
||||||
|
@ -64,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};
|
||||||
|
@ -78,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
|
||||||
|
|
||||||
|
@ -86,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};
|
||||||
|
@ -95,49 +196,12 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISystem final : public ServiceFramework<ISystem> {
|
|
||||||
public:
|
|
||||||
explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
|
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, nullptr, "Initialize"},
|
|
||||||
{1, nullptr, "Finalize"},
|
|
||||||
{2, nullptr, "GetStateOld"},
|
|
||||||
{3, nullptr, "IsNfcEnabledOld"},
|
|
||||||
{100, nullptr, "SetNfcEnabledOld"},
|
|
||||||
{400, nullptr, "InitializeSystem"},
|
|
||||||
{401, nullptr, "FinalizeSystem"},
|
|
||||||
{402, nullptr, "GetState"},
|
|
||||||
{403, nullptr, "IsNfcEnabled"},
|
|
||||||
{404, nullptr, "ListDevices"},
|
|
||||||
{405, nullptr, "GetDeviceState"},
|
|
||||||
{406, nullptr, "GetNpadId"},
|
|
||||||
{407, nullptr, "AttachAvailabilityChangeEvent"},
|
|
||||||
{408, nullptr, "StartDetection"},
|
|
||||||
{409, nullptr, "StopDetection"},
|
|
||||||
{410, nullptr, "GetTagInfo"},
|
|
||||||
{411, nullptr, "AttachActivateEvent"},
|
|
||||||
{412, nullptr, "AttachDeactivateEvent"},
|
|
||||||
{500, nullptr, "SetNfcEnabled"},
|
|
||||||
{510, nullptr, "OutputTestWave"},
|
|
||||||
{1000, nullptr, "ReadMifare"},
|
|
||||||
{1001, nullptr, "WriteMifare"},
|
|
||||||
{1300, nullptr, "SendCommandByPassThrough"},
|
|
||||||
{1301, nullptr, "KeepPassThroughSession"},
|
|
||||||
{1302, nullptr, "ReleasePassThroughSession"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class NFC_SYS final : public ServiceFramework<NFC_SYS> {
|
class NFC_SYS final : public ServiceFramework<NFC_SYS> {
|
||||||
public:
|
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
|
||||||
|
|
||||||
|
@ -145,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};
|
||||||
|
@ -161,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
382
src/core/hle/service/nfc/nfc_interface.cpp
Executable file
382
src/core/hle/service/nfc/nfc_interface.cpp
Executable file
|
@ -0,0 +1,382 @@
|
||||||
|
// 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/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_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"
|
||||||
|
|
||||||
|
namespace Service::NFC {
|
||||||
|
|
||||||
|
NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
|
||||||
|
: ServiceFramework{system_, name}, service_context{system_, service_name},
|
||||||
|
backend_type{service_backend} {}
|
||||||
|
|
||||||
|
NfcInterface ::~NfcInterface() = default;
|
||||||
|
|
||||||
|
void NfcInterface::Initialize(HLERequestContext& ctx) {
|
||||||
|
LOG_INFO(Service_NFC, "called");
|
||||||
|
|
||||||
|
auto manager = GetManager();
|
||||||
|
auto result = manager->Initialize();
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
state = State::Initialized;
|
||||||
|
} else {
|
||||||
|
manager->Finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 0};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::Finalize(HLERequestContext& ctx) {
|
||||||
|
LOG_INFO(Service_NFC, "called");
|
||||||
|
|
||||||
|
if (state != State::NonInitialized) {
|
||||||
|
if (GetBackendType() != BackendType::None) {
|
||||||
|
GetManager()->Finalize();
|
||||||
|
}
|
||||||
|
device_manager = nullptr;
|
||||||
|
state = State::NonInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::GetState(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_NFC, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushEnum(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_NFC, "called");
|
||||||
|
|
||||||
|
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
|
||||||
|
const bool is_enabled = true;
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(is_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::ListDevices(HLERequestContext& ctx) {
|
||||||
|
std::vector<u64> nfp_devices;
|
||||||
|
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
|
||||||
|
LOG_DEBUG(Service_NFC, "called");
|
||||||
|
|
||||||
|
auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
|
||||||
|
result = TranslateResultToServiceError(result);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.WriteBuffer(nfp_devices);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(static_cast<s32>(nfp_devices.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::GetDeviceState(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||||
|
|
||||||
|
const auto device_state = GetManager()->GetDeviceState(device_handle);
|
||||||
|
|
||||||
|
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};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushEnum(npad_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
|
||||||
|
LOG_INFO(Service_NFC, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::StartDetection(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
const auto tag_protocol{rp.PopEnum<NfcProtocol>()};
|
||||||
|
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
|
||||||
|
|
||||||
|
auto result = GetManager()->StartDetection(device_handle, tag_protocol);
|
||||||
|
result = TranslateResultToServiceError(result);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::StopDetection(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||||
|
|
||||||
|
auto result = GetManager()->StopDetection(device_handle);
|
||||||
|
result = TranslateResultToServiceError(result);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
|
||||||
|
|
||||||
|
TagInfo tag_info{};
|
||||||
|
auto result =
|
||||||
|
GetManager()->GetTagInfo(device_handle, tag_info, backend_type == BackendType::Mifare);
|
||||||
|
result = TranslateResultToServiceError(result);
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
ctx.WriteBuffer(tag_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
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};
|
||||||
|
const auto device_handle{rp.Pop<u64>()};
|
||||||
|
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
|
||||||
|
const auto command_data{ctx.ReadBuffer()};
|
||||||
|
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
|
||||||
|
device_handle, timeout.ToSeconds(), command_data.size());
|
||||||
|
|
||||||
|
std::vector<u8> out_data(1);
|
||||||
|
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);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(static_cast<u32>(out_data.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
|
||||||
|
if (device_manager == nullptr) {
|
||||||
|
device_manager = std::make_shared<DeviceManager>(system, service_context);
|
||||||
|
}
|
||||||
|
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
|
49
src/core/hle/service/nfc/nfc_interface.h
Executable file
49
src/core/hle/service/nfc/nfc_interface.h
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/kernel_helpers.h"
|
||||||
|
#include "core/hle/service/nfc/nfc_types.h"
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Service::NFC {
|
||||||
|
class DeviceManager;
|
||||||
|
|
||||||
|
class NfcInterface : public ServiceFramework<NfcInterface> {
|
||||||
|
public:
|
||||||
|
explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
|
||||||
|
~NfcInterface();
|
||||||
|
|
||||||
|
void Initialize(HLERequestContext& ctx);
|
||||||
|
void Finalize(HLERequestContext& ctx);
|
||||||
|
void GetState(HLERequestContext& ctx);
|
||||||
|
void IsNfcEnabled(HLERequestContext& ctx);
|
||||||
|
void ListDevices(HLERequestContext& ctx);
|
||||||
|
void GetDeviceState(HLERequestContext& ctx);
|
||||||
|
void GetNpadId(HLERequestContext& ctx);
|
||||||
|
void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
|
||||||
|
void StartDetection(HLERequestContext& ctx);
|
||||||
|
void StopDetection(HLERequestContext& ctx);
|
||||||
|
void GetTagInfo(HLERequestContext& ctx);
|
||||||
|
void AttachActivateEvent(HLERequestContext& ctx);
|
||||||
|
void AttachDeactivateEvent(HLERequestContext& ctx);
|
||||||
|
void ReadMifare(HLERequestContext& ctx);
|
||||||
|
void WriteMifare(HLERequestContext& ctx);
|
||||||
|
void SendCommandByPassThrough(HLERequestContext& ctx);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<DeviceManager> GetManager();
|
||||||
|
BackendType GetBackendType() const;
|
||||||
|
Result TranslateResultToServiceError(Result result) const;
|
||||||
|
Result TranslateResultToNfp(Result result) const;
|
||||||
|
Result TranslateResultToMifare(Result result) const;
|
||||||
|
|
||||||
|
KernelHelpers::ServiceContext service_context;
|
||||||
|
|
||||||
|
BackendType backend_type;
|
||||||
|
State state{State::NonInitialized};
|
||||||
|
std::shared_ptr<DeviceManager> device_manager = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // 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
|
||||||
|
|
90
src/core/hle/service/nfc/nfc_types.h
Executable file
90
src/core/hle/service/nfc/nfc_types.h
Executable file
|
@ -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
|
||||||
|
|
||||||
|
@ -152,16 +152,10 @@ private:
|
||||||
void CreateUserInterface(HLERequestContext& ctx) {
|
void CreateUserInterface(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NFP, "called");
|
LOG_DEBUG(Service_NFP, "called");
|
||||||
|
|
||||||
if (user_interface == nullptr) {
|
|
||||||
user_interface = std::make_shared<IUser>(system);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IUser>(user_interface);
|
rb.PushIpcInterface<IUser>(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IUser> user_interface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISystemManager final : public ServiceFramework<ISystemManager> {
|
class ISystemManager final : public ServiceFramework<ISystemManager> {
|
||||||
|
@ -180,16 +174,10 @@ private:
|
||||||
void CreateSystemInterface(HLERequestContext& ctx) {
|
void CreateSystemInterface(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NFP, "called");
|
LOG_DEBUG(Service_NFP, "called");
|
||||||
|
|
||||||
if (system_interface == nullptr) {
|
|
||||||
system_interface = std::make_shared<ISystem>(system);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ISystem>(system_interface);
|
rb.PushIpcInterface<ISystem>(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ISystem> system_interface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class IDebugManager final : public ServiceFramework<IDebugManager> {
|
class IDebugManager final : public ServiceFramework<IDebugManager> {
|
||||||
|
@ -208,16 +196,10 @@ private:
|
||||||
void CreateDebugInterface(HLERequestContext& ctx) {
|
void CreateDebugInterface(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NFP, "called");
|
LOG_DEBUG(Service_NFP, "called");
|
||||||
|
|
||||||
if (system_interface == nullptr) {
|
|
||||||
system_interface = std::make_shared<IDebug>(system);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IDebug>(system_interface);
|
rb.PushIpcInterface<IDebug>(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<IDebug> system_interface;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
|
|
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
|
||||||
|
|
|
@ -142,7 +142,8 @@ template <typename Self>
|
||||||
class ServiceFramework : public ServiceFrameworkBase {
|
class ServiceFramework : public ServiceFrameworkBase {
|
||||||
protected:
|
protected:
|
||||||
/// Contains information about a request type which is handled by the service.
|
/// Contains information about a request type which is handled by the service.
|
||||||
struct FunctionInfo : FunctionInfoBase {
|
template <typename T>
|
||||||
|
struct FunctionInfoTyped : FunctionInfoBase {
|
||||||
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
|
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
|
||||||
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
|
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
|
||||||
|
|
||||||
|
@ -155,12 +156,13 @@ protected:
|
||||||
* the request
|
* the request
|
||||||
* @param name_ human-friendly name for the request. Used mostly for logging purposes.
|
* @param name_ human-friendly name for the request. Used mostly for logging purposes.
|
||||||
*/
|
*/
|
||||||
FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
|
FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
|
||||||
: FunctionInfoBase{
|
: FunctionInfoBase{
|
||||||
expected_header_,
|
expected_header_,
|
||||||
// Type-erase member function pointer by casting it down to the base class.
|
// Type-erase member function pointer by casting it down to the base class.
|
||||||
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
|
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
|
||||||
};
|
};
|
||||||
|
using FunctionInfo = FunctionInfoTyped<Self>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the handler with no functions installed.
|
* Initializes the handler with no functions installed.
|
||||||
|
@ -175,8 +177,8 @@ protected:
|
||||||
: ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
|
: ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
|
||||||
|
|
||||||
/// Registers handlers in the service.
|
/// Registers handlers in the service.
|
||||||
template <std::size_t N>
|
template <typename T = Self, std::size_t N>
|
||||||
void RegisterHandlers(const FunctionInfo (&functions)[N]) {
|
void RegisterHandlers(const FunctionInfoTyped<T> (&functions)[N]) {
|
||||||
RegisterHandlers(functions, N);
|
RegisterHandlers(functions, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,13 +186,14 @@ protected:
|
||||||
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
|
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
|
||||||
* overload in order to avoid needing to specify the array size.
|
* overload in order to avoid needing to specify the array size.
|
||||||
*/
|
*/
|
||||||
void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
|
template <typename T = Self>
|
||||||
|
void RegisterHandlers(const FunctionInfoTyped<T>* functions, std::size_t n) {
|
||||||
RegisterHandlersBase(functions, n);
|
RegisterHandlersBase(functions, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers handlers in the service.
|
/// Registers handlers in the service.
|
||||||
template <std::size_t N>
|
template <typename T = Self, std::size_t N>
|
||||||
void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
|
void RegisterHandlersTipc(const FunctionInfoTyped<T> (&functions)[N]) {
|
||||||
RegisterHandlersTipc(functions, N);
|
RegisterHandlersTipc(functions, N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +201,8 @@ protected:
|
||||||
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
|
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
|
||||||
* overload in order to avoid needing to specify the array size.
|
* overload in order to avoid needing to specify the array size.
|
||||||
*/
|
*/
|
||||||
void RegisterHandlersTipc(const FunctionInfo* functions, std::size_t n) {
|
template <typename T = Self>
|
||||||
|
void RegisterHandlersTipc(const FunctionInfoTyped<T>* functions, std::size_t n) {
|
||||||
RegisterHandlersBaseTipc(functions, n);
|
RegisterHandlersBaseTipc(functions, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -571,8 +571,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");
|
||||||
|
@ -600,7 +600,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);
|
||||||
|
|
Loading…
Reference in a new issue