summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/nfp/nfp.cpp115
-rw-r--r--src/core/hle/service/nfp/nfp.h71
2 files changed, 145 insertions, 41 deletions
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 7f1fb3a71..1e91aa340 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -108,7 +108,7 @@ void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
108 108
109 // TODO(german77): Loop through all interfaces 109 // TODO(german77): Loop through all interfaces
110 if (device_handle == nfp_interface.GetHandle()) { 110 if (device_handle == nfp_interface.GetHandle()) {
111 const auto result = nfp_interface.StartDetection(); 111 const auto result = nfp_interface.StartDetection(nfp_protocol);
112 IPC::ResponseBuilder rb{ctx, 2}; 112 IPC::ResponseBuilder rb{ctx, 2};
113 rb.Push(result); 113 rb.Push(result);
114 return; 114 return;
@@ -209,7 +209,6 @@ void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {
209 if (device_handle == nfp_interface.GetHandle()) { 209 if (device_handle == nfp_interface.GetHandle()) {
210 std::vector<u8> data{}; 210 std::vector<u8> data{};
211 const auto result = nfp_interface.GetApplicationArea(data); 211 const auto result = nfp_interface.GetApplicationArea(data);
212
213 ctx.WriteBuffer(data); 212 ctx.WriteBuffer(data);
214 IPC::ResponseBuilder rb{ctx, 3}; 213 IPC::ResponseBuilder rb{ctx, 3};
215 rb.Push(result); 214 rb.Push(result);
@@ -232,7 +231,6 @@ void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {
232 // TODO(german77): Loop through all interfaces 231 // TODO(german77): Loop through all interfaces
233 if (device_handle == nfp_interface.GetHandle()) { 232 if (device_handle == nfp_interface.GetHandle()) {
234 const auto result = nfp_interface.SetApplicationArea(data); 233 const auto result = nfp_interface.SetApplicationArea(data);
235
236 IPC::ResponseBuilder rb{ctx, 2}; 234 IPC::ResponseBuilder rb{ctx, 2};
237 rb.Push(result); 235 rb.Push(result);
238 return; 236 return;
@@ -255,7 +253,6 @@ void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
255 // TODO(german77): Loop through all interfaces 253 // TODO(german77): Loop through all interfaces
256 if (device_handle == nfp_interface.GetHandle()) { 254 if (device_handle == nfp_interface.GetHandle()) {
257 const auto result = nfp_interface.CreateApplicationArea(access_id, data); 255 const auto result = nfp_interface.CreateApplicationArea(access_id, data);
258
259 IPC::ResponseBuilder rb{ctx, 2}; 256 IPC::ResponseBuilder rb{ctx, 2};
260 rb.Push(result); 257 rb.Push(result);
261 return; 258 return;
@@ -390,7 +387,7 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
390} 387}
391 388
392void IUser::GetState(Kernel::HLERequestContext& ctx) { 389void IUser::GetState(Kernel::HLERequestContext& ctx) {
393 LOG_INFO(Service_NFC, "called"); 390 LOG_DEBUG(Service_NFC, "called");
394 391
395 IPC::ResponseBuilder rb{ctx, 3, 0}; 392 IPC::ResponseBuilder rb{ctx, 3, 0};
396 rb.Push(ResultSuccess); 393 rb.Push(ResultSuccess);
@@ -400,7 +397,7 @@ void IUser::GetState(Kernel::HLERequestContext& ctx) {
400void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { 397void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
401 IPC::RequestParser rp{ctx}; 398 IPC::RequestParser rp{ctx};
402 const auto device_handle{rp.Pop<u64>()}; 399 const auto device_handle{rp.Pop<u64>()};
403 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 400 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
404 401
405 // TODO(german77): Loop through all interfaces 402 // TODO(german77): Loop through all interfaces
406 if (device_handle == nfp_interface.GetHandle()) { 403 if (device_handle == nfp_interface.GetHandle()) {
@@ -419,7 +416,7 @@ void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
419void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { 416void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
420 IPC::RequestParser rp{ctx}; 417 IPC::RequestParser rp{ctx};
421 const auto device_handle{rp.Pop<u64>()}; 418 const auto device_handle{rp.Pop<u64>()};
422 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 419 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
423 420
424 // TODO(german77): Loop through all interfaces 421 // TODO(german77): Loop through all interfaces
425 if (device_handle == nfp_interface.GetHandle()) { 422 if (device_handle == nfp_interface.GetHandle()) {
@@ -438,7 +435,7 @@ void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
438void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { 435void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
439 IPC::RequestParser rp{ctx}; 436 IPC::RequestParser rp{ctx};
440 const auto device_handle{rp.Pop<u64>()}; 437 const auto device_handle{rp.Pop<u64>()};
441 LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); 438 LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
442 439
443 // TODO(german77): Loop through all interfaces 440 // TODO(german77): Loop through all interfaces
444 if (device_handle == nfp_interface.GetHandle()) { 441 if (device_handle == nfp_interface.GetHandle()) {
@@ -493,6 +490,11 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
493 490
494 LOG_INFO(Service_NFP, "New Amiibo detected"); 491 LOG_INFO(Service_NFP, "New Amiibo detected");
495 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 492 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
493
494 if (!IsAmiiboValid()) {
495 return false;
496 }
497
496 device_state = DeviceState::TagFound; 498 device_state = DeviceState::TagFound;
497 activate_event->GetWritableEvent().Signal(); 499 activate_event->GetWritableEvent().Signal();
498 return true; 500 return true;
@@ -501,13 +503,54 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
501void Module::Interface::CloseAmiibo() { 503void Module::Interface::CloseAmiibo() {
502 LOG_INFO(Service_NFP, "Remove amiibo"); 504 LOG_INFO(Service_NFP, "Remove amiibo");
503 device_state = DeviceState::TagRemoved; 505 device_state = DeviceState::TagRemoved;
504 write_counter = 0;
505 is_application_area_initialized = false; 506 is_application_area_initialized = false;
506 application_area_id = 0; 507 application_area_id = 0;
507 application_area_data.clear(); 508 application_area_data.clear();
508 deactivate_event->GetWritableEvent().Signal(); 509 deactivate_event->GetWritableEvent().Signal();
509} 510}
510 511
512bool Module::Interface::IsAmiiboValid() const {
513 LOG_INFO(Service_NFP, "uuid_lock=0x{0:x}", amiibo.uuid_lock);
514 LOG_INFO(Service_NFP, "compability_container=0x{0:x}", amiibo.compability_container);
515 LOG_INFO(Service_NFP, "crypto_init=0x{0:x}", amiibo.crypto_init);
516 LOG_INFO(Service_NFP, "write_count={}", amiibo.write_count);
517
518 LOG_INFO(Service_NFP, "character_id=0x{0:x}", amiibo.model_info.character_id);
519 LOG_INFO(Service_NFP, "character_variant={}", amiibo.model_info.character_variant);
520 LOG_INFO(Service_NFP, "amiibo_type={}", amiibo.model_info.amiibo_type);
521 LOG_INFO(Service_NFP, "model_number=0x{0:x}", amiibo.model_info.model_number);
522 LOG_INFO(Service_NFP, "series={}", amiibo.model_info.series);
523 LOG_INFO(Service_NFP, "fixed_value=0x{0:x}", amiibo.model_info.fixed);
524
525 LOG_INFO(Service_NFP, "tag_dynamic_lock=0x{0:x}", amiibo.tag_dynamic_lock);
526 LOG_INFO(Service_NFP, "tag_CFG0=0x{0:x}", amiibo.tag_CFG0);
527 LOG_INFO(Service_NFP, "tag_CFG1=0x{0:x}", amiibo.tag_CFG1);
528
529 // Check against all know constants on an amiibo binary
530 if (amiibo.uuid_lock != 0xE00F) {
531 return false;
532 }
533 if (amiibo.compability_container != 0xEEFF10F1UL) {
534 return false;
535 }
536 if ((amiibo.crypto_init & 0xFF) != 0xA5) {
537 return false;
538 }
539 if (amiibo.model_info.fixed != 0x02) {
540 return false;
541 }
542 if ((amiibo.tag_dynamic_lock & 0xFFFFFF) != 0x0F0001) {
543 return false;
544 }
545 if (amiibo.tag_CFG0 != 0x04000000UL) {
546 return false;
547 }
548 if (amiibo.tag_CFG1 != 0x5F) {
549 return false;
550 }
551 return true;
552}
553
511Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { 554Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const {
512 return activate_event->GetReadableEvent(); 555 return activate_event->GetReadableEvent();
513} 556}
@@ -522,13 +565,12 @@ void Module::Interface::Initialize() {
522 565
523void Module::Interface::Finalize() { 566void Module::Interface::Finalize() {
524 device_state = DeviceState::Unaviable; 567 device_state = DeviceState::Unaviable;
525 write_counter = 0;
526 is_application_area_initialized = false; 568 is_application_area_initialized = false;
527 application_area_id = 0; 569 application_area_id = 0;
528 application_area_data.clear(); 570 application_area_data.clear();
529} 571}
530 572
531ResultCode Module::Interface::StartDetection() { 573ResultCode Module::Interface::StartDetection(s32 protocol_) {
532 auto npad_device = system.HIDCore().GetEmulatedController(npad_id); 574 auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
533 575
534 // TODO(german77): Add callback for when nfc data is available 576 // TODO(german77): Add callback for when nfc data is available
@@ -536,6 +578,7 @@ ResultCode Module::Interface::StartDetection() {
536 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { 578 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
537 npad_device->SetPollingMode(Common::Input::PollingMode::NFC); 579 npad_device->SetPollingMode(Common::Input::PollingMode::NFC);
538 device_state = DeviceState::SearchingForTag; 580 device_state = DeviceState::SearchingForTag;
581 protocol = protocol_;
539 return ResultSuccess; 582 return ResultSuccess;
540 } 583 }
541 584
@@ -589,8 +632,8 @@ ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const {
589 tag_info = { 632 tag_info = {
590 .uuid = amiibo.uuid, 633 .uuid = amiibo.uuid,
591 .uuid_length = static_cast<u8>(amiibo.uuid.size()), 634 .uuid_length = static_cast<u8>(amiibo.uuid.size()),
592 .protocol = 0xFFFFFFFF, // TODO(ogniK): Figure out actual values 635 .protocol = protocol,
593 .tag_type = 0xFFFFFFFF, 636 .tag_type = static_cast<u32>(amiibo.model_info.amiibo_type),
594 }; 637 };
595 return ResultSuccess; 638 return ResultSuccess;
596 } 639 }
@@ -610,7 +653,7 @@ ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const {
610 .last_write_year = 2022, 653 .last_write_year = 2022,
611 .last_write_month = 2, 654 .last_write_month = 2,
612 .last_write_day = 7, 655 .last_write_day = 7,
613 .write_counter = write_counter, 656 .write_counter = amiibo.write_count,
614 .version = 1, 657 .version = 1,
615 .application_area_size = ApplicationAreaSize, 658 .application_area_size = ApplicationAreaSize,
616 }; 659 };
@@ -652,11 +695,11 @@ ResultCode Module::Interface::OpenApplicationArea(u32 access_id) {
652 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 695 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
653 return ErrCodes::WrongDeviceState; 696 return ErrCodes::WrongDeviceState;
654 } 697 }
655 // if (AmiiboApplicationDataExist(access_id)) { 698 if (AmiiboApplicationDataExist(access_id)) {
656 // application_area_data = LoadAmiiboApplicationData(access_id); 699 application_area_data = LoadAmiiboApplicationData(access_id);
657 // application_area_id = access_id; 700 application_area_id = access_id;
658 // is_application_area_initialized = true; 701 is_application_area_initialized = true;
659 // } 702 }
660 if (!is_application_area_initialized) { 703 if (!is_application_area_initialized) {
661 LOG_ERROR(Service_NFP, "Application area is not initialized"); 704 LOG_ERROR(Service_NFP, "Application area is not initialized");
662 return ErrCodes::ApplicationAreaIsNotInitialized; 705 return ErrCodes::ApplicationAreaIsNotInitialized;
@@ -689,8 +732,7 @@ ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) {
689 return ErrCodes::ApplicationAreaIsNotInitialized; 732 return ErrCodes::ApplicationAreaIsNotInitialized;
690 } 733 }
691 application_area_data = data; 734 application_area_data = data;
692 write_counter++; 735 SaveAmiiboApplicationData(application_area_id, application_area_data);
693 // SaveAmiiboApplicationData(application_area_id,application_area_data);
694 return ResultSuccess; 736 return ResultSuccess;
695} 737}
696 738
@@ -699,21 +741,32 @@ ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::ve
699 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 741 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
700 return ErrCodes::WrongDeviceState; 742 return ErrCodes::WrongDeviceState;
701 } 743 }
702 // if (AmiiboApplicationDataExist(access_id)) { 744 if (AmiiboApplicationDataExist(access_id)) {
703 // LOG_ERROR(Service_NFP, "Application area already exist"); 745 LOG_ERROR(Service_NFP, "Application area already exist");
704 // return ErrCodes::ApplicationAreaExist; 746 return ErrCodes::ApplicationAreaExist;
705 // } 747 }
706 // if (LoadAmiiboApplicationData(access_id,data)) {
707 // is_application_area_initialized = true;
708 // application_area_id = access_id;
709 // }
710 application_area_data = data; 748 application_area_data = data;
711 application_area_id = access_id; 749 application_area_id = access_id;
712 write_counter = 0; 750 SaveAmiiboApplicationData(application_area_id, application_area_data);
713 // SaveAmiiboApplicationData(application_area_id,application_area_data);
714 return ResultSuccess; 751 return ResultSuccess;
715} 752}
716 753
754bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const {
755 // TODO(german77): Check if file exist
756 return false;
757}
758
759const std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const {
760 // TODO(german77): Read file
761 std::vector<u8> data(ApplicationAreaSize);
762 return data;
763}
764
765void Module::Interface::SaveAmiiboApplicationData(u32 access_id,
766 const std::vector<u8>& data) const {
767 // TODO(german77): Save file
768}
769
717u64 Module::Interface::GetHandle() const { 770u64 Module::Interface::GetHandle() const {
718 // Generate a handle based of the npad id 771 // Generate a handle based of the npad id
719 return static_cast<u64>(npad_id); 772 return static_cast<u64>(npad_id);
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 4642ed634..633539dcc 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -53,11 +53,43 @@ enum class MountTarget : u32 {
53 All, 53 All,
54}; 54};
55 55
56enum class AmiiboType : u8 {
57 Figure,
58 Card,
59 Yarn,
60};
61
62enum class AmiiboSeries : u8 {
63 SuperSmashBros,
64 SuperMario,
65 ChibiRobo,
66 YoshiWoollyWorld,
67 Splatoon,
68 AnimalCrossing,
69 EightBitMario,
70 Skylanders,
71 Unknown8,
72 TheLegendOfZelda,
73 ShovelKnight,
74 Unknown11,
75 Kiby,
76 Pokemon,
77 MarioSportsSuperstars,
78 MonsterHunter,
79 BoxBoy,
80 Pikmin,
81 FireEmblem,
82 Metroid,
83 Others,
84 MegaMan,
85 Diablo
86};
87
56struct TagInfo { 88struct TagInfo {
57 std::array<u8, 10> uuid; 89 std::array<u8, 10> uuid;
58 u8 uuid_length; 90 u8 uuid_length;
59 INSERT_PADDING_BYTES(0x15); 91 INSERT_PADDING_BYTES(0x15);
60 u32 protocol; 92 s32 protocol;
61 u32 tag_type; 93 u32 tag_type;
62 INSERT_PADDING_BYTES(0x30); 94 INSERT_PADDING_BYTES(0x30);
63}; 95};
@@ -77,10 +109,13 @@ static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
77struct ModelInfo { 109struct ModelInfo {
78 u16 character_id; 110 u16 character_id;
79 u8 character_variant; 111 u8 character_variant;
80 u8 figure_type; 112 AmiiboType amiibo_type;
81 u16 model_number; 113 u16 model_number;
82 u8 series; 114 AmiiboSeries series;
83 INSERT_PADDING_BYTES(0x39); 115 u8 fixed; // Must be 02
116 INSERT_PADDING_BYTES(0x4); // Unknown
117 INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash
118 INSERT_PADDING_BYTES(0x14); // SHA256-HMAC
84}; 119};
85static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); 120static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
86 121
@@ -105,11 +140,21 @@ public:
105 140
106 struct AmiiboFile { 141 struct AmiiboFile {
107 std::array<u8, 10> uuid; 142 std::array<u8, 10> uuid;
108 INSERT_PADDING_BYTES(0x4); // Compability container 143 u16 uuid_lock; // Must be 0F E0
109 INSERT_PADDING_BYTES(0x46); 144 u32 compability_container; // Must be F1 10 FF EE
110 ModelInfo model_info; 145 u16 crypto_init; // Must be A5 XX
146 u16 write_count; // Number of times the amiibo has been written?
147 INSERT_PADDING_BYTES(0x20); // System crypts
148 INSERT_PADDING_BYTES(0x20); // SHA256-(HMAC?) hash
149 ModelInfo model_info; // This struct is bigger than documentation
150 INSERT_PADDING_BYTES(0xC); // SHA256-HMAC
151 INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer
152 INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer
153 u32 tag_dynamic_lock; // Must be 01 00 0F XX
154 u32 tag_CFG0; // Must be 00 00 00 04
155 u32 tag_CFG1; // Must be 50 00 00 00
111 }; 156 };
112 static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); 157 static_assert(sizeof(AmiiboFile) == 0x214, "AmiiboFile is an invalid size");
113 158
114 void CreateUserInterface(Kernel::HLERequestContext& ctx); 159 void CreateUserInterface(Kernel::HLERequestContext& ctx);
115 bool LoadAmiibo(const std::vector<u8>& buffer); 160 bool LoadAmiibo(const std::vector<u8>& buffer);
@@ -118,7 +163,7 @@ public:
118 void Initialize(); 163 void Initialize();
119 void Finalize(); 164 void Finalize();
120 165
121 ResultCode StartDetection(); 166 ResultCode StartDetection(s32 protocol_);
122 ResultCode StopDetection(); 167 ResultCode StopDetection();
123 ResultCode Mount(); 168 ResultCode Mount();
124 ResultCode Unmount(); 169 ResultCode Unmount();
@@ -144,6 +189,12 @@ public:
144 std::shared_ptr<Module> module; 189 std::shared_ptr<Module> module;
145 190
146 private: 191 private:
192 /// Validates that the amiibo file is not corrupted
193 bool IsAmiiboValid() const;
194 bool AmiiboApplicationDataExist(u32 access_id) const;
195 const std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const;
196 void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const;
197
147 const Core::HID::NpadIdType npad_id; 198 const Core::HID::NpadIdType npad_id;
148 199
149 DeviceState device_state{DeviceState::Unaviable}; 200 DeviceState device_state{DeviceState::Unaviable};
@@ -151,7 +202,7 @@ public:
151 Kernel::KEvent* activate_event; 202 Kernel::KEvent* activate_event;
152 Kernel::KEvent* deactivate_event; 203 Kernel::KEvent* deactivate_event;
153 AmiiboFile amiibo{}; 204 AmiiboFile amiibo{};
154 u16 write_counter{}; 205 s32 protocol;
155 bool is_application_area_initialized{}; 206 bool is_application_area_initialized{};
156 u32 application_area_id; 207 u32 application_area_id;
157 std::vector<u8> application_area_data; 208 std::vector<u8> application_area_data;