nfc_user.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/logging/log.h"
  4. #include "core/core.h"
  5. #include "core/hid/hid_types.h"
  6. #include "core/hle/kernel/k_event.h"
  7. #include "core/hle/service/ipc_helpers.h"
  8. #include "core/hle/service/nfc/nfc_device.h"
  9. #include "core/hle/service/nfc/nfc_result.h"
  10. #include "core/hle/service/nfc/nfc_user.h"
  11. #include "core/hle/service/time/clock_types.h"
  12. namespace Service::NFC {
  13. IUser::IUser(Core::System& system_)
  14. : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
  15. static const FunctionInfo functions[] = {
  16. {0, &IUser::Initialize, "InitializeOld"},
  17. {1, &IUser::Finalize, "FinalizeOld"},
  18. {2, &IUser::GetState, "GetStateOld"},
  19. {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
  20. {400, &IUser::Initialize, "Initialize"},
  21. {401, &IUser::Finalize, "Finalize"},
  22. {402, &IUser::GetState, "GetState"},
  23. {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
  24. {404, &IUser::ListDevices, "ListDevices"},
  25. {405, &IUser::GetDeviceState, "GetDeviceState"},
  26. {406, &IUser::GetNpadId, "GetNpadId"},
  27. {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
  28. {408, &IUser::StartDetection, "StartDetection"},
  29. {409, &IUser::StopDetection, "StopDetection"},
  30. {410, &IUser::GetTagInfo, "GetTagInfo"},
  31. {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
  32. {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
  33. {1000, nullptr, "ReadMifare"},
  34. {1001, nullptr, "WriteMifare"},
  35. {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
  36. {1301, nullptr, "KeepPassThroughSession"},
  37. {1302, nullptr, "ReleasePassThroughSession"},
  38. };
  39. RegisterHandlers(functions);
  40. availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
  41. for (u32 device_index = 0; device_index < 10; device_index++) {
  42. devices[device_index] =
  43. std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
  44. service_context, availability_change_event);
  45. }
  46. }
  47. IUser ::~IUser() {
  48. availability_change_event->Close();
  49. }
  50. void IUser::Initialize(HLERequestContext& ctx) {
  51. LOG_INFO(Service_NFC, "called");
  52. state = State::Initialized;
  53. for (auto& device : devices) {
  54. device->Initialize();
  55. }
  56. IPC::ResponseBuilder rb{ctx, 2, 0};
  57. rb.Push(ResultSuccess);
  58. }
  59. void IUser::Finalize(HLERequestContext& ctx) {
  60. LOG_INFO(Service_NFC, "called");
  61. state = State::NonInitialized;
  62. for (auto& device : devices) {
  63. device->Finalize();
  64. }
  65. IPC::ResponseBuilder rb{ctx, 2};
  66. rb.Push(ResultSuccess);
  67. }
  68. void IUser::GetState(HLERequestContext& ctx) {
  69. LOG_DEBUG(Service_NFC, "called");
  70. IPC::ResponseBuilder rb{ctx, 3};
  71. rb.Push(ResultSuccess);
  72. rb.PushEnum(state);
  73. }
  74. void IUser::IsNfcEnabled(HLERequestContext& ctx) {
  75. LOG_DEBUG(Service_NFC, "called");
  76. IPC::ResponseBuilder rb{ctx, 3};
  77. rb.Push(ResultSuccess);
  78. rb.Push(state != State::NonInitialized);
  79. }
  80. void IUser::ListDevices(HLERequestContext& ctx) {
  81. LOG_DEBUG(Service_NFC, "called");
  82. if (state == State::NonInitialized) {
  83. IPC::ResponseBuilder rb{ctx, 2};
  84. rb.Push(NfcDisabled);
  85. return;
  86. }
  87. if (!ctx.CanWriteBuffer()) {
  88. IPC::ResponseBuilder rb{ctx, 2};
  89. rb.Push(InvalidArgument);
  90. return;
  91. }
  92. if (ctx.GetWriteBufferSize() == 0) {
  93. IPC::ResponseBuilder rb{ctx, 2};
  94. rb.Push(InvalidArgument);
  95. return;
  96. }
  97. std::vector<u64> nfp_devices;
  98. const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
  99. for (auto& device : devices) {
  100. if (nfp_devices.size() >= max_allowed_devices) {
  101. continue;
  102. }
  103. if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
  104. nfp_devices.push_back(device->GetHandle());
  105. }
  106. }
  107. if (nfp_devices.empty()) {
  108. IPC::ResponseBuilder rb{ctx, 2};
  109. rb.Push(DeviceNotFound);
  110. return;
  111. }
  112. ctx.WriteBuffer(nfp_devices);
  113. IPC::ResponseBuilder rb{ctx, 3};
  114. rb.Push(ResultSuccess);
  115. rb.Push(static_cast<s32>(nfp_devices.size()));
  116. }
  117. void IUser::GetDeviceState(HLERequestContext& ctx) {
  118. IPC::RequestParser rp{ctx};
  119. const auto device_handle{rp.Pop<u64>()};
  120. LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
  121. auto device = GetNfcDevice(device_handle);
  122. if (!device.has_value()) {
  123. IPC::ResponseBuilder rb{ctx, 2};
  124. rb.Push(DeviceNotFound);
  125. return;
  126. }
  127. IPC::ResponseBuilder rb{ctx, 3};
  128. rb.Push(ResultSuccess);
  129. rb.PushEnum(device.value()->GetCurrentState());
  130. }
  131. void IUser::GetNpadId(HLERequestContext& ctx) {
  132. IPC::RequestParser rp{ctx};
  133. const auto device_handle{rp.Pop<u64>()};
  134. LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
  135. if (state == State::NonInitialized) {
  136. IPC::ResponseBuilder rb{ctx, 2};
  137. rb.Push(NfcDisabled);
  138. return;
  139. }
  140. auto device = GetNfcDevice(device_handle);
  141. if (!device.has_value()) {
  142. IPC::ResponseBuilder rb{ctx, 2};
  143. rb.Push(DeviceNotFound);
  144. return;
  145. }
  146. IPC::ResponseBuilder rb{ctx, 3};
  147. rb.Push(ResultSuccess);
  148. rb.PushEnum(device.value()->GetNpadId());
  149. }
  150. void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
  151. LOG_INFO(Service_NFC, "called");
  152. if (state == State::NonInitialized) {
  153. IPC::ResponseBuilder rb{ctx, 2};
  154. rb.Push(NfcDisabled);
  155. return;
  156. }
  157. IPC::ResponseBuilder rb{ctx, 2, 1};
  158. rb.Push(ResultSuccess);
  159. rb.PushCopyObjects(availability_change_event->GetReadableEvent());
  160. }
  161. void IUser::StartDetection(HLERequestContext& ctx) {
  162. IPC::RequestParser rp{ctx};
  163. const auto device_handle{rp.Pop<u64>()};
  164. const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
  165. LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
  166. if (state == State::NonInitialized) {
  167. IPC::ResponseBuilder rb{ctx, 2};
  168. rb.Push(NfcDisabled);
  169. return;
  170. }
  171. auto device = GetNfcDevice(device_handle);
  172. if (!device.has_value()) {
  173. IPC::ResponseBuilder rb{ctx, 2};
  174. rb.Push(DeviceNotFound);
  175. return;
  176. }
  177. const auto result = device.value()->StartDetection(nfp_protocol);
  178. IPC::ResponseBuilder rb{ctx, 2};
  179. rb.Push(result);
  180. }
  181. void IUser::StopDetection(HLERequestContext& ctx) {
  182. IPC::RequestParser rp{ctx};
  183. const auto device_handle{rp.Pop<u64>()};
  184. LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
  185. if (state == State::NonInitialized) {
  186. IPC::ResponseBuilder rb{ctx, 2};
  187. rb.Push(NfcDisabled);
  188. return;
  189. }
  190. auto device = GetNfcDevice(device_handle);
  191. if (!device.has_value()) {
  192. IPC::ResponseBuilder rb{ctx, 2};
  193. rb.Push(DeviceNotFound);
  194. return;
  195. }
  196. const auto result = device.value()->StopDetection();
  197. IPC::ResponseBuilder rb{ctx, 2};
  198. rb.Push(result);
  199. }
  200. void IUser::GetTagInfo(HLERequestContext& ctx) {
  201. IPC::RequestParser rp{ctx};
  202. const auto device_handle{rp.Pop<u64>()};
  203. LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
  204. if (state == State::NonInitialized) {
  205. IPC::ResponseBuilder rb{ctx, 2};
  206. rb.Push(NfcDisabled);
  207. return;
  208. }
  209. auto device = GetNfcDevice(device_handle);
  210. if (!device.has_value()) {
  211. IPC::ResponseBuilder rb{ctx, 2};
  212. rb.Push(DeviceNotFound);
  213. return;
  214. }
  215. NFP::TagInfo tag_info{};
  216. const auto result = device.value()->GetTagInfo(tag_info, false);
  217. ctx.WriteBuffer(tag_info);
  218. IPC::ResponseBuilder rb{ctx, 2};
  219. rb.Push(result);
  220. }
  221. void IUser::AttachActivateEvent(HLERequestContext& ctx) {
  222. IPC::RequestParser rp{ctx};
  223. const auto device_handle{rp.Pop<u64>()};
  224. LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
  225. if (state == State::NonInitialized) {
  226. IPC::ResponseBuilder rb{ctx, 2};
  227. rb.Push(NfcDisabled);
  228. return;
  229. }
  230. auto device = GetNfcDevice(device_handle);
  231. if (!device.has_value()) {
  232. IPC::ResponseBuilder rb{ctx, 2};
  233. rb.Push(DeviceNotFound);
  234. return;
  235. }
  236. IPC::ResponseBuilder rb{ctx, 2, 1};
  237. rb.Push(ResultSuccess);
  238. rb.PushCopyObjects(device.value()->GetActivateEvent());
  239. }
  240. void IUser::AttachDeactivateEvent(HLERequestContext& ctx) {
  241. IPC::RequestParser rp{ctx};
  242. const auto device_handle{rp.Pop<u64>()};
  243. LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
  244. if (state == State::NonInitialized) {
  245. IPC::ResponseBuilder rb{ctx, 2};
  246. rb.Push(NfcDisabled);
  247. return;
  248. }
  249. auto device = GetNfcDevice(device_handle);
  250. if (!device.has_value()) {
  251. IPC::ResponseBuilder rb{ctx, 2};
  252. rb.Push(DeviceNotFound);
  253. return;
  254. }
  255. IPC::ResponseBuilder rb{ctx, 2, 1};
  256. rb.Push(ResultSuccess);
  257. rb.PushCopyObjects(device.value()->GetDeactivateEvent());
  258. }
  259. void IUser::SendCommandByPassThrough(HLERequestContext& ctx) {
  260. IPC::RequestParser rp{ctx};
  261. const auto device_handle{rp.Pop<u64>()};
  262. const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
  263. const auto command_data{ctx.ReadBuffer()};
  264. LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
  265. device_handle, timeout.ToSeconds(), command_data.size());
  266. if (state == State::NonInitialized) {
  267. IPC::ResponseBuilder rb{ctx, 2};
  268. rb.Push(NfcDisabled);
  269. return;
  270. }
  271. auto device = GetNfcDevice(device_handle);
  272. if (!device.has_value()) {
  273. IPC::ResponseBuilder rb{ctx, 2};
  274. rb.Push(DeviceNotFound);
  275. return;
  276. }
  277. std::vector<u8> out_data(1);
  278. // TODO: Request data from nfc device
  279. ctx.WriteBuffer(out_data);
  280. IPC::ResponseBuilder rb{ctx, 3};
  281. rb.Push(ResultSuccess);
  282. rb.Push(static_cast<u32>(out_data.size()));
  283. }
  284. std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
  285. for (auto& device : devices) {
  286. if (device->GetHandle() == handle) {
  287. return device;
  288. }
  289. }
  290. return std::nullopt;
  291. }
  292. } // namespace Service::NFC