nfp.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <atomic>
  6. #include "common/logging/log.h"
  7. #include "core/core.h"
  8. #include "core/hle/ipc_helpers.h"
  9. #include "core/hle/kernel/k_event.h"
  10. #include "core/hle/kernel/k_readable_event.h"
  11. #include "core/hle/kernel/k_thread.h"
  12. #include "core/hle/kernel/k_writable_event.h"
  13. #include "core/hle/kernel/kernel.h"
  14. #include "core/hle/lock.h"
  15. #include "core/hle/service/nfp/nfp.h"
  16. #include "core/hle/service/nfp/nfp_user.h"
  17. namespace Service::NFP {
  18. namespace ErrCodes {
  19. constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
  20. } // namespace ErrCodes
  21. Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
  22. const char* name)
  23. : ServiceFramework{system_, name}, module{std::move(module_)} {
  24. auto& kernel = system.Kernel();
  25. nfc_tag_load = Kernel::KEvent::Create(kernel, "IUser:NFCTagDetected");
  26. nfc_tag_load->Initialize();
  27. }
  28. Module::Interface::~Interface() = default;
  29. class IUser final : public ServiceFramework<IUser> {
  30. public:
  31. explicit IUser(Module::Interface& nfp_interface_, Core::System& system_)
  32. : ServiceFramework{system_, "NFP::IUser"}, 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, nullptr, "SetApplicationArea"},
  44. {10, nullptr, "Flush"},
  45. {11, nullptr, "Restore"},
  46. {12, nullptr, "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, nullptr, "RecreateApplicationArea"},
  59. };
  60. RegisterHandlers(functions);
  61. auto& kernel = system.Kernel();
  62. deactivate_event = Kernel::KEvent::Create(kernel, "IUser:DeactivateEvent");
  63. deactivate_event->Initialize();
  64. availability_change_event = Kernel::KEvent::Create(kernel, "IUser:AvailabilityChangeEvent");
  65. availability_change_event->Initialize();
  66. }
  67. private:
  68. struct TagInfo {
  69. std::array<u8, 10> uuid;
  70. u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
  71. // mean something else
  72. std::array<u8, 0x15> padding_1;
  73. u32_le protocol;
  74. u32_le tag_type;
  75. std::array<u8, 0x2c> padding_2;
  76. };
  77. static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
  78. enum class State : u32 {
  79. NonInitialized = 0,
  80. Initialized = 1,
  81. };
  82. enum class DeviceState : u32 {
  83. Initialized = 0,
  84. SearchingForTag = 1,
  85. TagFound = 2,
  86. TagRemoved = 3,
  87. TagNearby = 4,
  88. Unknown5 = 5,
  89. Finalized = 6
  90. };
  91. struct CommonInfo {
  92. u16_be last_write_year;
  93. u8 last_write_month;
  94. u8 last_write_day;
  95. u16_be write_counter;
  96. u16_be version;
  97. u32_be application_area_size;
  98. INSERT_PADDING_BYTES(0x34);
  99. };
  100. static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
  101. void Initialize(Kernel::HLERequestContext& ctx) {
  102. LOG_DEBUG(Service_NFC, "called");
  103. IPC::ResponseBuilder rb{ctx, 2, 0};
  104. rb.Push(RESULT_SUCCESS);
  105. state = State::Initialized;
  106. }
  107. void GetState(Kernel::HLERequestContext& ctx) {
  108. LOG_DEBUG(Service_NFC, "called");
  109. IPC::ResponseBuilder rb{ctx, 3, 0};
  110. rb.Push(RESULT_SUCCESS);
  111. rb.PushRaw<u32>(static_cast<u32>(state));
  112. }
  113. void ListDevices(Kernel::HLERequestContext& ctx) {
  114. IPC::RequestParser rp{ctx};
  115. const u32 array_size = rp.Pop<u32>();
  116. LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
  117. ctx.WriteBuffer(device_handle);
  118. IPC::ResponseBuilder rb{ctx, 3};
  119. rb.Push(RESULT_SUCCESS);
  120. rb.Push<u32>(1);
  121. }
  122. void GetNpadId(Kernel::HLERequestContext& ctx) {
  123. IPC::RequestParser rp{ctx};
  124. const u64 dev_handle = rp.Pop<u64>();
  125. LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
  126. IPC::ResponseBuilder rb{ctx, 3};
  127. rb.Push(RESULT_SUCCESS);
  128. rb.Push<u32>(npad_id);
  129. }
  130. void AttachActivateEvent(Kernel::HLERequestContext& ctx) {
  131. IPC::RequestParser rp{ctx};
  132. const u64 dev_handle = rp.Pop<u64>();
  133. LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
  134. IPC::ResponseBuilder rb{ctx, 2, 1};
  135. rb.Push(RESULT_SUCCESS);
  136. rb.PushCopyObjects(nfp_interface.GetNFCEvent());
  137. has_attached_handle = true;
  138. }
  139. void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
  140. IPC::RequestParser rp{ctx};
  141. const u64 dev_handle = rp.Pop<u64>();
  142. LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
  143. IPC::ResponseBuilder rb{ctx, 2, 1};
  144. rb.Push(RESULT_SUCCESS);
  145. rb.PushCopyObjects(deactivate_event->GetReadableEvent());
  146. }
  147. void StopDetection(Kernel::HLERequestContext& ctx) {
  148. LOG_DEBUG(Service_NFP, "called");
  149. switch (device_state) {
  150. case DeviceState::TagFound:
  151. case DeviceState::TagNearby:
  152. deactivate_event->GetWritableEvent()->Signal();
  153. device_state = DeviceState::Initialized;
  154. break;
  155. case DeviceState::SearchingForTag:
  156. case DeviceState::TagRemoved:
  157. device_state = DeviceState::Initialized;
  158. break;
  159. default:
  160. break;
  161. }
  162. IPC::ResponseBuilder rb{ctx, 2};
  163. rb.Push(RESULT_SUCCESS);
  164. }
  165. void GetDeviceState(Kernel::HLERequestContext& ctx) {
  166. LOG_DEBUG(Service_NFP, "called");
  167. IPC::ResponseBuilder rb{ctx, 3};
  168. rb.Push(RESULT_SUCCESS);
  169. rb.Push<u32>(static_cast<u32>(device_state));
  170. }
  171. void StartDetection(Kernel::HLERequestContext& ctx) {
  172. LOG_DEBUG(Service_NFP, "called");
  173. if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
  174. device_state = DeviceState::SearchingForTag;
  175. }
  176. IPC::ResponseBuilder rb{ctx, 2};
  177. rb.Push(RESULT_SUCCESS);
  178. }
  179. void GetTagInfo(Kernel::HLERequestContext& ctx) {
  180. LOG_DEBUG(Service_NFP, "called");
  181. IPC::ResponseBuilder rb{ctx, 2};
  182. const auto& amiibo = nfp_interface.GetAmiiboBuffer();
  183. const TagInfo tag_info{
  184. .uuid = amiibo.uuid,
  185. .uuid_length = static_cast<u8>(amiibo.uuid.size()),
  186. .padding_1 = {},
  187. .protocol = 1, // TODO(ogniK): Figure out actual values
  188. .tag_type = 2,
  189. .padding_2 = {},
  190. };
  191. ctx.WriteBuffer(tag_info);
  192. rb.Push(RESULT_SUCCESS);
  193. }
  194. void Mount(Kernel::HLERequestContext& ctx) {
  195. LOG_DEBUG(Service_NFP, "called");
  196. device_state = DeviceState::TagNearby;
  197. IPC::ResponseBuilder rb{ctx, 2};
  198. rb.Push(RESULT_SUCCESS);
  199. }
  200. void GetModelInfo(Kernel::HLERequestContext& ctx) {
  201. LOG_DEBUG(Service_NFP, "called");
  202. IPC::ResponseBuilder rb{ctx, 2};
  203. const auto& amiibo = nfp_interface.GetAmiiboBuffer();
  204. ctx.WriteBuffer(amiibo.model_info);
  205. rb.Push(RESULT_SUCCESS);
  206. }
  207. void Unmount(Kernel::HLERequestContext& ctx) {
  208. LOG_DEBUG(Service_NFP, "called");
  209. device_state = DeviceState::TagFound;
  210. IPC::ResponseBuilder rb{ctx, 2};
  211. rb.Push(RESULT_SUCCESS);
  212. }
  213. void Finalize(Kernel::HLERequestContext& ctx) {
  214. LOG_DEBUG(Service_NFP, "called");
  215. device_state = DeviceState::Finalized;
  216. IPC::ResponseBuilder rb{ctx, 2};
  217. rb.Push(RESULT_SUCCESS);
  218. }
  219. void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
  220. LOG_WARNING(Service_NFP, "(STUBBED) called");
  221. IPC::ResponseBuilder rb{ctx, 2, 1};
  222. rb.Push(RESULT_SUCCESS);
  223. rb.PushCopyObjects(availability_change_event->GetReadableEvent());
  224. }
  225. void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
  226. LOG_WARNING(Service_NFP, "(STUBBED) called");
  227. // TODO(ogniK): Pull Mii and owner data from amiibo
  228. IPC::ResponseBuilder rb{ctx, 2};
  229. rb.Push(RESULT_SUCCESS);
  230. }
  231. void GetCommonInfo(Kernel::HLERequestContext& ctx) {
  232. LOG_WARNING(Service_NFP, "(STUBBED) called");
  233. // TODO(ogniK): Pull common information from amiibo
  234. CommonInfo common_info{};
  235. common_info.application_area_size = 0;
  236. ctx.WriteBuffer(common_info);
  237. IPC::ResponseBuilder rb{ctx, 2};
  238. rb.Push(RESULT_SUCCESS);
  239. }
  240. void OpenApplicationArea(Kernel::HLERequestContext& ctx) {
  241. LOG_WARNING(Service_NFP, "(STUBBED) called");
  242. IPC::ResponseBuilder rb{ctx, 2};
  243. rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA);
  244. }
  245. void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
  246. LOG_WARNING(Service_NFP, "(STUBBED) called");
  247. // We don't need to worry about this since we can just open the file
  248. IPC::ResponseBuilder rb{ctx, 3};
  249. rb.Push(RESULT_SUCCESS);
  250. rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
  251. }
  252. void GetApplicationArea(Kernel::HLERequestContext& ctx) {
  253. LOG_WARNING(Service_NFP, "(STUBBED) called");
  254. // TODO(ogniK): Pull application area from amiibo
  255. IPC::ResponseBuilder rb{ctx, 3};
  256. rb.Push(RESULT_SUCCESS);
  257. rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub
  258. }
  259. bool has_attached_handle{};
  260. const u64 device_handle{0}; // Npad device 1
  261. const u32 npad_id{0}; // Player 1 controller
  262. State state{State::NonInitialized};
  263. DeviceState device_state{DeviceState::Initialized};
  264. std::shared_ptr<Kernel::KEvent> deactivate_event;
  265. std::shared_ptr<Kernel::KEvent> availability_change_event;
  266. const Module::Interface& nfp_interface;
  267. };
  268. void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
  269. LOG_DEBUG(Service_NFP, "called");
  270. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  271. rb.Push(RESULT_SUCCESS);
  272. rb.PushIpcInterface<IUser>(*this, system);
  273. }
  274. bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
  275. std::lock_guard lock{HLE::g_hle_lock};
  276. if (buffer.size() < sizeof(AmiiboFile)) {
  277. return false;
  278. }
  279. std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
  280. nfc_tag_load->GetWritableEvent()->Signal();
  281. return true;
  282. }
  283. Kernel::KReadableEvent* Module::Interface::GetNFCEvent() const {
  284. return nfc_tag_load->GetReadableEvent();
  285. }
  286. const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
  287. return amiibo;
  288. }
  289. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
  290. auto module = std::make_shared<Module>();
  291. std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
  292. }
  293. } // namespace Service::NFP