IUser.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. using Ryujinx.Common.Logging;
  2. using Ryujinx.HLE.Exceptions;
  3. using Ryujinx.HLE.HOS.Ipc;
  4. using Ryujinx.HLE.HOS.Kernel.Common;
  5. using Ryujinx.HLE.HOS.Kernel.Threading;
  6. using Ryujinx.HLE.HOS.Services.Hid;
  7. using System;
  8. using System.Collections.Generic;
  9. namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
  10. {
  11. class IUser : IpcService
  12. {
  13. private State _state = State.NonInitialized;
  14. private KEvent _availabilityChangeEvent;
  15. private int _availabilityChangeEventHandle = 0;
  16. private List<Device> _devices = new List<Device>();
  17. private Dictionary<int, ServiceProcessRequest> _commands;
  18. public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
  19. public IUser()
  20. {
  21. _commands = new Dictionary<int, ServiceProcessRequest>
  22. {
  23. { 0, Initialize },
  24. { 1, Finalize },
  25. { 2, ListDevices },
  26. { 3, StartDetection },
  27. { 4, StopDetection },
  28. { 5, Mount },
  29. { 6, Unmount },
  30. { 7, OpenApplicationArea },
  31. { 8, GetApplicationArea },
  32. { 9, SetApplicationArea },
  33. { 10, Flush },
  34. { 11, Restore },
  35. { 12, CreateApplicationArea },
  36. { 13, GetTagInfo },
  37. { 14, GetRegisterInfo },
  38. { 15, GetCommonInfo },
  39. { 16, GetModelInfo },
  40. { 17, AttachActivateEvent },
  41. { 18, AttachDeactivateEvent },
  42. { 19, GetState },
  43. { 20, GetDeviceState },
  44. { 21, GetNpadId },
  45. { 22, GetApplicationAreaSize },
  46. { 23, AttachAvailabilityChangeEvent }, // 3.0.0+
  47. { 24, RecreateApplicationArea }, // 3.0.0+
  48. };
  49. }
  50. // Initialize(u64, u64, pid, buffer<unknown, 5>)
  51. public long Initialize(ServiceCtx context)
  52. {
  53. long appletResourceUserId = context.RequestData.ReadInt64();
  54. long mcuVersionData = context.RequestData.ReadInt64();
  55. long inputPosition = context.Request.SendBuff[0].Position;
  56. long inputSize = context.Request.SendBuff[0].Size;
  57. byte[] unknownBuffer = context.Memory.ReadBytes(inputPosition, inputSize);
  58. // NOTE: appletResourceUserId, mcuVersionData and the buffer are stored inside an internal struct.
  59. // The buffer seems to contains entries with a size of 0x40 bytes each.
  60. // Sadly, this internal struct doesn't seems to be used in retail.
  61. // TODO: Add an instance of nn::nfc::server::Manager when it will be implemented.
  62. // Add an instance of nn::nfc::server::SaveData when it will be implemented.
  63. // TODO: When we will be able to add multiple controllers add one entry by controller here.
  64. Device device1 = new Device
  65. {
  66. NpadIdType = NpadIdType.Player1,
  67. Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
  68. State = DeviceState.Initialized
  69. };
  70. _devices.Add(device1);
  71. _state = State.Initialized;
  72. return 0;
  73. }
  74. // Finalize()
  75. public long Finalize(ServiceCtx context)
  76. {
  77. // TODO: Call StopDetection() and Unmount() when they will be implemented.
  78. // Remove the instance of nn::nfc::server::Manager when it will be implemented.
  79. // Remove the instance of nn::nfc::server::SaveData when it will be implemented.
  80. _devices.Clear();
  81. _state = State.NonInitialized;
  82. return 0;
  83. }
  84. // ListDevices() -> (u32, buffer<unknown, 0xa>)
  85. public long ListDevices(ServiceCtx context)
  86. {
  87. if (context.Request.RecvListBuff.Count == 0)
  88. {
  89. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DevicesBufferIsNull);
  90. }
  91. long outputPosition = context.Request.RecvListBuff[0].Position;
  92. long outputSize = context.Request.RecvListBuff[0].Size;
  93. if (_devices.Count == 0)
  94. {
  95. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
  96. }
  97. for (int i = 0; i < _devices.Count; i++)
  98. {
  99. context.Memory.WriteUInt32(outputPosition + (i * sizeof(long)), (uint)_devices[i].Handle);
  100. }
  101. context.ResponseData.Write(_devices.Count);
  102. return 0;
  103. }
  104. // StartDetection(bytes<8, 4>)
  105. public long StartDetection(ServiceCtx context)
  106. {
  107. throw new ServiceNotImplementedException(context);
  108. }
  109. // StopDetection(bytes<8, 4>)
  110. public long StopDetection(ServiceCtx context)
  111. {
  112. throw new ServiceNotImplementedException(context);
  113. }
  114. // Mount(bytes<8, 4>, u32, u32)
  115. public long Mount(ServiceCtx context)
  116. {
  117. throw new ServiceNotImplementedException(context);
  118. }
  119. // Unmount(bytes<8, 4>)
  120. public long Unmount(ServiceCtx context)
  121. {
  122. throw new ServiceNotImplementedException(context);
  123. }
  124. // OpenApplicationArea(bytes<8, 4>, u32)
  125. public long OpenApplicationArea(ServiceCtx context)
  126. {
  127. throw new ServiceNotImplementedException(context);
  128. }
  129. // GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
  130. public long GetApplicationArea(ServiceCtx context)
  131. {
  132. throw new ServiceNotImplementedException(context);
  133. }
  134. // SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
  135. public long SetApplicationArea(ServiceCtx context)
  136. {
  137. throw new ServiceNotImplementedException(context);
  138. }
  139. // Flush(bytes<8, 4>)
  140. public long Flush(ServiceCtx context)
  141. {
  142. throw new ServiceNotImplementedException(context);
  143. }
  144. // Restore(bytes<8, 4>)
  145. public long Restore(ServiceCtx context)
  146. {
  147. throw new ServiceNotImplementedException(context);
  148. }
  149. // CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
  150. public long CreateApplicationArea(ServiceCtx context)
  151. {
  152. throw new ServiceNotImplementedException(context);
  153. }
  154. // GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
  155. public long GetTagInfo(ServiceCtx context)
  156. {
  157. throw new ServiceNotImplementedException(context);
  158. }
  159. // GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
  160. public long GetRegisterInfo(ServiceCtx context)
  161. {
  162. throw new ServiceNotImplementedException(context);
  163. }
  164. // GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
  165. public long GetCommonInfo(ServiceCtx context)
  166. {
  167. throw new ServiceNotImplementedException(context);
  168. }
  169. // GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
  170. public long GetModelInfo(ServiceCtx context)
  171. {
  172. throw new ServiceNotImplementedException(context);
  173. }
  174. // AttachActivateEvent(bytes<8, 4>) -> handle<copy>
  175. public long AttachActivateEvent(ServiceCtx context)
  176. {
  177. uint deviceHandle = context.RequestData.ReadUInt32();
  178. for (int i = 0; i < _devices.Count; i++)
  179. {
  180. if ((uint)_devices[i].Handle == deviceHandle)
  181. {
  182. if (_devices[i].ActivateEventHandle == 0)
  183. {
  184. _devices[i].ActivateEvent = new KEvent(context.Device.System);
  185. if (context.Process.HandleTable.GenerateHandle(_devices[i].ActivateEvent.ReadableEvent, out _devices[i].ActivateEventHandle) != KernelResult.Success)
  186. {
  187. throw new InvalidOperationException("Out of handles!");
  188. }
  189. }
  190. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].ActivateEventHandle);
  191. return 0;
  192. }
  193. }
  194. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
  195. }
  196. // AttachDeactivateEvent(bytes<8, 4>) -> handle<copy>
  197. public long AttachDeactivateEvent(ServiceCtx context)
  198. {
  199. uint deviceHandle = context.RequestData.ReadUInt32();
  200. for (int i = 0; i < _devices.Count; i++)
  201. {
  202. if ((uint)_devices[i].Handle == deviceHandle)
  203. {
  204. if (_devices[i].DeactivateEventHandle == 0)
  205. {
  206. _devices[i].DeactivateEvent = new KEvent(context.Device.System);
  207. if (context.Process.HandleTable.GenerateHandle(_devices[i].DeactivateEvent.ReadableEvent, out _devices[i].DeactivateEventHandle) != KernelResult.Success)
  208. {
  209. throw new InvalidOperationException("Out of handles!");
  210. }
  211. }
  212. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].DeactivateEventHandle);
  213. return 0;
  214. }
  215. }
  216. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
  217. }
  218. // GetState() -> u32
  219. public long GetState(ServiceCtx context)
  220. {
  221. context.ResponseData.Write((int)_state);
  222. return 0;
  223. }
  224. // GetDeviceState(bytes<8, 4>) -> u32
  225. public long GetDeviceState(ServiceCtx context)
  226. {
  227. uint deviceHandle = context.RequestData.ReadUInt32();
  228. for (int i = 0; i < _devices.Count; i++)
  229. {
  230. if ((uint)_devices[i].Handle == deviceHandle)
  231. {
  232. context.ResponseData.Write((uint)_devices[i].State);
  233. return 0;
  234. }
  235. }
  236. context.ResponseData.Write((uint)DeviceState.Unavailable);
  237. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
  238. }
  239. // GetNpadId(bytes<8, 4>) -> u32
  240. public long GetNpadId(ServiceCtx context)
  241. {
  242. uint deviceHandle = context.RequestData.ReadUInt32();
  243. for (int i = 0; i < _devices.Count; i++)
  244. {
  245. if ((uint)_devices[i].Handle == deviceHandle)
  246. {
  247. context.ResponseData.Write((uint)HidUtils.GetNpadIdTypeFromIndex(_devices[i].Handle));
  248. return 0;
  249. }
  250. }
  251. return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
  252. }
  253. // GetApplicationAreaSize(bytes<8, 4>) -> u32
  254. public long GetApplicationAreaSize(ServiceCtx context)
  255. {
  256. throw new ServiceNotImplementedException(context);
  257. }
  258. // AttachAvailabilityChangeEvent() -> handle<copy>
  259. public long AttachAvailabilityChangeEvent(ServiceCtx context)
  260. {
  261. if (_availabilityChangeEventHandle == 0)
  262. {
  263. _availabilityChangeEvent = new KEvent(context.Device.System);
  264. if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out _availabilityChangeEventHandle) != KernelResult.Success)
  265. {
  266. throw new InvalidOperationException("Out of handles!");
  267. }
  268. }
  269. context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_availabilityChangeEventHandle);
  270. return 0;
  271. }
  272. // RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
  273. public long RecreateApplicationArea(ServiceCtx context)
  274. {
  275. throw new ServiceNotImplementedException(context);
  276. }
  277. }
  278. }