aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE')
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs56
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs10
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs3
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs17
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs145
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs5
-rw-r--r--Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs13
7 files changed, 206 insertions, 43 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
index bbc30172..55f8070a 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs
@@ -1,7 +1,9 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Ryujinx.Common;
+using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Hid.Types;
@@ -20,11 +22,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private ControllerType[] _configuredTypes;
private KEvent[] _styleSetUpdateEvents;
private bool[] _supportedPlayers;
+ private static HidVibrationValue _neutralVibrationValue = new HidVibrationValue
+ {
+ AmplitudeLow = 0f,
+ FrequencyLow = 160f,
+ AmplitudeHigh = 0f,
+ FrequencyHigh = 320f
+ };
internal NpadJoyHoldType JoyHold { get; set; }
internal bool SixAxisActive = false; // TODO: link to hidserver when implemented
internal ControllerType SupportedStyleSets { get; set; }
+ public Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>> RumbleQueues = new Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>>();
+ public Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)> LastVibrationValues = new Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)>();
+
public NpadDevices(Switch device, bool active = true) : base(device, active)
{
_configuredTypes = new ControllerType[MaxControllers];
@@ -596,5 +608,49 @@ namespace Ryujinx.HLE.HOS.Services.Hid
WriteNewSixInputEntry(ref currentNpad.JoyLeftSixAxisSensor, ref newState);
WriteNewSixInputEntry(ref currentNpad.JoyRightSixAxisSensor, ref newState);
}
+
+ public void UpdateRumbleQueue(PlayerIndex index, Dictionary<byte, HidVibrationValue> dualVibrationValues)
+ {
+ if (RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> currentQueue))
+ {
+ if (!dualVibrationValues.TryGetValue(0, out HidVibrationValue leftVibrationValue))
+ {
+ leftVibrationValue = _neutralVibrationValue;
+ }
+
+ if (!dualVibrationValues.TryGetValue(1, out HidVibrationValue rightVibrationValue))
+ {
+ rightVibrationValue = _neutralVibrationValue;
+ }
+
+ if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue) || !leftVibrationValue.Equals(dualVibrationValue.Item1) || !rightVibrationValue.Equals(dualVibrationValue.Item2))
+ {
+ currentQueue.Enqueue((leftVibrationValue, rightVibrationValue));
+
+ LastVibrationValues[index] = (leftVibrationValue, rightVibrationValue);
+ }
+ }
+ }
+
+ public HidVibrationValue GetLastVibrationValue(PlayerIndex index, byte position)
+ {
+ if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue))
+ {
+ return _neutralVibrationValue;
+ }
+
+ return (position == 0) ? dualVibrationValue.Item1 : dualVibrationValue.Item2;
+ }
+
+ public ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> GetRumbleQueue(PlayerIndex index)
+ {
+ if (!RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> rumbleQueue))
+ {
+ rumbleQueue = new ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>();
+ _device.Hid.Npads.RumbleQueues[index] = rumbleQueue;
+ }
+
+ return rumbleQueue;
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs
new file mode 100644
index 00000000..4501c721
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceHandle.cs
@@ -0,0 +1,10 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+ public struct HidVibrationDeviceHandle
+ {
+ public byte DeviceType;
+ public byte PlayerId;
+ public byte Position;
+ public byte Reserved;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs
index cf9e6498..898384be 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationDeviceType.cs
@@ -3,6 +3,7 @@
public enum HidVibrationDeviceType
{
None,
- LinearResonantActuator
+ LinearResonantActuator,
+ GcErm
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs
index 7211396e..3f45d269 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/HidServer/Types/Vibration/HidVibrationValue.cs
@@ -1,4 +1,7 @@
-namespace Ryujinx.HLE.HOS.Services.Hid
+using Ryujinx.HLE.HOS.Tamper;
+using System;
+
+namespace Ryujinx.HLE.HOS.Services.Hid
{
public struct HidVibrationValue
{
@@ -6,5 +9,17 @@
public float FrequencyLow;
public float AmplitudeHigh;
public float FrequencyHigh;
+
+ public override bool Equals(object obj)
+ {
+ return obj is HidVibrationValue value &&
+ AmplitudeLow == value.AmplitudeLow &&
+ AmplitudeHigh == value.AmplitudeHigh;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(AmplitudeLow, AmplitudeHigh);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
index 3f2aae35..140545ad 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/IHidServer.cs
@@ -1,10 +1,13 @@
+using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
using Ryujinx.HLE.HOS.Services.Hid.Types;
+using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.InteropServices;
@@ -37,7 +40,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private HidSensorFusionParameters _sensorFusionParams;
private HidAccelerometerParameters _accelerometerParams;
- private HidVibrationValue _vibrationValue;
public IHidServer(ServiceCtx context) : base(context.Device.System.HidServer)
{
@@ -52,7 +54,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
_sensorFusionParams = new HidSensorFusionParameters();
_accelerometerParams = new HidAccelerometerParameters();
- _vibrationValue = new HidVibrationValue();
// TODO: signal event at right place
_xpadIdEvent.ReadableEvent.Signal();
@@ -1025,29 +1026,78 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo
public ResultCode GetVibrationDeviceInfo(ServiceCtx context)
{
- int vibrationDeviceHandle = context.RequestData.ReadInt32();
+ HidVibrationDeviceHandle deviceHandle = context.RequestData.ReadStruct<HidVibrationDeviceHandle>();
+ NpadStyleIndex deviceType = (NpadStyleIndex)deviceHandle.DeviceType;
+ NpadIdType npadIdType = (NpadIdType)deviceHandle.PlayerId;
- HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue
+ if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey)
{
- DeviceType = HidVibrationDeviceType.None,
- Position = HidVibrationDevicePosition.None
- };
+ if (npadIdType >= (NpadIdType.Player8 + 1) && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown)
+ {
+ return ResultCode.InvalidNpadIdType;
+ }
- context.ResponseData.Write((int)deviceInfo.DeviceType);
- context.ResponseData.Write((int)deviceInfo.Position);
+ if (deviceHandle.Position > 1)
+ {
+ return ResultCode.InvalidDeviceIndex;
+ }
- Logger.Stub?.PrintStub(LogClass.ServiceHid, new { vibrationDeviceHandle, deviceInfo.DeviceType, deviceInfo.Position });
+ HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None;
- return ResultCode.Success;
+ if (Enum.IsDefined(typeof(NpadStyleIndex), deviceType))
+ {
+ vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator;
+ }
+ else if ((uint)deviceType == 8)
+ {
+ vibrationDeviceType = HidVibrationDeviceType.GcErm;
+ }
+
+ HidVibrationDevicePosition vibrationDevicePosition = HidVibrationDevicePosition.None;
+
+ if (vibrationDeviceType == HidVibrationDeviceType.LinearResonantActuator)
+ {
+ if (deviceHandle.Position == 0)
+ {
+ vibrationDevicePosition = HidVibrationDevicePosition.Left;
+ }
+ else if (deviceHandle.Position == 1)
+ {
+ vibrationDevicePosition = HidVibrationDevicePosition.Right;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException(nameof(deviceHandle.Position));
+ }
+ }
+
+ HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue
+ {
+ DeviceType = vibrationDeviceType,
+ Position = vibrationDevicePosition
+ };
+
+ context.ResponseData.WriteStruct(deviceInfo);
+
+ return ResultCode.Success;
+ }
+
+ return ResultCode.InvalidNpadDeviceType;
}
[CommandHipc(201)]
// SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId)
public ResultCode SendVibrationValue(ServiceCtx context)
{
- int vibrationDeviceHandle = context.RequestData.ReadInt32();
+ HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle
+ {
+ DeviceType = context.RequestData.ReadByte(),
+ PlayerId = context.RequestData.ReadByte(),
+ Position = context.RequestData.ReadByte(),
+ Reserved = context.RequestData.ReadByte()
+ };
- _vibrationValue = new HidVibrationValue
+ HidVibrationValue vibrationValue = new HidVibrationValue
{
AmplitudeLow = context.RequestData.ReadSingle(),
FrequencyLow = context.RequestData.ReadSingle(),
@@ -1057,14 +1107,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid
long appletResourceUserId = context.RequestData.ReadInt64();
- Logger.Debug?.PrintStub(LogClass.ServiceHid, new {
- appletResourceUserId,
- vibrationDeviceHandle,
- _vibrationValue.AmplitudeLow,
- _vibrationValue.FrequencyLow,
- _vibrationValue.AmplitudeHigh,
- _vibrationValue.FrequencyHigh
- });
+ Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
+
+ dualVibrationValues[deviceHandle.Position] = vibrationValue;
+
+ context.Device.Hid.Npads.UpdateRumbleQueue((PlayerIndex)deviceHandle.PlayerId, dualVibrationValues);
return ResultCode.Success;
}
@@ -1073,22 +1120,22 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue
public ResultCode GetActualVibrationValue(ServiceCtx context)
{
- int vibrationDeviceHandle = context.RequestData.ReadInt32();
+ HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle
+ {
+ DeviceType = context.RequestData.ReadByte(),
+ PlayerId = context.RequestData.ReadByte(),
+ Position = context.RequestData.ReadByte(),
+ Reserved = context.RequestData.ReadByte()
+ };
+
long appletResourceUserId = context.RequestData.ReadInt64();
- context.ResponseData.Write(_vibrationValue.AmplitudeLow);
- context.ResponseData.Write(_vibrationValue.FrequencyLow);
- context.ResponseData.Write(_vibrationValue.AmplitudeHigh);
- context.ResponseData.Write(_vibrationValue.FrequencyHigh);
+ HidVibrationValue vibrationValue = context.Device.Hid.Npads.GetLastVibrationValue((PlayerIndex)deviceHandle.PlayerId, deviceHandle.Position);
- Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
- appletResourceUserId,
- vibrationDeviceHandle,
- _vibrationValue.AmplitudeLow,
- _vibrationValue.FrequencyLow,
- _vibrationValue.AmplitudeHigh,
- _vibrationValue.FrequencyHigh
- });
+ context.ResponseData.Write(vibrationValue.AmplitudeLow);
+ context.ResponseData.Write(vibrationValue.FrequencyLow);
+ context.ResponseData.Write(vibrationValue.AmplitudeHigh);
+ context.ResponseData.Write(vibrationValue.FrequencyHigh);
return ResultCode.Success;
}
@@ -1138,13 +1185,31 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer);
- // TODO: Read all handles and values from buffer.
+ Span<HidVibrationDeviceHandle> deviceHandles = MemoryMarshal.Cast<byte, HidVibrationDeviceHandle>(vibrationDeviceHandleBuffer);
+ Span<HidVibrationValue> vibrationValues = MemoryMarshal.Cast<byte, HidVibrationValue>(vibrationValueBuffer);
- Logger.Debug?.PrintStub(LogClass.ServiceHid, new {
- appletResourceUserId,
- VibrationDeviceHandleBufferLength = vibrationDeviceHandleBuffer.Length,
- VibrationValueBufferLength = vibrationValueBuffer.Length
- });
+ if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length)
+ {
+ Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
+ PlayerIndex currentIndex = (PlayerIndex)deviceHandles[0].PlayerId;
+
+ for (int deviceCounter = 0; deviceCounter < deviceHandles.Length; deviceCounter++)
+ {
+ PlayerIndex index = (PlayerIndex)deviceHandles[deviceCounter].PlayerId;
+ byte position = deviceHandles[deviceCounter].Position;
+
+ if (index != currentIndex || dualVibrationValues.Count == 2)
+ {
+ context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues);
+ dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
+ }
+
+ dualVibrationValues[position] = vibrationValues[deviceCounter];
+ currentIndex = index;
+ }
+
+ context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues);
+ }
return ResultCode.Success;
}
diff --git a/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs
index 9b829cc5..9c87ac1d 100644
--- a/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs
+++ b/Ryujinx.HLE/HOS/Services/Hid/ResultCode.cs
@@ -7,6 +7,9 @@
Success = 0,
- InvalidNpadIdType = (710 << ErrorCodeShift) | ModuleId
+ InvalidNpadDeviceType = (122 << ErrorCodeShift) | ModuleId,
+ InvalidNpadIdType = (123 << ErrorCodeShift) | ModuleId,
+ InvalidDeviceIndex = (124 << ErrorCodeShift) | ModuleId,
+ InvalidBufferSize = (131 << ErrorCodeShift) | ModuleId
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs
new file mode 100644
index 00000000..b85681d2
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/NpadStyleIndex.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.HLE.HOS.Services.Hid
+{
+ public enum NpadStyleIndex : byte
+ {
+ FullKey = 3,
+ Handheld = 4,
+ JoyDual = 5,
+ JoyLeft = 6,
+ JoyRight = 7,
+ SystemExt = 32,
+ System = 33
+ }
+}