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