Browse Source
Merge pull request #10097 from german77/nfp_full
Merge pull request #10097 from german77/nfp_full
service: nfc: Merge device interfaces and create the device managernce_cpp
committed by
GitHub
34 changed files with 2254 additions and 2632 deletions
-
21src/core/CMakeLists.txt
-
2src/core/frontend/applets/cabinet.cpp
-
10src/core/frontend/applets/cabinet.h
-
24src/core/hle/service/am/applets/applet_cabinet.cpp
-
6src/core/hle/service/am/applets/applet_cabinet.h
-
4src/core/hle/service/nfc/common/amiibo_crypto.cpp
-
4src/core/hle/service/nfc/common/amiibo_crypto.h
-
672src/core/hle/service/nfc/common/device.cpp
-
138src/core/hle/service/nfc/common/device.h
-
695src/core/hle/service/nfc/common/device_manager.cpp
-
100src/core/hle/service/nfc/common/device_manager.h
-
17src/core/hle/service/nfc/mifare_result.h
-
63src/core/hle/service/nfc/mifare_types.h
-
400src/core/hle/service/nfc/mifare_user.cpp
-
52src/core/hle/service/nfc/mifare_user.h
-
159src/core/hle/service/nfc/nfc.cpp
-
288src/core/hle/service/nfc/nfc_device.cpp
-
78src/core/hle/service/nfc/nfc_device.h
-
382src/core/hle/service/nfc/nfc_interface.cpp
-
33src/core/hle/service/nfc/nfc_interface.h
-
33src/core/hle/service/nfc/nfc_result.h
-
90src/core/hle/service/nfc/nfc_types.h
-
365src/core/hle/service/nfc/nfc_user.cpp
-
36src/core/hle/service/nfp/nfp.cpp
-
120src/core/hle/service/nfp/nfp_device.h
-
839src/core/hle/service/nfp/nfp_interface.cpp
-
37src/core/hle/service/nfp/nfp_interface.h
-
29src/core/hle/service/nfp/nfp_result.h
-
129src/core/hle/service/nfp/nfp_types.h
-
20src/core/hle/service/service.h
-
12src/yuzu/applets/qt_amiibo_settings.cpp
-
14src/yuzu/applets/qt_amiibo_settings.h
-
6src/yuzu/main.cpp
-
8src/yuzu/main.h
672
src/core/hle/service/nfc/common/device.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View 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 |
|||
@ -0,0 +1,695 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|||
|
|||
#include "common/logging/log.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hid/hid_types.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/nfc/common/device.h"
|
|||
#include "core/hle/service/nfc/common/device_manager.h"
|
|||
#include "core/hle/service/nfc/nfc_result.h"
|
|||
#include "core/hle/service/time/clock_types.h"
|
|||
|
|||
namespace Service::NFC { |
|||
|
|||
DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_) |
|||
: system{system_}, service_context{service_context_} { |
|||
|
|||
availability_change_event = |
|||
service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent"); |
|||
|
|||
for (u32 device_index = 0; device_index < devices.size(); device_index++) { |
|||
devices[device_index] = |
|||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, |
|||
service_context, availability_change_event); |
|||
} |
|||
|
|||
is_initialized = false; |
|||
} |
|||
|
|||
DeviceManager ::~DeviceManager() { |
|||
service_context.CloseEvent(availability_change_event); |
|||
} |
|||
|
|||
Result DeviceManager::Initialize() { |
|||
for (auto& device : devices) { |
|||
device->Initialize(); |
|||
} |
|||
is_initialized = true; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DeviceManager::Finalize() { |
|||
for (auto& device : devices) { |
|||
device->Finalize(); |
|||
} |
|||
is_initialized = false; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, |
|||
std::size_t max_allowed_devices) const { |
|||
for (auto& device : devices) { |
|||
if (nfp_devices.size() >= max_allowed_devices) { |
|||
continue; |
|||
} |
|||
if (device->GetCurrentState() != DeviceState::Unavailable) { |
|||
nfp_devices.push_back(device->GetHandle()); |
|||
} |
|||
} |
|||
|
|||
if (nfp_devices.empty()) { |
|||
return ResultDeviceNotFound; |
|||
} |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
DeviceState DeviceManager::GetDeviceState(u64 device_handle) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
const auto result = GetDeviceFromHandle(device_handle, device, false); |
|||
|
|||
if (result.IsSuccess()) { |
|||
return device->GetCurrentState(); |
|||
} |
|||
|
|||
return DeviceState::Unavailable; |
|||
} |
|||
|
|||
Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetNpadId(npad_id); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const { |
|||
return availability_change_event->GetReadableEvent(); |
|||
} |
|||
|
|||
Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->StartDetection(tag_protocol); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::StopDetection(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->StopDetection(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetTagInfo(tag_info, is_mifare); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
GetDeviceFromHandle(device_handle, device, false); |
|||
|
|||
// TODO: Return proper error code on failure
|
|||
return device->GetActivateEvent(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
GetDeviceFromHandle(device_handle, device, false); |
|||
|
|||
// TODO: Return proper error code on failure
|
|||
return device->GetDeactivateEvent(); |
|||
} |
|||
|
|||
Result DeviceManager::ReadMifare(u64 device_handle, |
|||
std::span<const MifareReadBlockParameter> read_parameters, |
|||
std::span<MifareReadBlockData> read_data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->ReadMifare(read_parameters, read_data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::WriteMifare(u64 device_handle, |
|||
std::span<const MifareWriteBlockParameter> write_parameters) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->WriteMifare(write_parameters); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::SendCommandByPassThrough(u64 device_handle, |
|||
const Time::Clock::TimeSpanType& timeout, |
|||
std::span<const u8> command_data, |
|||
std::span<u8> out_data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->SendCommandByPassThrough(timeout, command_data, out_data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type, |
|||
NFP::MountTarget mount_target) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->Mount(model_type, mount_target); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::Unmount(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->Unmount(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->OpenApplicationArea(access_id); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetApplicationArea(data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->SetApplicationArea(data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::Flush(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->Flush(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::Restore(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->Restore(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id, |
|||
std::span<const u8> data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->CreateApplicationArea(access_id, data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetRegisterInfo(register_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetCommonInfo(common_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetModelInfo(model_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
u32 DeviceManager::GetApplicationAreaSize() const { |
|||
return sizeof(NFP::ApplicationArea); |
|||
} |
|||
|
|||
Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id, |
|||
std::span<const u8> data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->RecreateApplicationArea(access_id, data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::Format(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->Format(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetAdminInfo(admin_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle, |
|||
NFP::RegisterInfoPrivate& register_info) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetRegisterInfoPrivate(register_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle, |
|||
const NFP::RegisterInfoPrivate& register_info) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->SetRegisterInfoPrivate(register_info); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::DeleteRegisterInfo(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->DeleteRegisterInfo(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::DeleteApplicationArea(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->DeleteApplicationArea(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->ExistsApplicationArea(has_application_area); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->GetAll(nfp_data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->SetAll(nfp_data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::FlushDebug(u64 device_handle) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->FlushDebug(); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->BreakTag(break_type); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->ReadBackupData(data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->WriteBackupData(data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
std::shared_ptr<NfcDevice> device = nullptr; |
|||
auto result = GetDeviceHandle(device_handle, device); |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device->WriteNtf(data); |
|||
result = VerifyDeviceResult(device, result); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device, |
|||
bool check_state) const { |
|||
if (check_state) { |
|||
const Result is_parameter_set = IsNfcParameterSet(); |
|||
if (is_parameter_set.IsError()) { |
|||
return is_parameter_set; |
|||
} |
|||
const Result is_enabled = IsNfcEnabled(); |
|||
if (is_enabled.IsError()) { |
|||
return is_enabled; |
|||
} |
|||
const Result is_nfc_initialized = IsNfcInitialized(); |
|||
if (is_nfc_initialized.IsError()) { |
|||
return is_nfc_initialized; |
|||
} |
|||
} |
|||
|
|||
for (auto& device : devices) { |
|||
if (device->GetHandle() == handle) { |
|||
nfc_device = device; |
|||
return ResultSuccess; |
|||
} |
|||
} |
|||
|
|||
return ResultDeviceNotFound; |
|||
} |
|||
|
|||
std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) { |
|||
for (auto& device : devices) { |
|||
if (device->GetHandle() == handle) { |
|||
return device; |
|||
} |
|||
} |
|||
return std::nullopt; |
|||
} |
|||
|
|||
const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const { |
|||
for (auto& device : devices) { |
|||
if (device->GetHandle() == handle) { |
|||
return device; |
|||
} |
|||
} |
|||
return std::nullopt; |
|||
} |
|||
|
|||
Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const { |
|||
const auto result = GetDeviceFromHandle(handle, device, true); |
|||
if (result.IsError()) { |
|||
return result; |
|||
} |
|||
return CheckDeviceState(device); |
|||
} |
|||
|
|||
Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, |
|||
Result operation_result) const { |
|||
if (operation_result.IsSuccess()) { |
|||
return operation_result; |
|||
} |
|||
|
|||
const Result is_parameter_set = IsNfcParameterSet(); |
|||
if (is_parameter_set.IsError()) { |
|||
return is_parameter_set; |
|||
} |
|||
const Result is_enabled = IsNfcEnabled(); |
|||
if (is_enabled.IsError()) { |
|||
return is_enabled; |
|||
} |
|||
const Result is_nfc_initialized = IsNfcInitialized(); |
|||
if (is_nfc_initialized.IsError()) { |
|||
return is_nfc_initialized; |
|||
} |
|||
const Result device_state = CheckDeviceState(device); |
|||
if (device_state.IsError()) { |
|||
return device_state; |
|||
} |
|||
|
|||
return operation_result; |
|||
} |
|||
|
|||
Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const { |
|||
if (device == nullptr) { |
|||
return ResultInvalidArgument; |
|||
} |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DeviceManager::IsNfcEnabled() const { |
|||
// TODO: This calls nn::settings::detail::GetNfcEnableFlag
|
|||
const bool is_enabled = true; |
|||
if (!is_enabled) { |
|||
return ResultNfcDisabled; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DeviceManager::IsNfcParameterSet() const { |
|||
// TODO: This calls checks against a bool on offset 0x450
|
|||
const bool is_set = true; |
|||
if (!is_set) { |
|||
return ResultUnknown76; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DeviceManager::IsNfcInitialized() const { |
|||
if (!is_initialized) { |
|||
return ResultNfcNotInitialized; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
} // namespace Service::NFC
|
|||
@ -0,0 +1,100 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <memory> |
|||
#include <optional> |
|||
#include <span> |
|||
|
|||
#include "core/hid/hid_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/nfc/mifare_types.h" |
|||
#include "core/hle/service/nfc/nfc_types.h" |
|||
#include "core/hle/service/nfp/nfp_types.h" |
|||
#include "core/hle/service/service.h" |
|||
#include "core/hle/service/time/clock_types.h" |
|||
|
|||
namespace Service::NFC { |
|||
class NfcDevice; |
|||
|
|||
class DeviceManager { |
|||
public: |
|||
explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_); |
|||
~DeviceManager(); |
|||
|
|||
// Nfc device manager |
|||
Result Initialize(); |
|||
Result Finalize(); |
|||
Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const; |
|||
DeviceState GetDeviceState(u64 device_handle) const; |
|||
Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const; |
|||
Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; |
|||
Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); |
|||
Result StopDetection(u64 device_handle); |
|||
Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info, bool is_mifare) const; |
|||
Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; |
|||
Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; |
|||
Result ReadMifare(u64 device_handle, |
|||
const std::span<const MifareReadBlockParameter> read_parameters, |
|||
std::span<MifareReadBlockData> read_data); |
|||
Result WriteMifare(u64 device_handle, |
|||
std::span<const MifareWriteBlockParameter> write_parameters); |
|||
Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout, |
|||
std::span<const u8> command_data, std::span<u8> out_data); |
|||
|
|||
// Nfp device manager |
|||
Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target); |
|||
Result Unmount(u64 device_handle); |
|||
Result OpenApplicationArea(u64 device_handle, u32 access_id); |
|||
Result GetApplicationArea(u64 device_handle, std::span<u8> data) const; |
|||
Result SetApplicationArea(u64 device_handle, std::span<const u8> data); |
|||
Result Flush(u64 device_handle); |
|||
Result Restore(u64 device_handle); |
|||
Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); |
|||
Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const; |
|||
Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const; |
|||
Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const; |
|||
u32 GetApplicationAreaSize() const; |
|||
Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); |
|||
Result Format(u64 device_handle); |
|||
Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const; |
|||
Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const; |
|||
Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info); |
|||
Result DeleteRegisterInfo(u64 device_handle); |
|||
Result DeleteApplicationArea(u64 device_handle); |
|||
Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const; |
|||
Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const; |
|||
Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data); |
|||
Result FlushDebug(u64 device_handle); |
|||
Result BreakTag(u64 device_handle, NFP::BreakType break_type); |
|||
Result ReadBackupData(u64 device_handle, std::span<u8> data) const; |
|||
Result WriteBackupData(u64 device_handle, std::span<const u8> data); |
|||
Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data); |
|||
|
|||
private: |
|||
Result IsNfcEnabled() const; |
|||
Result IsNfcParameterSet() const; |
|||
Result IsNfcInitialized() const; |
|||
|
|||
Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device, |
|||
bool check_state) const; |
|||
|
|||
Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const; |
|||
Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const; |
|||
Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const; |
|||
|
|||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); |
|||
const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; |
|||
|
|||
bool is_initialized = false; |
|||
mutable std::mutex mutex; |
|||
std::array<std::shared_ptr<NfcDevice>, 10> devices{}; |
|||
|
|||
Core::System& system; |
|||
KernelHelpers::ServiceContext service_context; |
|||
Kernel::KEvent* availability_change_event; |
|||
}; |
|||
|
|||
} // namespace Service::NFC |
|||
@ -0,0 +1,17 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "core/hle/result.h" |
|||
|
|||
namespace Service::NFC::Mifare { |
|||
|
|||
constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64); |
|||
constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65); |
|||
constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73); |
|||
constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80); |
|||
constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97); |
|||
constexpr Result ResultReadError(ErrorModule::NFCMifare, 288); |
|||
|
|||
} // namespace Service::NFC::Mifare |
|||
@ -0,0 +1,63 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-3.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
|
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Service::NFC { |
|||
|
|||
enum class MifareCmd : u8 { |
|||
AuthA = 0x60, |
|||
AuthB = 0x61, |
|||
Read = 0x30, |
|||
Write = 0xA0, |
|||
Transfer = 0xB0, |
|||
Decrement = 0xC0, |
|||
Increment = 0xC1, |
|||
Store = 0xC2 |
|||
}; |
|||
|
|||
using DataBlock = std::array<u8, 0x10>; |
|||
using KeyData = std::array<u8, 0x6>; |
|||
|
|||
struct SectorKey { |
|||
MifareCmd command; |
|||
u8 unknown; // Usually 1 |
|||
INSERT_PADDING_BYTES(0x6); |
|||
KeyData sector_key; |
|||
INSERT_PADDING_BYTES(0x2); |
|||
}; |
|||
static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); |
|||
|
|||
// This is nn::nfc::MifareReadBlockParameter |
|||
struct MifareReadBlockParameter { |
|||
u8 sector_number; |
|||
INSERT_PADDING_BYTES(0x7); |
|||
SectorKey sector_key; |
|||
}; |
|||
static_assert(sizeof(MifareReadBlockParameter) == 0x18, |
|||
"MifareReadBlockParameter is an invalid size"); |
|||
|
|||
// This is nn::nfc::MifareReadBlockData |
|||
struct MifareReadBlockData { |
|||
DataBlock data; |
|||
u8 sector_number; |
|||
INSERT_PADDING_BYTES(0x7); |
|||
}; |
|||
static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); |
|||
|
|||
// This is nn::nfc::MifareWriteBlockParameter |
|||
struct MifareWriteBlockParameter { |
|||
DataBlock data; |
|||
u8 sector_number; |
|||
INSERT_PADDING_BYTES(0x7); |
|||
SectorKey sector_key; |
|||
}; |
|||
static_assert(sizeof(MifareWriteBlockParameter) == 0x28, |
|||
"MifareWriteBlockParameter is an invalid size"); |
|||
|
|||
} // namespace Service::NFC |
|||
@ -1,400 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/logging/log.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hid/hid_types.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/nfc/mifare_user.h"
|
|||
#include "core/hle/service/nfc/nfc_device.h"
|
|||
#include "core/hle/service/nfc/nfc_result.h"
|
|||
|
|||
namespace Service::NFC { |
|||
|
|||
MFIUser::MFIUser(Core::System& system_) |
|||
: ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} { |
|||
static const FunctionInfo functions[] = { |
|||
{0, &MFIUser::Initialize, "Initialize"}, |
|||
{1, &MFIUser::Finalize, "Finalize"}, |
|||
{2, &MFIUser::ListDevices, "ListDevices"}, |
|||
{3, &MFIUser::StartDetection, "StartDetection"}, |
|||
{4, &MFIUser::StopDetection, "StopDetection"}, |
|||
{5, &MFIUser::Read, "Read"}, |
|||
{6, &MFIUser::Write, "Write"}, |
|||
{7, &MFIUser::GetTagInfo, "GetTagInfo"}, |
|||
{8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, |
|||
{9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, |
|||
{10, &MFIUser::GetState, "GetState"}, |
|||
{11, &MFIUser::GetDeviceState, "GetDeviceState"}, |
|||
{12, &MFIUser::GetNpadId, "GetNpadId"}, |
|||
{13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, |
|||
}; |
|||
RegisterHandlers(functions); |
|||
|
|||
availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent"); |
|||
|
|||
for (u32 device_index = 0; device_index < 10; device_index++) { |
|||
devices[device_index] = |
|||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, |
|||
service_context, availability_change_event); |
|||
} |
|||
} |
|||
|
|||
MFIUser ::~MFIUser() { |
|||
availability_change_event->Close(); |
|||
} |
|||
|
|||
void MFIUser::Initialize(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
state = State::Initialized; |
|||
|
|||
for (auto& device : devices) { |
|||
device->Initialize(); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void MFIUser::Finalize(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
state = State::NonInitialized; |
|||
|
|||
for (auto& device : devices) { |
|||
device->Finalize(); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void MFIUser::ListDevices(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_NFC, "called"); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
if (!ctx.CanWriteBuffer()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareInvalidArgument); |
|||
return; |
|||
} |
|||
|
|||
if (ctx.GetWriteBufferSize() == 0) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareInvalidArgument); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u64> nfp_devices; |
|||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); |
|||
|
|||
for (const auto& device : devices) { |
|||
if (nfp_devices.size() >= max_allowed_devices) { |
|||
continue; |
|||
} |
|||
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { |
|||
nfp_devices.push_back(device->GetHandle()); |
|||
} |
|||
} |
|||
|
|||
if (nfp_devices.empty()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
ctx.WriteBuffer(nfp_devices); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<s32>(nfp_devices.size())); |
|||
} |
|||
|
|||
void MFIUser::StartDetection(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
const auto result = device.value()->StartDetection(NFP::TagProtocol::All); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void MFIUser::StopDetection(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
const auto result = device.value()->StopDetection(); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void MFIUser::Read(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
const auto buffer{ctx.ReadBuffer()}; |
|||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()}; |
|||
std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands); |
|||
|
|||
memcpy(read_commands.data(), buffer.data(), |
|||
number_of_commands * sizeof(NFP::MifareReadBlockParameter)); |
|||
|
|||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", |
|||
device_handle, number_of_commands); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
Result result = ResultSuccess; |
|||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); |
|||
for (std::size_t i = 0; i < number_of_commands; i++) { |
|||
result = device.value()->MifareRead(read_commands[i], out_data[i]); |
|||
if (result.IsError()) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
ctx.WriteBuffer(out_data); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void MFIUser::Write(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
const auto buffer{ctx.ReadBuffer()}; |
|||
const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()}; |
|||
std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands); |
|||
|
|||
memcpy(write_commands.data(), buffer.data(), |
|||
number_of_commands * sizeof(NFP::MifareWriteBlockParameter)); |
|||
|
|||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", |
|||
device_handle, number_of_commands); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
Result result = ResultSuccess; |
|||
std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); |
|||
for (std::size_t i = 0; i < number_of_commands; i++) { |
|||
result = device.value()->MifareWrite(write_commands[i]); |
|||
if (result.IsError()) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (result.IsSuccess()) { |
|||
result = device.value()->Flush(); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void MFIUser::GetTagInfo(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
NFP::TagInfo tag_info{}; |
|||
const auto result = device.value()->GetTagInfo(tag_info, true); |
|||
ctx.WriteBuffer(tag_info); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void MFIUser::GetActivateEventHandle(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(device.value()->GetActivateEvent()); |
|||
} |
|||
|
|||
void MFIUser::GetDeactivateEventHandle(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(device.value()->GetDeactivateEvent()); |
|||
} |
|||
|
|||
void MFIUser::GetState(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_NFC, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(state); |
|||
} |
|||
|
|||
void MFIUser::GetDeviceState(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(device.value()->GetCurrentState()); |
|||
} |
|||
|
|||
void MFIUser::GetNpadId(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareDeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(device.value()->GetNpadId()); |
|||
} |
|||
|
|||
void MFIUser::GetAvailabilityChangeEventHandle(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(MifareNfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(availability_change_event->GetReadableEvent()); |
|||
} |
|||
|
|||
std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) { |
|||
for (auto& device : devices) { |
|||
if (device->GetHandle() == handle) { |
|||
return device; |
|||
} |
|||
} |
|||
return std::nullopt; |
|||
} |
|||
|
|||
} // namespace Service::NFC
|
|||
@ -1,52 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <array> |
|||
#include <memory> |
|||
#include <optional> |
|||
|
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Service::NFC { |
|||
class NfcDevice; |
|||
|
|||
class MFIUser final : public ServiceFramework<MFIUser> { |
|||
public: |
|||
explicit MFIUser(Core::System& system_); |
|||
~MFIUser(); |
|||
|
|||
private: |
|||
enum class State : u32 { |
|||
NonInitialized, |
|||
Initialized, |
|||
}; |
|||
|
|||
void Initialize(HLERequestContext& ctx); |
|||
void Finalize(HLERequestContext& ctx); |
|||
void ListDevices(HLERequestContext& ctx); |
|||
void StartDetection(HLERequestContext& ctx); |
|||
void StopDetection(HLERequestContext& ctx); |
|||
void Read(HLERequestContext& ctx); |
|||
void Write(HLERequestContext& ctx); |
|||
void GetTagInfo(HLERequestContext& ctx); |
|||
void GetActivateEventHandle(HLERequestContext& ctx); |
|||
void GetDeactivateEventHandle(HLERequestContext& ctx); |
|||
void GetState(HLERequestContext& ctx); |
|||
void GetDeviceState(HLERequestContext& ctx); |
|||
void GetNpadId(HLERequestContext& ctx); |
|||
void GetAvailabilityChangeEventHandle(HLERequestContext& ctx); |
|||
|
|||
std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); |
|||
|
|||
KernelHelpers::ServiceContext service_context; |
|||
|
|||
std::array<std::shared_ptr<NfcDevice>, 10> devices{}; |
|||
|
|||
State state{State::NonInitialized}; |
|||
Kernel::KEvent* availability_change_event; |
|||
}; |
|||
|
|||
} // namespace Service::NFC |
|||
@ -1,288 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/input.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hid/emulated_controller.h"
|
|||
#include "core/hid/hid_core.h"
|
|||
#include "core/hid/hid_types.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/nfc/nfc_device.h"
|
|||
#include "core/hle/service/nfc/nfc_result.h"
|
|||
#include "core/hle/service/nfc/nfc_user.h"
|
|||
|
|||
namespace Service::NFC { |
|||
NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, |
|||
KernelHelpers::ServiceContext& service_context_, |
|||
Kernel::KEvent* availability_change_event_) |
|||
: npad_id{npad_id_}, system{system_}, service_context{service_context_}, |
|||
availability_change_event{availability_change_event_} { |
|||
activate_event = service_context.CreateEvent("IUser:NFCActivateEvent"); |
|||
deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent"); |
|||
npad_device = system.HIDCore().GetEmulatedController(npad_id); |
|||
|
|||
Core::HID::ControllerUpdateCallback engine_callback{ |
|||
.on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); }, |
|||
.is_npad_service = false, |
|||
}; |
|||
is_controller_set = true; |
|||
callback_key = npad_device->SetCallback(engine_callback); |
|||
} |
|||
|
|||
NfcDevice::~NfcDevice() { |
|||
activate_event->Close(); |
|||
deactivate_event->Close(); |
|||
if (!is_controller_set) { |
|||
return; |
|||
} |
|||
npad_device->DeleteCallback(callback_key); |
|||
is_controller_set = false; |
|||
}; |
|||
|
|||
void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { |
|||
if (!is_initalized) { |
|||
return; |
|||
} |
|||
|
|||
if (type == Core::HID::ControllerTriggerType::Connected) { |
|||
Initialize(); |
|||
availability_change_event->Signal(); |
|||
return; |
|||
} |
|||
|
|||
if (type == Core::HID::ControllerTriggerType::Disconnected) { |
|||
device_state = NFP::DeviceState::Unavailable; |
|||
availability_change_event->Signal(); |
|||
return; |
|||
} |
|||
|
|||
if (type != Core::HID::ControllerTriggerType::Nfc) { |
|||
return; |
|||
} |
|||
|
|||
if (!npad_device->IsConnected()) { |
|||
return; |
|||
} |
|||
|
|||
const auto nfc_status = npad_device->GetNfc(); |
|||
switch (nfc_status.state) { |
|||
case Common::Input::NfcState::NewAmiibo: |
|||
LoadNfcTag(nfc_status.data); |
|||
break; |
|||
case Common::Input::NfcState::AmiiboRemoved: |
|||
if (device_state != NFP::DeviceState::SearchingForTag) { |
|||
CloseNfcTag(); |
|||
} |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
bool NfcDevice::LoadNfcTag(std::span<const u8> data) { |
|||
if (device_state != NFP::DeviceState::SearchingForTag) { |
|||
LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); |
|||
return false; |
|||
} |
|||
|
|||
if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { |
|||
LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); |
|||
return false; |
|||
} |
|||
|
|||
tag_data.resize(data.size()); |
|||
memcpy(tag_data.data(), data.data(), data.size()); |
|||
memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); |
|||
|
|||
device_state = NFP::DeviceState::TagFound; |
|||
deactivate_event->GetReadableEvent().Clear(); |
|||
activate_event->Signal(); |
|||
return true; |
|||
} |
|||
|
|||
void NfcDevice::CloseNfcTag() { |
|||
LOG_INFO(Service_NFC, "Remove nfc tag"); |
|||
|
|||
device_state = NFP::DeviceState::TagRemoved; |
|||
encrypted_tag_data = {}; |
|||
activate_event->GetReadableEvent().Clear(); |
|||
deactivate_event->Signal(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const { |
|||
return activate_event->GetReadableEvent(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const { |
|||
return deactivate_event->GetReadableEvent(); |
|||
} |
|||
|
|||
void NfcDevice::Initialize() { |
|||
device_state = |
|||
npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable; |
|||
encrypted_tag_data = {}; |
|||
is_initalized = true; |
|||
} |
|||
|
|||
void NfcDevice::Finalize() { |
|||
if (device_state == NFP::DeviceState::SearchingForTag || |
|||
device_state == NFP::DeviceState::TagRemoved) { |
|||
StopDetection(); |
|||
} |
|||
device_state = NFP::DeviceState::Unavailable; |
|||
is_initalized = false; |
|||
} |
|||
|
|||
Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { |
|||
if (device_state != NFP::DeviceState::Initialized && |
|||
device_state != NFP::DeviceState::TagRemoved) { |
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
if (npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, |
|||
Common::Input::PollingMode::NFC) != |
|||
Common::Input::DriverResult::Success) { |
|||
LOG_ERROR(Service_NFC, "Nfc not supported"); |
|||
return NfcDisabled; |
|||
} |
|||
|
|||
device_state = NFP::DeviceState::SearchingForTag; |
|||
allowed_protocols = allowed_protocol; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result NfcDevice::StopDetection() { |
|||
npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex, |
|||
Common::Input::PollingMode::Active); |
|||
|
|||
if (device_state == NFP::DeviceState::Initialized) { |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
if (device_state == NFP::DeviceState::TagFound || |
|||
device_state == NFP::DeviceState::TagMounted) { |
|||
CloseNfcTag(); |
|||
return ResultSuccess; |
|||
} |
|||
if (device_state == NFP::DeviceState::SearchingForTag || |
|||
device_state == NFP::DeviceState::TagRemoved) { |
|||
device_state = NFP::DeviceState::Initialized; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
Result NfcDevice::Flush() { |
|||
if (device_state != NFP::DeviceState::TagFound && |
|||
device_state != NFP::DeviceState::TagMounted) { |
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
if (device_state == NFP::DeviceState::TagRemoved) { |
|||
return TagRemoved; |
|||
} |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
if (!npad_device->WriteNfc(tag_data)) { |
|||
LOG_ERROR(Service_NFP, "Error writing to file"); |
|||
return MifareReadError; |
|||
} |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const { |
|||
if (device_state != NFP::DeviceState::TagFound && |
|||
device_state != NFP::DeviceState::TagMounted) { |
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
if (device_state == NFP::DeviceState::TagRemoved) { |
|||
return TagRemoved; |
|||
} |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
if (is_mifare) { |
|||
tag_info = { |
|||
.uuid = encrypted_tag_data.uuid.uid, |
|||
.uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), |
|||
.protocol = NFP::TagProtocol::TypeA, |
|||
.tag_type = NFP::TagType::Type4, |
|||
}; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
// Protocol and tag type may change here
|
|||
tag_info = { |
|||
.uuid = encrypted_tag_data.uuid.uid, |
|||
.uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), |
|||
.protocol = NFP::TagProtocol::TypeA, |
|||
.tag_type = NFP::TagType::Type2, |
|||
}; |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter, |
|||
NFP::MifareReadBlockData& read_block_data) { |
|||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); |
|||
read_block_data.sector_number = parameter.sector_number; |
|||
|
|||
if (device_state != NFP::DeviceState::TagFound && |
|||
device_state != NFP::DeviceState::TagMounted) { |
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
if (device_state == NFP::DeviceState::TagRemoved) { |
|||
return TagRemoved; |
|||
} |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { |
|||
return MifareReadError; |
|||
} |
|||
|
|||
// TODO: Use parameter.sector_key to read encrypted data
|
|||
memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock)); |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) { |
|||
const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); |
|||
|
|||
if (device_state != NFP::DeviceState::TagFound && |
|||
device_state != NFP::DeviceState::TagMounted) { |
|||
LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
|||
if (device_state == NFP::DeviceState::TagRemoved) { |
|||
return TagRemoved; |
|||
} |
|||
return WrongDeviceState; |
|||
} |
|||
|
|||
if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { |
|||
return MifareReadError; |
|||
} |
|||
|
|||
// TODO: Use parameter.sector_key to encrypt the data
|
|||
memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock)); |
|||
|
|||
return ResultSuccess; |
|||
} |
|||
|
|||
u64 NfcDevice::GetHandle() const { |
|||
// Generate a handle based of the npad id
|
|||
return static_cast<u64>(npad_id); |
|||
} |
|||
|
|||
NFP::DeviceState NfcDevice::GetCurrentState() const { |
|||
return device_state; |
|||
} |
|||
|
|||
Core::HID::NpadIdType NfcDevice::GetNpadId() const { |
|||
return npad_id; |
|||
} |
|||
|
|||
} // namespace Service::NFC
|
|||
@ -1,78 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/nfp/nfp_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KEvent; |
|||
class KReadableEvent; |
|||
} // namespace Kernel |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} // namespace Core |
|||
|
|||
namespace Core::HID { |
|||
class EmulatedController; |
|||
enum class ControllerTriggerType; |
|||
enum class NpadIdType : u32; |
|||
} // namespace Core::HID |
|||
|
|||
namespace Service::NFC { |
|||
class NfcDevice { |
|||
public: |
|||
NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, |
|||
KernelHelpers::ServiceContext& service_context_, |
|||
Kernel::KEvent* availability_change_event_); |
|||
~NfcDevice(); |
|||
|
|||
void Initialize(); |
|||
void Finalize(); |
|||
|
|||
Result StartDetection(NFP::TagProtocol allowed_protocol); |
|||
Result StopDetection(); |
|||
Result Flush(); |
|||
|
|||
Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const; |
|||
|
|||
Result MifareRead(const NFP::MifareReadBlockParameter& parameter, |
|||
NFP::MifareReadBlockData& read_block_data); |
|||
|
|||
Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter); |
|||
|
|||
u64 GetHandle() const; |
|||
NFP::DeviceState GetCurrentState() const; |
|||
Core::HID::NpadIdType GetNpadId() const; |
|||
|
|||
Kernel::KReadableEvent& GetActivateEvent() const; |
|||
Kernel::KReadableEvent& GetDeactivateEvent() const; |
|||
|
|||
private: |
|||
void NpadUpdate(Core::HID::ControllerTriggerType type); |
|||
bool LoadNfcTag(std::span<const u8> data); |
|||
void CloseNfcTag(); |
|||
|
|||
bool is_controller_set{}; |
|||
int callback_key; |
|||
const Core::HID::NpadIdType npad_id; |
|||
Core::System& system; |
|||
Core::HID::EmulatedController* npad_device = nullptr; |
|||
KernelHelpers::ServiceContext& service_context; |
|||
Kernel::KEvent* activate_event = nullptr; |
|||
Kernel::KEvent* deactivate_event = nullptr; |
|||
Kernel::KEvent* availability_change_event = nullptr; |
|||
|
|||
bool is_initalized{}; |
|||
NFP::TagProtocol allowed_protocols{}; |
|||
NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; |
|||
|
|||
NFP::EncryptedNTAG215File encrypted_tag_data{}; |
|||
std::vector<u8> tag_data{}; |
|||
}; |
|||
|
|||
} // namespace Service::NFC |
|||
@ -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
|
|||
@ -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 |
|||
@ -1,365 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/logging/log.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hid/hid_types.h"
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/ipc_helpers.h"
|
|||
#include "core/hle/service/nfc/nfc_device.h"
|
|||
#include "core/hle/service/nfc/nfc_result.h"
|
|||
#include "core/hle/service/nfc/nfc_user.h"
|
|||
#include "core/hle/service/time/clock_types.h"
|
|||
|
|||
namespace Service::NFC { |
|||
|
|||
IUser::IUser(Core::System& system_) |
|||
: ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} { |
|||
static const FunctionInfo functions[] = { |
|||
{0, &IUser::Initialize, "InitializeOld"}, |
|||
{1, &IUser::Finalize, "FinalizeOld"}, |
|||
{2, &IUser::GetState, "GetStateOld"}, |
|||
{3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"}, |
|||
{400, &IUser::Initialize, "Initialize"}, |
|||
{401, &IUser::Finalize, "Finalize"}, |
|||
{402, &IUser::GetState, "GetState"}, |
|||
{403, &IUser::IsNfcEnabled, "IsNfcEnabled"}, |
|||
{404, &IUser::ListDevices, "ListDevices"}, |
|||
{405, &IUser::GetDeviceState, "GetDeviceState"}, |
|||
{406, &IUser::GetNpadId, "GetNpadId"}, |
|||
{407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, |
|||
{408, &IUser::StartDetection, "StartDetection"}, |
|||
{409, &IUser::StopDetection, "StopDetection"}, |
|||
{410, &IUser::GetTagInfo, "GetTagInfo"}, |
|||
{411, &IUser::AttachActivateEvent, "AttachActivateEvent"}, |
|||
{412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, |
|||
{1000, nullptr, "ReadMifare"}, |
|||
{1001, nullptr, "WriteMifare"}, |
|||
{1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"}, |
|||
{1301, nullptr, "KeepPassThroughSession"}, |
|||
{1302, nullptr, "ReleasePassThroughSession"}, |
|||
}; |
|||
RegisterHandlers(functions); |
|||
|
|||
availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); |
|||
|
|||
for (u32 device_index = 0; device_index < 10; device_index++) { |
|||
devices[device_index] = |
|||
std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, |
|||
service_context, availability_change_event); |
|||
} |
|||
} |
|||
|
|||
IUser ::~IUser() { |
|||
availability_change_event->Close(); |
|||
} |
|||
|
|||
void IUser::Initialize(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
state = State::Initialized; |
|||
|
|||
for (auto& device : devices) { |
|||
device->Initialize(); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 0}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IUser::Finalize(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
state = State::NonInitialized; |
|||
|
|||
for (auto& device : devices) { |
|||
device->Finalize(); |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(ResultSuccess); |
|||
} |
|||
|
|||
void IUser::GetState(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_NFC, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(state); |
|||
} |
|||
|
|||
void IUser::IsNfcEnabled(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_NFC, "called"); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(state != State::NonInitialized); |
|||
} |
|||
|
|||
void IUser::ListDevices(HLERequestContext& ctx) { |
|||
LOG_DEBUG(Service_NFC, "called"); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
if (!ctx.CanWriteBuffer()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(InvalidArgument); |
|||
return; |
|||
} |
|||
|
|||
if (ctx.GetWriteBufferSize() == 0) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(InvalidArgument); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u64> nfp_devices; |
|||
const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); |
|||
|
|||
for (auto& device : devices) { |
|||
if (nfp_devices.size() >= max_allowed_devices) { |
|||
continue; |
|||
} |
|||
if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { |
|||
nfp_devices.push_back(device->GetHandle()); |
|||
} |
|||
} |
|||
|
|||
if (nfp_devices.empty()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
ctx.WriteBuffer(nfp_devices); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<s32>(nfp_devices.size())); |
|||
} |
|||
|
|||
void IUser::GetDeviceState(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(device.value()->GetCurrentState()); |
|||
} |
|||
|
|||
void IUser::GetNpadId(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushEnum(device.value()->GetNpadId()); |
|||
} |
|||
|
|||
void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { |
|||
LOG_INFO(Service_NFC, "called"); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(availability_change_event->GetReadableEvent()); |
|||
} |
|||
|
|||
void IUser::StartDetection(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
const auto result = device.value()->StartDetection(nfp_protocol); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void IUser::StopDetection(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
const auto result = device.value()->StopDetection(); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void IUser::GetTagInfo(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
NFP::TagInfo tag_info{}; |
|||
const auto result = device.value()->GetTagInfo(tag_info, false); |
|||
ctx.WriteBuffer(tag_info); |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(result); |
|||
} |
|||
|
|||
void IUser::AttachActivateEvent(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(device.value()->GetActivateEvent()); |
|||
} |
|||
|
|||
void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 2, 1}; |
|||
rb.Push(ResultSuccess); |
|||
rb.PushCopyObjects(device.value()->GetDeactivateEvent()); |
|||
} |
|||
|
|||
void IUser::SendCommandByPassThrough(HLERequestContext& ctx) { |
|||
IPC::RequestParser rp{ctx}; |
|||
const auto device_handle{rp.Pop<u64>()}; |
|||
const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; |
|||
const auto command_data{ctx.ReadBuffer()}; |
|||
|
|||
LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", |
|||
device_handle, timeout.ToSeconds(), command_data.size()); |
|||
|
|||
if (state == State::NonInitialized) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(NfcDisabled); |
|||
return; |
|||
} |
|||
|
|||
auto device = GetNfcDevice(device_handle); |
|||
|
|||
if (!device.has_value()) { |
|||
IPC::ResponseBuilder rb{ctx, 2}; |
|||
rb.Push(DeviceNotFound); |
|||
return; |
|||
} |
|||
|
|||
std::vector<u8> out_data(1); |
|||
// TODO: Request data from nfc device
|
|||
ctx.WriteBuffer(out_data); |
|||
|
|||
IPC::ResponseBuilder rb{ctx, 3}; |
|||
rb.Push(ResultSuccess); |
|||
rb.Push(static_cast<u32>(out_data.size())); |
|||
} |
|||
|
|||
std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) { |
|||
for (auto& device : devices) { |
|||
if (device->GetHandle() == handle) { |
|||
return device; |
|||
} |
|||
} |
|||
return std::nullopt; |
|||
} |
|||
|
|||
} // namespace Service::NFC
|
|||
@ -1,120 +0,0 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <span> |
|||
#include <vector> |
|||
|
|||
#include "common/common_types.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/nfp/nfp_types.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
namespace Kernel { |
|||
class KEvent; |
|||
class KReadableEvent; |
|||
} // namespace Kernel |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} // namespace Core |
|||
|
|||
namespace Core::HID { |
|||
class EmulatedController; |
|||
enum class ControllerTriggerType; |
|||
enum class NpadIdType : u32; |
|||
} // namespace Core::HID |
|||
|
|||
namespace Service::NFP { |
|||
class NfpDevice { |
|||
public: |
|||
NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, |
|||
KernelHelpers::ServiceContext& service_context_, |
|||
Kernel::KEvent* availability_change_event_); |
|||
~NfpDevice(); |
|||
|
|||
void Initialize(); |
|||
void Finalize(); |
|||
|
|||
Result StartDetection(TagProtocol allowed_protocol); |
|||
Result StopDetection(); |
|||
Result Mount(MountTarget mount_target); |
|||
Result Unmount(); |
|||
|
|||
Result Flush(); |
|||
Result FlushDebug(); |
|||
Result FlushWithBreak(BreakType break_type); |
|||
|
|||
Result GetTagInfo(TagInfo& tag_info) const; |
|||
Result GetCommonInfo(CommonInfo& common_info) const; |
|||
Result GetModelInfo(ModelInfo& model_info) const; |
|||
Result GetRegisterInfo(RegisterInfo& register_info) const; |
|||
Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const; |
|||
Result GetAdminInfo(AdminInfo& admin_info) const; |
|||
|
|||
Result DeleteRegisterInfo(); |
|||
Result SetRegisterInfoPrivate(const AmiiboName& amiibo_name); |
|||
Result RestoreAmiibo(); |
|||
Result Format(); |
|||
|
|||
Result OpenApplicationArea(u32 access_id); |
|||
Result GetApplicationAreaId(u32& application_area_id) const; |
|||
Result GetApplicationArea(std::vector<u8>& data) const; |
|||
Result SetApplicationArea(std::span<const u8> data); |
|||
Result CreateApplicationArea(u32 access_id, std::span<const u8> data); |
|||
Result RecreateApplicationArea(u32 access_id, std::span<const u8> data); |
|||
Result DeleteApplicationArea(); |
|||
Result ExistApplicationArea(bool& has_application_area); |
|||
|
|||
Result GetAll(NfpData& data) const; |
|||
Result SetAll(const NfpData& data); |
|||
Result BreakTag(BreakType break_type); |
|||
Result ReadBackupData(); |
|||
Result WriteBackupData(); |
|||
Result WriteNtf(); |
|||
|
|||
u64 GetHandle() const; |
|||
u32 GetApplicationAreaSize() const; |
|||
DeviceState GetCurrentState() const; |
|||
Core::HID::NpadIdType GetNpadId() const; |
|||
|
|||
Kernel::KReadableEvent& GetActivateEvent() const; |
|||
Kernel::KReadableEvent& GetDeactivateEvent() const; |
|||
|
|||
private: |
|||
void NpadUpdate(Core::HID::ControllerTriggerType type); |
|||
bool LoadAmiibo(std::span<const u8> data); |
|||
void CloseAmiibo(); |
|||
|
|||
AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; |
|||
void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name); |
|||
AmiiboDate GetAmiiboDate(s64 posix_time) const; |
|||
u64 RemoveVersionByte(u64 application_id) const; |
|||
void UpdateSettingsCrc(); |
|||
void UpdateRegisterInfoCrc(); |
|||
|
|||
bool is_controller_set{}; |
|||
int callback_key; |
|||
const Core::HID::NpadIdType npad_id; |
|||
Core::System& system; |
|||
Core::HID::EmulatedController* npad_device = nullptr; |
|||
KernelHelpers::ServiceContext& service_context; |
|||
Kernel::KEvent* activate_event = nullptr; |
|||
Kernel::KEvent* deactivate_event = nullptr; |
|||
Kernel::KEvent* availability_change_event = nullptr; |
|||
|
|||
bool is_initalized{}; |
|||
bool is_data_moddified{}; |
|||
bool is_app_area_open{}; |
|||
bool is_plain_amiibo{}; |
|||
TagProtocol allowed_protocols{}; |
|||
s64 current_posix_time{}; |
|||
MountTarget mount_target{MountTarget::None}; |
|||
DeviceState device_state{DeviceState::Unavailable}; |
|||
|
|||
NTAG215File tag_data{}; |
|||
EncryptedNTAG215File encrypted_tag_data{}; |
|||
}; |
|||
|
|||
} // namespace Service::NFP |
|||
839
src/core/hle/service/nfp/nfp_interface.cpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue