aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs19
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs20
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs346
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUserManager.cs (renamed from Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs)4
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpError.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs (renamed from Ryujinx.HLE/HOS/Services/Nfp/State.cs)2
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs7
-rw-r--r--Ryujinx.HLE/HOS/Services/Nfp/IUser.cs125
-rw-r--r--Ryujinx.HLE/HOS/Services/ServiceFactory.cs2
10 files changed, 410 insertions, 136 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs b/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
index 64252ce8..051be7a8 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidUtils.cs
@@ -23,5 +23,24 @@ namespace Ryujinx.HLE.HOS.Services.Hid
default: throw new ArgumentOutOfRangeException(nameof(npadIdType));
}
}
+
+ public static NpadIdType GetNpadIdTypeFromIndex(HidControllerId index)
+ {
+ switch (index)
+ {
+ case HidControllerId.ControllerPlayer1: return NpadIdType.Player1;
+ case HidControllerId.ControllerPlayer2: return NpadIdType.Player2;
+ case HidControllerId.ControllerPlayer3: return NpadIdType.Player3;
+ case HidControllerId.ControllerPlayer4: return NpadIdType.Player4;
+ case HidControllerId.ControllerPlayer5: return NpadIdType.Player5;
+ case HidControllerId.ControllerPlayer6: return NpadIdType.Player6;
+ case HidControllerId.ControllerPlayer7: return NpadIdType.Player7;
+ case HidControllerId.ControllerPlayer8: return NpadIdType.Player8;
+ case HidControllerId.ControllerHandheld: return NpadIdType.Handheld;
+ case HidControllerId.ControllerUnknown: return NpadIdType.Unknown;
+
+ default: throw new ArgumentOutOfRangeException(nameof(index));
+ }
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs
new file mode 100644
index 00000000..a1f58dae
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/Device.cs
@@ -0,0 +1,20 @@
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Hid;
+using Ryujinx.HLE.Input;
+
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
+{
+ class Device
+ {
+ public KEvent ActivateEvent;
+ public int ActivateEventHandle;
+
+ public KEvent DeactivateEvent;
+ public int DeactivateEventHandle;
+
+ public DeviceState State = DeviceState.Unavailable;
+
+ public HidControllerId Handle;
+ public NpadIdType NpadIdType;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs
new file mode 100644
index 00000000..09cff5f8
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/DeviceState.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
+{
+ enum DeviceState
+ {
+ Initialized = 0,
+ SearchingForTag = 1,
+ TagFound = 2,
+ TagRemoved = 3,
+ TagMounted = 4,
+ Unavailable = 5,
+ Finalized = 6
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs
new file mode 100644
index 00000000..d4c97779
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUser.cs
@@ -0,0 +1,346 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE.Exceptions;
+using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
+using Ryujinx.HLE.HOS.Services.Hid;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
+{
+ class IUser : IpcService
+ {
+ private State _state = State.NonInitialized;
+
+ private KEvent _availabilityChangeEvent;
+ private int _availabilityChangeEventHandle = 0;
+
+ private List<Device> _devices = new List<Device>();
+
+ private Dictionary<int, ServiceProcessRequest> _commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
+
+ public IUser()
+ {
+ _commands = new Dictionary<int, ServiceProcessRequest>
+ {
+ { 0, Initialize },
+ { 1, Finalize },
+ { 2, ListDevices },
+ { 3, StartDetection },
+ { 4, StopDetection },
+ { 5, Mount },
+ { 6, Unmount },
+ { 7, OpenApplicationArea },
+ { 8, GetApplicationArea },
+ { 9, SetApplicationArea },
+ { 10, Flush },
+ { 11, Restore },
+ { 12, CreateApplicationArea },
+ { 13, GetTagInfo },
+ { 14, GetRegisterInfo },
+ { 15, GetCommonInfo },
+ { 16, GetModelInfo },
+ { 17, AttachActivateEvent },
+ { 18, AttachDeactivateEvent },
+ { 19, GetState },
+ { 20, GetDeviceState },
+ { 21, GetNpadId },
+ { 22, GetApplicationAreaSize },
+ { 23, AttachAvailabilityChangeEvent }, // 3.0.0+
+ { 24, RecreateApplicationArea }, // 3.0.0+
+ };
+ }
+
+ // Initialize(u64, u64, pid, buffer<unknown, 5>)
+ public long Initialize(ServiceCtx context)
+ {
+ long appletResourceUserId = context.RequestData.ReadInt64();
+ long mcuVersionData = context.RequestData.ReadInt64();
+
+ long inputPosition = context.Request.SendBuff[0].Position;
+ long inputSize = context.Request.SendBuff[0].Size;
+
+ byte[] unknownBuffer = context.Memory.ReadBytes(inputPosition, inputSize);
+
+ // NOTE: appletResourceUserId, mcuVersionData and the buffer are stored inside an internal struct.
+ // The buffer seems to contains entries with a size of 0x40 bytes each.
+ // Sadly, this internal struct doesn't seems to be used in retail.
+
+ // TODO: Add an instance of nn::nfc::server::Manager when it will be implemented.
+ // Add an instance of nn::nfc::server::SaveData when it will be implemented.
+
+ // TODO: When we will be able to add multiple controllers add one entry by controller here.
+ Device device1 = new Device
+ {
+ NpadIdType = NpadIdType.Player1,
+ Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
+ State = DeviceState.Initialized
+ };
+
+ _devices.Add(device1);
+
+ _state = State.Initialized;
+
+ return 0;
+ }
+
+ // Finalize()
+ public long Finalize(ServiceCtx context)
+ {
+ // TODO: Call StopDetection() and Unmount() when they will be implemented.
+ // Remove the instance of nn::nfc::server::Manager when it will be implemented.
+ // Remove the instance of nn::nfc::server::SaveData when it will be implemented.
+
+ _devices.Clear();
+
+ _state = State.NonInitialized;
+
+ return 0;
+ }
+
+ // ListDevices() -> (u32, buffer<unknown, 0xa>)
+ public long ListDevices(ServiceCtx context)
+ {
+ if (context.Request.RecvListBuff.Count == 0)
+ {
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DevicesBufferIsNull);
+ }
+
+ long outputPosition = context.Request.RecvListBuff[0].Position;
+ long outputSize = context.Request.RecvListBuff[0].Size;
+
+ if (_devices.Count == 0)
+ {
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
+ }
+
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ context.Memory.WriteUInt32(outputPosition + (i * sizeof(long)), (uint)_devices[i].Handle);
+ }
+
+ context.ResponseData.Write(_devices.Count);
+
+ return 0;
+ }
+
+ // StartDetection(bytes<8, 4>)
+ public long StartDetection(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // StopDetection(bytes<8, 4>)
+ public long StopDetection(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // Mount(bytes<8, 4>, u32, u32)
+ public long Mount(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // Unmount(bytes<8, 4>)
+ public long Unmount(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // OpenApplicationArea(bytes<8, 4>, u32)
+ public long OpenApplicationArea(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // GetApplicationArea(bytes<8, 4>) -> (u32, buffer<unknown, 6>)
+ public long GetApplicationArea(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // SetApplicationArea(bytes<8, 4>, buffer<unknown, 5>)
+ public long SetApplicationArea(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // Flush(bytes<8, 4>)
+ public long Flush(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // Restore(bytes<8, 4>)
+ public long Restore(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // CreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
+ public long CreateApplicationArea(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // GetTagInfo(bytes<8, 4>) -> buffer<unknown<0x58>, 0x1a>
+ public long GetTagInfo(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // GetRegisterInfo(bytes<8, 4>) -> buffer<unknown<0x100>, 0x1a>
+ public long GetRegisterInfo(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // GetCommonInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
+ public long GetCommonInfo(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // GetModelInfo(bytes<8, 4>) -> buffer<unknown<0x40>, 0x1a>
+ public long GetModelInfo(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // AttachActivateEvent(bytes<8, 4>) -> handle<copy>
+ public long AttachActivateEvent(ServiceCtx context)
+ {
+ uint deviceHandle = context.RequestData.ReadUInt32();
+
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ if ((uint)_devices[i].Handle == deviceHandle)
+ {
+ if (_devices[i].ActivateEventHandle == 0)
+ {
+ _devices[i].ActivateEvent = new KEvent(context.Device.System);
+
+ if (context.Process.HandleTable.GenerateHandle(_devices[i].ActivateEvent.ReadableEvent, out _devices[i].ActivateEventHandle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].ActivateEventHandle);
+
+ return 0;
+ }
+ }
+
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
+ }
+
+ // AttachDeactivateEvent(bytes<8, 4>) -> handle<copy>
+ public long AttachDeactivateEvent(ServiceCtx context)
+ {
+ uint deviceHandle = context.RequestData.ReadUInt32();
+
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ if ((uint)_devices[i].Handle == deviceHandle)
+ {
+ if (_devices[i].DeactivateEventHandle == 0)
+ {
+ _devices[i].DeactivateEvent = new KEvent(context.Device.System);
+
+ if (context.Process.HandleTable.GenerateHandle(_devices[i].DeactivateEvent.ReadableEvent, out _devices[i].DeactivateEventHandle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_devices[i].DeactivateEventHandle);
+
+ return 0;
+ }
+ }
+
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
+ }
+
+ // GetState() -> u32
+ public long GetState(ServiceCtx context)
+ {
+ context.ResponseData.Write((int)_state);
+
+ return 0;
+ }
+
+ // GetDeviceState(bytes<8, 4>) -> u32
+ public long GetDeviceState(ServiceCtx context)
+ {
+ uint deviceHandle = context.RequestData.ReadUInt32();
+
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ if ((uint)_devices[i].Handle == deviceHandle)
+ {
+ context.ResponseData.Write((uint)_devices[i].State);
+
+ return 0;
+ }
+ }
+
+ context.ResponseData.Write((uint)DeviceState.Unavailable);
+
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
+ }
+
+ // GetNpadId(bytes<8, 4>) -> u32
+ public long GetNpadId(ServiceCtx context)
+ {
+ uint deviceHandle = context.RequestData.ReadUInt32();
+
+ for (int i = 0; i < _devices.Count; i++)
+ {
+ if ((uint)_devices[i].Handle == deviceHandle)
+ {
+ context.ResponseData.Write((uint)HidUtils.GetNpadIdTypeFromIndex(_devices[i].Handle));
+
+ return 0;
+ }
+ }
+
+ return ErrorCode.MakeError(ErrorModule.Nfp, NfpError.DeviceNotFound);
+ }
+
+ // GetApplicationAreaSize(bytes<8, 4>) -> u32
+ public long GetApplicationAreaSize(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+
+ // AttachAvailabilityChangeEvent() -> handle<copy>
+ public long AttachAvailabilityChangeEvent(ServiceCtx context)
+ {
+ if (_availabilityChangeEventHandle == 0)
+ {
+ _availabilityChangeEvent = new KEvent(context.Device.System);
+
+ if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out _availabilityChangeEventHandle) != KernelResult.Success)
+ {
+ throw new InvalidOperationException("Out of handles!");
+ }
+ }
+
+ context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_availabilityChangeEventHandle);
+
+ return 0;
+ }
+
+ // RecreateApplicationArea(bytes<8, 4>, u32, buffer<unknown, 5>)
+ public long RecreateApplicationArea(ServiceCtx context)
+ {
+ throw new ServiceNotImplementedException(context);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUserManager.cs
index 1bf93746..dad1026e 100644
--- a/Ryujinx.HLE/HOS/Services/Nfp/IUserManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/IUserManager.cs
@@ -1,7 +1,7 @@
using Ryujinx.HLE.HOS.Ipc;
using System.Collections.Generic;
-namespace Ryujinx.HLE.HOS.Services.Nfp
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
class IUserManager : IpcService
{
@@ -19,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfp
public long GetUserInterface(ServiceCtx context)
{
- MakeObject(context, new IUser(context.Device.System));
+ MakeObject(context, new IUser());
return 0;
}
diff --git a/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpError.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpError.cs
new file mode 100644
index 00000000..f9bfecc0
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/NfpError.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
+{
+ static class NfpError
+ {
+ public const int DeviceNotFound = 64;
+ public const int DevicesBufferIsNull = 65;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfp/State.cs b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs
index 0b4b3c1b..166e5d7e 100644
--- a/Ryujinx.HLE/HOS/Services/Nfp/State.cs
+++ b/Ryujinx.HLE/HOS/Services/Nfc/Nfp/State.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.HLE.HOS.Services.Nfp
+namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
enum State
{
diff --git a/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs b/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs
deleted file mode 100644
index 04527893..00000000
--- a/Ryujinx.HLE/HOS/Services/Nfp/DeviceState.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.Nfp
-{
- enum DeviceState
- {
- Initialized = 0
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs b/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs
deleted file mode 100644
index 66bff1a7..00000000
--- a/Ryujinx.HLE/HOS/Services/Nfp/IUser.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE.HOS.Ipc;
-using Ryujinx.HLE.HOS.Kernel.Common;
-using Ryujinx.HLE.HOS.Kernel.Threading;
-using Ryujinx.HLE.Input;
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.HOS.Services.Nfp
-{
- class IUser : IpcService
- {
- private Dictionary<int, ServiceProcessRequest> _commands;
-
- public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
-
- private const HidControllerId NpadId = HidControllerId.ControllerPlayer1;
-
- private State _state = State.NonInitialized;
-
- private DeviceState _deviceState = DeviceState.Initialized;
-
- private KEvent _activateEvent;
-
- private KEvent _deactivateEvent;
-
- private KEvent _availabilityChangeEvent;
-
- public IUser(Horizon system)
- {
- _commands = new Dictionary<int, ServiceProcessRequest>
- {
- { 0, Initialize },
- { 17, AttachActivateEvent },
- { 18, AttachDeactivateEvent },
- { 19, GetState },
- { 20, GetDeviceState },
- { 21, GetNpadId },
- { 23, AttachAvailabilityChangeEvent }
- };
-
- _activateEvent = new KEvent(system);
- _deactivateEvent = new KEvent(system);
- _availabilityChangeEvent = new KEvent(system);
- }
-
- public long Initialize(ServiceCtx context)
- {
- Logger.PrintStub(LogClass.ServiceNfp);
-
- _state = State.Initialized;
-
- return 0;
- }
-
- public long AttachActivateEvent(ServiceCtx context)
- {
- Logger.PrintStub(LogClass.ServiceNfp);
-
- if (context.Process.HandleTable.GenerateHandle(_activateEvent.ReadableEvent, out int handle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
-
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
-
- return 0;
- }
-
- public long AttachDeactivateEvent(ServiceCtx context)
- {
- Logger.PrintStub(LogClass.ServiceNfp);
-
- if (context.Process.HandleTable.GenerateHandle(_deactivateEvent.ReadableEvent, out int handle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
-
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
-
- return 0;
- }
-
- public long GetState(ServiceCtx context)
- {
- context.ResponseData.Write((int)_state);
-
- Logger.PrintStub(LogClass.ServiceNfp);
-
- return 0;
- }
-
- public long GetDeviceState(ServiceCtx context)
- {
- context.ResponseData.Write((int)_deviceState);
-
- Logger.PrintStub(LogClass.ServiceNfp);
-
- return 0;
- }
-
- public long GetNpadId(ServiceCtx context)
- {
- context.ResponseData.Write((int)NpadId);
-
- Logger.PrintStub(LogClass.ServiceNfp);
-
- return 0;
- }
-
- public long AttachAvailabilityChangeEvent(ServiceCtx context)
- {
- Logger.PrintStub(LogClass.ServiceNfp);
-
- if (context.Process.HandleTable.GenerateHandle(_availabilityChangeEvent.ReadableEvent, out int handle) != KernelResult.Success)
- {
- throw new InvalidOperationException("Out of handles!");
- }
-
- context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
-
- return 0;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
index 63488d21..7cd943e0 100644
--- a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
+++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs
@@ -13,7 +13,7 @@ using Ryujinx.HLE.HOS.Services.Ldr;
using Ryujinx.HLE.HOS.Services.Lm;
using Ryujinx.HLE.HOS.Services.Mm;
using Ryujinx.HLE.HOS.Services.Ncm;
-using Ryujinx.HLE.HOS.Services.Nfp;
+using Ryujinx.HLE.HOS.Services.Nfc.Nfp;
using Ryujinx.HLE.HOS.Services.Ns;
using Ryujinx.HLE.HOS.Services.Nv;
using Ryujinx.HLE.HOS.Services.Pctl;