nfp.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include <atomic>
  5. #include "common/fs/file.h"
  6. #include "common/fs/path_util.h"
  7. #include "common/logging/log.h"
  8. #include "common/string_util.h"
  9. #include "core/core.h"
  10. #include "core/hid/emulated_controller.h"
  11. #include "core/hid/hid_core.h"
  12. #include "core/hid/hid_types.h"
  13. #include "core/hle/ipc_helpers.h"
  14. #include "core/hle/kernel/k_event.h"
  15. #include "core/hle/service/mii/mii_manager.h"
  16. #include "core/hle/service/nfp/amiibo_crypto.h"
  17. #include "core/hle/service/nfp/nfp.h"
  18. #include "core/hle/service/nfp/nfp_user.h"
  19. namespace Service::NFP {
  20. namespace ErrCodes {
  21. constexpr Result DeviceNotFound(ErrorModule::NFP, 64);
  22. constexpr Result WrongDeviceState(ErrorModule::NFP, 73);
  23. constexpr Result NfcDisabled(ErrorModule::NFP, 80);
  24. constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88);
  25. constexpr Result TagRemoved(ErrorModule::NFP, 97);
  26. constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
  27. constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152);
  28. constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168);
  29. } // namespace ErrCodes
  30. IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_)
  31. : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name},
  32. nfp_interface{nfp_interface_} {
  33. static const FunctionInfo functions[] = {
  34. {0, &IUser::Initialize, "Initialize"},
  35. {1, &IUser::Finalize, "Finalize"},
  36. {2, &IUser::ListDevices, "ListDevices"},
  37. {3, &IUser::StartDetection, "StartDetection"},
  38. {4, &IUser::StopDetection, "StopDetection"},
  39. {5, &IUser::Mount, "Mount"},
  40. {6, &IUser::Unmount, "Unmount"},
  41. {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
  42. {8, &IUser::GetApplicationArea, "GetApplicationArea"},
  43. {9, &IUser::SetApplicationArea, "SetApplicationArea"},
  44. {10, &IUser::Flush, "Flush"},
  45. {11, nullptr, "Restore"},
  46. {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
  47. {13, &IUser::GetTagInfo, "GetTagInfo"},
  48. {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
  49. {15, &IUser::GetCommonInfo, "GetCommonInfo"},
  50. {16, &IUser::GetModelInfo, "GetModelInfo"},
  51. {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
  52. {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
  53. {19, &IUser::GetState, "GetState"},
  54. {20, &IUser::GetDeviceState, "GetDeviceState"},
  55. {21, &IUser::GetNpadId, "GetNpadId"},
  56. {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
  57. {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
  58. {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
  59. };
  60. RegisterHandlers(functions);
  61. availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
  62. }
  63. void IUser::Initialize(Kernel::HLERequestContext& ctx) {
  64. LOG_INFO(Service_NFC, "called");
  65. state = State::Initialized;
  66. // TODO(german77): Loop through all interfaces
  67. nfp_interface.Initialize();
  68. IPC::ResponseBuilder rb{ctx, 2, 0};
  69. rb.Push(ResultSuccess);
  70. }
  71. void IUser::Finalize(Kernel::HLERequestContext& ctx) {
  72. LOG_INFO(Service_NFP, "called");
  73. state = State::NonInitialized;
  74. // TODO(german77): Loop through all interfaces
  75. nfp_interface.Finalize();
  76. IPC::ResponseBuilder rb{ctx, 2};
  77. rb.Push(ResultSuccess);
  78. }
  79. void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
  80. LOG_INFO(Service_NFP, "called");
  81. if (state == State::NonInitialized) {
  82. IPC::ResponseBuilder rb{ctx, 2};
  83. rb.Push(ErrCodes::NfcDisabled);
  84. return;
  85. }
  86. std::vector<u64> devices;
  87. // TODO(german77): Loop through all interfaces
  88. devices.push_back(nfp_interface.GetHandle());
  89. if (devices.size() == 0) {
  90. IPC::ResponseBuilder rb{ctx, 2};
  91. rb.Push(ErrCodes::DeviceNotFound);
  92. return;
  93. }
  94. ctx.WriteBuffer(devices);
  95. IPC::ResponseBuilder rb{ctx, 3};
  96. rb.Push(ResultSuccess);
  97. rb.Push(static_cast<s32>(devices.size()));
  98. }
  99. void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
  100. IPC::RequestParser rp{ctx};
  101. const auto device_handle{rp.Pop<u64>()};
  102. const auto nfp_protocol{rp.Pop<s32>()};
  103. LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
  104. if (state == State::NonInitialized) {
  105. IPC::ResponseBuilder rb{ctx, 2};
  106. rb.Push(ErrCodes::NfcDisabled);
  107. return;
  108. }
  109. // TODO(german77): Loop through all interfaces
  110. if (device_handle == nfp_interface.GetHandle()) {
  111. const auto result = nfp_interface.StartDetection(nfp_protocol);
  112. IPC::ResponseBuilder rb{ctx, 2};
  113. rb.Push(result);
  114. return;
  115. }
  116. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  117. IPC::ResponseBuilder rb{ctx, 2};
  118. rb.Push(ErrCodes::DeviceNotFound);
  119. }
  120. void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
  121. IPC::RequestParser rp{ctx};
  122. const auto device_handle{rp.Pop<u64>()};
  123. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  124. if (state == State::NonInitialized) {
  125. IPC::ResponseBuilder rb{ctx, 2};
  126. rb.Push(ErrCodes::NfcDisabled);
  127. return;
  128. }
  129. // TODO(german77): Loop through all interfaces
  130. if (device_handle == nfp_interface.GetHandle()) {
  131. const auto result = nfp_interface.StopDetection();
  132. IPC::ResponseBuilder rb{ctx, 2};
  133. rb.Push(result);
  134. return;
  135. }
  136. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  137. IPC::ResponseBuilder rb{ctx, 2};
  138. rb.Push(ErrCodes::DeviceNotFound);
  139. }
  140. void IUser::Mount(Kernel::HLERequestContext& ctx) {
  141. IPC::RequestParser rp{ctx};
  142. const auto device_handle{rp.Pop<u64>()};
  143. const auto model_type{rp.PopEnum<ModelType>()};
  144. const auto mount_target{rp.PopEnum<MountTarget>()};
  145. LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
  146. model_type, mount_target);
  147. if (state == State::NonInitialized) {
  148. IPC::ResponseBuilder rb{ctx, 2};
  149. rb.Push(ErrCodes::NfcDisabled);
  150. return;
  151. }
  152. // TODO(german77): Loop through all interfaces
  153. if (device_handle == nfp_interface.GetHandle()) {
  154. const auto result = nfp_interface.Mount();
  155. IPC::ResponseBuilder rb{ctx, 2};
  156. rb.Push(result);
  157. return;
  158. }
  159. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  160. IPC::ResponseBuilder rb{ctx, 2};
  161. rb.Push(ErrCodes::DeviceNotFound);
  162. }
  163. void IUser::Unmount(Kernel::HLERequestContext& ctx) {
  164. IPC::RequestParser rp{ctx};
  165. const auto device_handle{rp.Pop<u64>()};
  166. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  167. if (state == State::NonInitialized) {
  168. IPC::ResponseBuilder rb{ctx, 2};
  169. rb.Push(ErrCodes::NfcDisabled);
  170. return;
  171. }
  172. // TODO(german77): Loop through all interfaces
  173. if (device_handle == nfp_interface.GetHandle()) {
  174. const auto result = nfp_interface.Unmount();
  175. IPC::ResponseBuilder rb{ctx, 2};
  176. rb.Push(result);
  177. return;
  178. }
  179. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  180. IPC::ResponseBuilder rb{ctx, 2};
  181. rb.Push(ErrCodes::DeviceNotFound);
  182. }
  183. void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) {
  184. IPC::RequestParser rp{ctx};
  185. const auto device_handle{rp.Pop<u64>()};
  186. const auto access_id{rp.Pop<u32>()};
  187. LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, access_id={}", device_handle,
  188. access_id);
  189. if (state == State::NonInitialized) {
  190. IPC::ResponseBuilder rb{ctx, 2};
  191. rb.Push(ErrCodes::NfcDisabled);
  192. return;
  193. }
  194. // TODO(german77): Loop through all interfaces
  195. if (device_handle == nfp_interface.GetHandle()) {
  196. const auto result = nfp_interface.OpenApplicationArea(access_id);
  197. IPC::ResponseBuilder rb{ctx, 2};
  198. rb.Push(result);
  199. return;
  200. }
  201. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  202. IPC::ResponseBuilder rb{ctx, 2};
  203. rb.Push(ErrCodes::DeviceNotFound);
  204. }
  205. void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {
  206. IPC::RequestParser rp{ctx};
  207. const auto device_handle{rp.Pop<u64>()};
  208. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  209. if (state == State::NonInitialized) {
  210. IPC::ResponseBuilder rb{ctx, 2};
  211. rb.Push(ErrCodes::NfcDisabled);
  212. return;
  213. }
  214. // TODO(german77): Loop through all interfaces
  215. if (device_handle == nfp_interface.GetHandle()) {
  216. ApplicationArea data{};
  217. const auto result = nfp_interface.GetApplicationArea(data);
  218. ctx.WriteBuffer(data);
  219. IPC::ResponseBuilder rb{ctx, 3};
  220. rb.Push(result);
  221. rb.Push(static_cast<u32>(data.size()));
  222. return;
  223. }
  224. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  225. IPC::ResponseBuilder rb{ctx, 2};
  226. rb.Push(ErrCodes::DeviceNotFound);
  227. }
  228. void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {
  229. IPC::RequestParser rp{ctx};
  230. const auto device_handle{rp.Pop<u64>()};
  231. const auto data{ctx.ReadBuffer()};
  232. LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}", device_handle,
  233. data.size());
  234. if (state == State::NonInitialized) {
  235. IPC::ResponseBuilder rb{ctx, 2};
  236. rb.Push(ErrCodes::NfcDisabled);
  237. return;
  238. }
  239. // TODO(german77): Loop through all interfaces
  240. if (device_handle == nfp_interface.GetHandle()) {
  241. const auto result = nfp_interface.SetApplicationArea(data);
  242. IPC::ResponseBuilder rb{ctx, 2};
  243. rb.Push(result);
  244. return;
  245. }
  246. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  247. IPC::ResponseBuilder rb{ctx, 2};
  248. rb.Push(ErrCodes::DeviceNotFound);
  249. }
  250. void IUser::Flush(Kernel::HLERequestContext& ctx) {
  251. IPC::RequestParser rp{ctx};
  252. const auto device_handle{rp.Pop<u64>()};
  253. LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
  254. if (state == State::NonInitialized) {
  255. IPC::ResponseBuilder rb{ctx, 2};
  256. rb.Push(ErrCodes::NfcDisabled);
  257. return;
  258. }
  259. // TODO(german77): Loop through all interfaces
  260. if (device_handle == nfp_interface.GetHandle()) {
  261. const auto result = nfp_interface.Flush();
  262. IPC::ResponseBuilder rb{ctx, 2};
  263. rb.Push(result);
  264. return;
  265. }
  266. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  267. IPC::ResponseBuilder rb{ctx, 2};
  268. rb.Push(ErrCodes::DeviceNotFound);
  269. }
  270. void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
  271. IPC::RequestParser rp{ctx};
  272. const auto device_handle{rp.Pop<u64>()};
  273. const auto access_id{rp.Pop<u32>()};
  274. const auto data{ctx.ReadBuffer()};
  275. LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}, access_id={}",
  276. device_handle, access_id, data.size());
  277. if (state == State::NonInitialized) {
  278. IPC::ResponseBuilder rb{ctx, 2};
  279. rb.Push(ErrCodes::NfcDisabled);
  280. return;
  281. }
  282. // TODO(german77): Loop through all interfaces
  283. if (device_handle == nfp_interface.GetHandle()) {
  284. const auto result = nfp_interface.CreateApplicationArea(access_id, data);
  285. IPC::ResponseBuilder rb{ctx, 2};
  286. rb.Push(result);
  287. return;
  288. }
  289. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  290. IPC::ResponseBuilder rb{ctx, 2};
  291. rb.Push(ErrCodes::DeviceNotFound);
  292. }
  293. void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
  294. IPC::RequestParser rp{ctx};
  295. const auto device_handle{rp.Pop<u64>()};
  296. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  297. if (state == State::NonInitialized) {
  298. IPC::ResponseBuilder rb{ctx, 2};
  299. rb.Push(ErrCodes::NfcDisabled);
  300. return;
  301. }
  302. // TODO(german77): Loop through all interfaces
  303. if (device_handle == nfp_interface.GetHandle()) {
  304. TagInfo tag_info{};
  305. const auto result = nfp_interface.GetTagInfo(tag_info);
  306. ctx.WriteBuffer(tag_info);
  307. IPC::ResponseBuilder rb{ctx, 2};
  308. rb.Push(result);
  309. return;
  310. }
  311. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  312. IPC::ResponseBuilder rb{ctx, 2};
  313. rb.Push(ErrCodes::DeviceNotFound);
  314. }
  315. void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) {
  316. IPC::RequestParser rp{ctx};
  317. const auto device_handle{rp.Pop<u64>()};
  318. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  319. if (state == State::NonInitialized) {
  320. IPC::ResponseBuilder rb{ctx, 2};
  321. rb.Push(ErrCodes::NfcDisabled);
  322. return;
  323. }
  324. // TODO(german77): Loop through all interfaces
  325. if (device_handle == nfp_interface.GetHandle()) {
  326. RegisterInfo register_info{};
  327. const auto result = nfp_interface.GetRegisterInfo(register_info);
  328. ctx.WriteBuffer(register_info);
  329. IPC::ResponseBuilder rb{ctx, 2};
  330. rb.Push(result);
  331. return;
  332. }
  333. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  334. IPC::ResponseBuilder rb{ctx, 2};
  335. rb.Push(ErrCodes::DeviceNotFound);
  336. }
  337. void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) {
  338. IPC::RequestParser rp{ctx};
  339. const auto device_handle{rp.Pop<u64>()};
  340. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  341. if (state == State::NonInitialized) {
  342. IPC::ResponseBuilder rb{ctx, 2};
  343. rb.Push(ErrCodes::NfcDisabled);
  344. return;
  345. }
  346. // TODO(german77): Loop through all interfaces
  347. if (device_handle == nfp_interface.GetHandle()) {
  348. CommonInfo common_info{};
  349. const auto result = nfp_interface.GetCommonInfo(common_info);
  350. ctx.WriteBuffer(common_info);
  351. IPC::ResponseBuilder rb{ctx, 2};
  352. rb.Push(result);
  353. return;
  354. }
  355. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  356. IPC::ResponseBuilder rb{ctx, 2};
  357. rb.Push(ErrCodes::DeviceNotFound);
  358. }
  359. void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) {
  360. IPC::RequestParser rp{ctx};
  361. const auto device_handle{rp.Pop<u64>()};
  362. LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
  363. if (state == State::NonInitialized) {
  364. IPC::ResponseBuilder rb{ctx, 2};
  365. rb.Push(ErrCodes::NfcDisabled);
  366. return;
  367. }
  368. // TODO(german77): Loop through all interfaces
  369. if (device_handle == nfp_interface.GetHandle()) {
  370. ModelInfo model_info{};
  371. const auto result = nfp_interface.GetModelInfo(model_info);
  372. ctx.WriteBuffer(model_info);
  373. IPC::ResponseBuilder rb{ctx, 2};
  374. rb.Push(result);
  375. return;
  376. }
  377. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  378. IPC::ResponseBuilder rb{ctx, 2};
  379. rb.Push(ErrCodes::DeviceNotFound);
  380. }
  381. void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
  382. IPC::RequestParser rp{ctx};
  383. const auto device_handle{rp.Pop<u64>()};
  384. LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
  385. if (state == State::NonInitialized) {
  386. IPC::ResponseBuilder rb{ctx, 2};
  387. rb.Push(ErrCodes::NfcDisabled);
  388. return;
  389. }
  390. // TODO(german77): Loop through all interfaces
  391. if (device_handle == nfp_interface.GetHandle()) {
  392. IPC::ResponseBuilder rb{ctx, 2, 1};
  393. rb.Push(ResultSuccess);
  394. rb.PushCopyObjects(nfp_interface.GetActivateEvent());
  395. return;
  396. }
  397. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  398. IPC::ResponseBuilder rb{ctx, 2};
  399. rb.Push(ErrCodes::DeviceNotFound);
  400. }
  401. void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
  402. IPC::RequestParser rp{ctx};
  403. const auto device_handle{rp.Pop<u64>()};
  404. LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
  405. if (state == State::NonInitialized) {
  406. IPC::ResponseBuilder rb{ctx, 2};
  407. rb.Push(ErrCodes::NfcDisabled);
  408. return;
  409. }
  410. // TODO(german77): Loop through all interfaces
  411. if (device_handle == nfp_interface.GetHandle()) {
  412. IPC::ResponseBuilder rb{ctx, 2, 1};
  413. rb.Push(ResultSuccess);
  414. rb.PushCopyObjects(nfp_interface.GetDeactivateEvent());
  415. return;
  416. }
  417. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  418. IPC::ResponseBuilder rb{ctx, 2};
  419. rb.Push(ErrCodes::DeviceNotFound);
  420. }
  421. void IUser::GetState(Kernel::HLERequestContext& ctx) {
  422. LOG_DEBUG(Service_NFC, "called");
  423. IPC::ResponseBuilder rb{ctx, 3, 0};
  424. rb.Push(ResultSuccess);
  425. rb.PushEnum(state);
  426. }
  427. void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
  428. IPC::RequestParser rp{ctx};
  429. const auto device_handle{rp.Pop<u64>()};
  430. LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
  431. // TODO(german77): Loop through all interfaces
  432. if (device_handle == nfp_interface.GetHandle()) {
  433. IPC::ResponseBuilder rb{ctx, 3};
  434. rb.Push(ResultSuccess);
  435. rb.PushEnum(nfp_interface.GetCurrentState());
  436. return;
  437. }
  438. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  439. IPC::ResponseBuilder rb{ctx, 2};
  440. rb.Push(ErrCodes::DeviceNotFound);
  441. }
  442. void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
  443. IPC::RequestParser rp{ctx};
  444. const auto device_handle{rp.Pop<u64>()};
  445. LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
  446. if (state == State::NonInitialized) {
  447. IPC::ResponseBuilder rb{ctx, 2};
  448. rb.Push(ErrCodes::NfcDisabled);
  449. return;
  450. }
  451. // TODO(german77): Loop through all interfaces
  452. if (device_handle == nfp_interface.GetHandle()) {
  453. IPC::ResponseBuilder rb{ctx, 3};
  454. rb.Push(ResultSuccess);
  455. rb.PushEnum(nfp_interface.GetNpadId());
  456. return;
  457. }
  458. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  459. IPC::ResponseBuilder rb{ctx, 2};
  460. rb.Push(ErrCodes::DeviceNotFound);
  461. }
  462. void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
  463. IPC::RequestParser rp{ctx};
  464. const auto device_handle{rp.Pop<u64>()};
  465. LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
  466. // TODO(german77): Loop through all interfaces
  467. if (device_handle == nfp_interface.GetHandle()) {
  468. IPC::ResponseBuilder rb{ctx, 3};
  469. rb.Push(ResultSuccess);
  470. rb.Push(sizeof(ApplicationArea));
  471. return;
  472. }
  473. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  474. IPC::ResponseBuilder rb{ctx, 2};
  475. rb.Push(ErrCodes::DeviceNotFound);
  476. }
  477. void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
  478. LOG_DEBUG(Service_NFP, "(STUBBED) called");
  479. if (state == State::NonInitialized) {
  480. IPC::ResponseBuilder rb{ctx, 2};
  481. rb.Push(ErrCodes::NfcDisabled);
  482. return;
  483. }
  484. IPC::ResponseBuilder rb{ctx, 2, 1};
  485. rb.Push(ResultSuccess);
  486. rb.PushCopyObjects(availability_change_event->GetReadableEvent());
  487. }
  488. void IUser::RecreateApplicationArea(Kernel::HLERequestContext& ctx) {
  489. IPC::RequestParser rp{ctx};
  490. const auto device_handle{rp.Pop<u64>()};
  491. const auto access_id{rp.Pop<u32>()};
  492. const auto data{ctx.ReadBuffer()};
  493. LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}, access_id={}",
  494. device_handle, access_id, data.size());
  495. if (state == State::NonInitialized) {
  496. IPC::ResponseBuilder rb{ctx, 2};
  497. rb.Push(ErrCodes::NfcDisabled);
  498. return;
  499. }
  500. // TODO(german77): Loop through all interfaces
  501. if (device_handle == nfp_interface.GetHandle()) {
  502. const auto result = nfp_interface.RecreateApplicationArea(access_id, data);
  503. IPC::ResponseBuilder rb{ctx, 2};
  504. rb.Push(result);
  505. return;
  506. }
  507. LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle);
  508. IPC::ResponseBuilder rb{ctx, 2};
  509. rb.Push(ErrCodes::DeviceNotFound);
  510. }
  511. Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
  512. const char* name)
  513. : ServiceFramework{system_, name}, module{std::move(module_)},
  514. npad_id{Core::HID::NpadIdType::Player1}, service_context{system_, service_name} {
  515. activate_event = service_context.CreateEvent("IUser:NFPActivateEvent");
  516. deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent");
  517. }
  518. Module::Interface::~Interface() = default;
  519. void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
  520. LOG_DEBUG(Service_NFP, "called");
  521. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  522. rb.Push(ResultSuccess);
  523. rb.PushIpcInterface<IUser>(*this, system);
  524. }
  525. bool Module::Interface::LoadAmiiboFile(const std::string& filename) {
  526. constexpr auto tag_size_without_password = sizeof(NTAG215File) - sizeof(NTAG215Password);
  527. const Common::FS::IOFile amiibo_file{filename, Common::FS::FileAccessMode::Read,
  528. Common::FS::FileType::BinaryFile};
  529. if (!amiibo_file.IsOpen()) {
  530. LOG_ERROR(Service_NFP, "Amiibo is already on use");
  531. return false;
  532. }
  533. // Workaround for files with missing password data
  534. std::array<u8, sizeof(EncryptedNTAG215File)> buffer{};
  535. if (amiibo_file.Read(buffer) < tag_size_without_password) {
  536. LOG_ERROR(Service_NFP, "Failed to read amiibo file");
  537. return false;
  538. }
  539. memcpy(&encrypted_tag_data, buffer.data(), sizeof(EncryptedNTAG215File));
  540. if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
  541. LOG_INFO(Service_NFP, "Invalid amiibo");
  542. return false;
  543. }
  544. file_path = filename;
  545. return true;
  546. }
  547. bool Module::Interface::LoadAmiibo(const std::string& filename) {
  548. if (device_state != DeviceState::SearchingForTag) {
  549. LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state);
  550. return false;
  551. }
  552. if (!LoadAmiiboFile(filename)) {
  553. return false;
  554. }
  555. device_state = DeviceState::TagFound;
  556. activate_event->GetWritableEvent().Signal();
  557. return true;
  558. }
  559. void Module::Interface::CloseAmiibo() {
  560. LOG_INFO(Service_NFP, "Remove amiibo");
  561. device_state = DeviceState::TagRemoved;
  562. is_data_decoded = false;
  563. is_application_area_initialized = false;
  564. encrypted_tag_data = {};
  565. tag_data = {};
  566. deactivate_event->GetWritableEvent().Signal();
  567. }
  568. Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const {
  569. return activate_event->GetReadableEvent();
  570. }
  571. Kernel::KReadableEvent& Module::Interface::GetDeactivateEvent() const {
  572. return deactivate_event->GetReadableEvent();
  573. }
  574. void Module::Interface::Initialize() {
  575. device_state = DeviceState::Initialized;
  576. is_data_decoded = false;
  577. is_application_area_initialized = false;
  578. encrypted_tag_data = {};
  579. tag_data = {};
  580. }
  581. void Module::Interface::Finalize() {
  582. if (device_state == DeviceState::TagMounted) {
  583. Unmount();
  584. }
  585. if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
  586. StopDetection();
  587. }
  588. device_state = DeviceState::Unaviable;
  589. }
  590. Result Module::Interface::StartDetection(s32 protocol_) {
  591. auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
  592. // TODO(german77): Add callback for when nfc data is available
  593. if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
  594. npad_device->SetPollingMode(Common::Input::PollingMode::NFC);
  595. device_state = DeviceState::SearchingForTag;
  596. protocol = protocol_;
  597. return ResultSuccess;
  598. }
  599. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  600. return ErrCodes::WrongDeviceState;
  601. }
  602. Result Module::Interface::StopDetection() {
  603. auto npad_device = system.HIDCore().GetEmulatedController(npad_id);
  604. npad_device->SetPollingMode(Common::Input::PollingMode::Active);
  605. if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
  606. CloseAmiibo();
  607. return ResultSuccess;
  608. }
  609. if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
  610. device_state = DeviceState::Initialized;
  611. return ResultSuccess;
  612. }
  613. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  614. return ErrCodes::WrongDeviceState;
  615. }
  616. Result Module::Interface::Flush() {
  617. // Ignore write command if we can't encrypt the data
  618. if (!is_data_decoded) {
  619. return ResultSuccess;
  620. }
  621. constexpr auto tag_size_without_password = sizeof(NTAG215File) - sizeof(NTAG215Password);
  622. EncryptedNTAG215File tmp_encrypted_tag_data{};
  623. const Common::FS::IOFile amiibo_file{file_path, Common::FS::FileAccessMode::ReadWrite,
  624. Common::FS::FileType::BinaryFile};
  625. if (!amiibo_file.IsOpen()) {
  626. LOG_ERROR(Core, "Amiibo is already on use");
  627. return ErrCodes::WriteAmiiboFailed;
  628. }
  629. // Workaround for files with missing password data
  630. std::array<u8, sizeof(EncryptedNTAG215File)> buffer{};
  631. if (amiibo_file.Read(buffer) < tag_size_without_password) {
  632. LOG_ERROR(Core, "Failed to read amiibo file");
  633. return ErrCodes::WriteAmiiboFailed;
  634. }
  635. memcpy(&tmp_encrypted_tag_data, buffer.data(), sizeof(EncryptedNTAG215File));
  636. if (!AmiiboCrypto::IsAmiiboValid(tmp_encrypted_tag_data)) {
  637. LOG_INFO(Service_NFP, "Invalid amiibo");
  638. return ErrCodes::WriteAmiiboFailed;
  639. }
  640. bool is_uuid_equal = memcmp(tmp_encrypted_tag_data.uuid.data(), tag_data.uuid.data(), 8) == 0;
  641. bool is_character_equal = tmp_encrypted_tag_data.user_memory.model_info.character_id ==
  642. tag_data.model_info.character_id;
  643. if (!is_uuid_equal || !is_character_equal) {
  644. LOG_ERROR(Service_NFP, "Not the same amiibo");
  645. return ErrCodes::WriteAmiiboFailed;
  646. }
  647. if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
  648. LOG_ERROR(Service_NFP, "Failed to encode data");
  649. return ErrCodes::WriteAmiiboFailed;
  650. }
  651. // Return to the start of the file
  652. if (!amiibo_file.Seek(0)) {
  653. LOG_ERROR(Service_NFP, "Error writing to file");
  654. return ErrCodes::WriteAmiiboFailed;
  655. }
  656. if (!amiibo_file.Write(encrypted_tag_data)) {
  657. LOG_ERROR(Service_NFP, "Error writing to file");
  658. return ErrCodes::WriteAmiiboFailed;
  659. }
  660. return ResultSuccess;
  661. }
  662. Result Module::Interface::Mount() {
  663. if (device_state != DeviceState::TagFound) {
  664. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  665. return ErrCodes::WrongDeviceState;
  666. }
  667. is_data_decoded = AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data);
  668. LOG_INFO(Service_NFP, "Is amiibo decoded {}", is_data_decoded);
  669. is_application_area_initialized = false;
  670. device_state = DeviceState::TagMounted;
  671. return ResultSuccess;
  672. }
  673. Result Module::Interface::Unmount() {
  674. if (device_state != DeviceState::TagMounted) {
  675. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  676. return ErrCodes::WrongDeviceState;
  677. }
  678. is_data_decoded = false;
  679. is_application_area_initialized = false;
  680. device_state = DeviceState::TagFound;
  681. return ResultSuccess;
  682. }
  683. Result Module::Interface::GetTagInfo(TagInfo& tag_info) const {
  684. if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
  685. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  686. return ErrCodes::WrongDeviceState;
  687. }
  688. tag_info = {
  689. .uuid = encrypted_tag_data.uuid,
  690. .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.size()),
  691. .protocol = protocol,
  692. .tag_type = static_cast<u32>(encrypted_tag_data.user_memory.model_info.amiibo_type),
  693. };
  694. return ResultSuccess;
  695. }
  696. Result Module::Interface::GetCommonInfo(CommonInfo& common_info) const {
  697. if (device_state != DeviceState::TagMounted) {
  698. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  699. return ErrCodes::WrongDeviceState;
  700. }
  701. if (is_data_decoded && tag_data.settings.settings.amiibo_initialized != 0) {
  702. const auto& settings = tag_data.settings;
  703. // TODO: Validate this data
  704. common_info = {
  705. .last_write_year = settings.write_date.GetYear(),
  706. .last_write_month = settings.write_date.GetMonth(),
  707. .last_write_day = settings.write_date.GetDay(),
  708. .write_counter = settings.crc_counter,
  709. .version = 1,
  710. .application_area_size = sizeof(ApplicationArea),
  711. };
  712. return ResultSuccess;
  713. }
  714. // Generate a generic answer
  715. common_info = {
  716. .last_write_year = 2022,
  717. .last_write_month = 2,
  718. .last_write_day = 7,
  719. .write_counter = 0,
  720. .version = 1,
  721. .application_area_size = sizeof(ApplicationArea),
  722. };
  723. return ResultSuccess;
  724. }
  725. Result Module::Interface::GetModelInfo(ModelInfo& model_info) const {
  726. if (device_state != DeviceState::TagMounted) {
  727. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  728. return ErrCodes::WrongDeviceState;
  729. }
  730. const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
  731. model_info = {
  732. .character_id = model_info_data.character_id,
  733. .character_variant = model_info_data.character_variant,
  734. .amiibo_type = model_info_data.amiibo_type,
  735. .model_number = model_info_data.model_number,
  736. .series = model_info_data.series,
  737. .constant_value = model_info_data.constant_value,
  738. };
  739. return ResultSuccess;
  740. }
  741. Result Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const {
  742. if (device_state != DeviceState::TagMounted) {
  743. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  744. if (device_state == DeviceState::TagRemoved) {
  745. return ErrCodes::TagRemoved;
  746. }
  747. return ErrCodes::WrongDeviceState;
  748. }
  749. Service::Mii::MiiManager manager;
  750. if (is_data_decoded && tag_data.settings.settings.amiibo_initialized != 0) {
  751. const auto& settings = tag_data.settings;
  752. // TODO: Validate this data
  753. register_info = {
  754. .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
  755. .first_write_year = settings.init_date.GetYear(),
  756. .first_write_month = settings.init_date.GetMonth(),
  757. .first_write_day = settings.init_date.GetDay(),
  758. .amiibo_name = GetAmiiboName(settings),
  759. .font_region = {},
  760. };
  761. return ResultSuccess;
  762. }
  763. // Generate a generic answer
  764. register_info = {
  765. .mii_char_info = manager.BuildDefault(0),
  766. .first_write_year = 2022,
  767. .first_write_month = 2,
  768. .first_write_day = 7,
  769. .amiibo_name = {'Y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o', 0},
  770. .font_region = {},
  771. };
  772. return ResultSuccess;
  773. }
  774. Result Module::Interface::OpenApplicationArea(u32 access_id) {
  775. if (device_state != DeviceState::TagMounted) {
  776. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  777. if (device_state == DeviceState::TagRemoved) {
  778. return ErrCodes::TagRemoved;
  779. }
  780. return ErrCodes::WrongDeviceState;
  781. }
  782. // Fallback for lack of amiibo keys
  783. if (!is_data_decoded) {
  784. LOG_WARNING(Service_NFP, "Application area is not initialized");
  785. return ErrCodes::ApplicationAreaIsNotInitialized;
  786. }
  787. if (tag_data.settings.settings.appdata_initialized == 0) {
  788. LOG_WARNING(Service_NFP, "Application area is not initialized");
  789. return ErrCodes::ApplicationAreaIsNotInitialized;
  790. }
  791. if (tag_data.application_area_id != access_id) {
  792. LOG_WARNING(Service_NFP, "Wrong application area id");
  793. return ErrCodes::WrongApplicationAreaId;
  794. }
  795. is_application_area_initialized = true;
  796. return ResultSuccess;
  797. }
  798. Result Module::Interface::GetApplicationArea(ApplicationArea& data) const {
  799. if (device_state != DeviceState::TagMounted) {
  800. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  801. if (device_state == DeviceState::TagRemoved) {
  802. return ErrCodes::TagRemoved;
  803. }
  804. return ErrCodes::WrongDeviceState;
  805. }
  806. if (!is_application_area_initialized) {
  807. LOG_ERROR(Service_NFP, "Application area is not initialized");
  808. return ErrCodes::ApplicationAreaIsNotInitialized;
  809. }
  810. data = tag_data.application_area;
  811. return ResultSuccess;
  812. }
  813. Result Module::Interface::SetApplicationArea(const std::vector<u8>& data) {
  814. if (device_state != DeviceState::TagMounted) {
  815. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  816. if (device_state == DeviceState::TagRemoved) {
  817. return ErrCodes::TagRemoved;
  818. }
  819. return ErrCodes::WrongDeviceState;
  820. }
  821. if (!is_application_area_initialized) {
  822. LOG_ERROR(Service_NFP, "Application area is not initialized");
  823. return ErrCodes::ApplicationAreaIsNotInitialized;
  824. }
  825. if (data.size() != sizeof(ApplicationArea)) {
  826. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  827. return ResultUnknown;
  828. }
  829. std::memcpy(&tag_data.application_area, data.data(), sizeof(ApplicationArea));
  830. return ResultSuccess;
  831. }
  832. Result Module::Interface::CreateApplicationArea(u32 access_id, const std::vector<u8>& data) {
  833. if (device_state != DeviceState::TagMounted) {
  834. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  835. if (device_state == DeviceState::TagRemoved) {
  836. return ErrCodes::TagRemoved;
  837. }
  838. return ErrCodes::WrongDeviceState;
  839. }
  840. if (tag_data.settings.settings.appdata_initialized != 0) {
  841. LOG_ERROR(Service_NFP, "Application area already exist");
  842. return ErrCodes::ApplicationAreaExist;
  843. }
  844. if (data.size() != sizeof(ApplicationArea)) {
  845. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  846. return ResultUnknown;
  847. }
  848. std::memcpy(&tag_data.application_area, data.data(), sizeof(ApplicationArea));
  849. tag_data.application_area_id = access_id;
  850. return ResultSuccess;
  851. }
  852. Result Module::Interface::RecreateApplicationArea(u32 access_id, const std::vector<u8>& data) {
  853. if (device_state != DeviceState::TagMounted) {
  854. LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
  855. if (device_state == DeviceState::TagRemoved) {
  856. return ErrCodes::TagRemoved;
  857. }
  858. return ErrCodes::WrongDeviceState;
  859. }
  860. if (data.size() != sizeof(ApplicationArea)) {
  861. LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
  862. return ResultUnknown;
  863. }
  864. std::memcpy(&tag_data.application_area, data.data(), sizeof(ApplicationArea));
  865. tag_data.application_area_id = access_id;
  866. return ResultSuccess;
  867. }
  868. u64 Module::Interface::GetHandle() const {
  869. // Generate a handle based of the npad id
  870. return static_cast<u64>(npad_id);
  871. }
  872. DeviceState Module::Interface::GetCurrentState() const {
  873. return device_state;
  874. }
  875. Core::HID::NpadIdType Module::Interface::GetNpadId() const {
  876. // Return first connected npad id as a workaround for lack of a single nfc interface per
  877. // controller
  878. return system.HIDCore().GetFirstNpadId();
  879. }
  880. AmiiboName Module::Interface::GetAmiiboName(const AmiiboSettings& settings) const {
  881. std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
  882. AmiiboName amiibo_name{};
  883. // Convert from big endian to little endian
  884. for (std::size_t i = 0; i < amiibo_name_length; i++) {
  885. settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
  886. }
  887. // Convert from utf16 to utf8
  888. const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
  889. memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
  890. return amiibo_name;
  891. }
  892. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  893. auto module = std::make_shared<Module>();
  894. std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
  895. }
  896. } // namespace Service::NFP